从 GPT-4 到 Gemini 3 Pro:一个五子棋游戏见证的 AI 两年进化史

前言

两年前,当 GPT-4 刚刚横空出世时,我怀着激动的心情尝试用它写一个五子棋游戏。那段经历我记录在了掘金文章《GPT-4多轮对话生成五子棋游戏》中。当时,为了得到一个能跑的 Demo,我与 GPT-4 进行了漫长的多轮对话:修复 Bug、调整样式、纠正逻辑,仿佛在带一个虽然聪明但由于"健忘"和"粗心"而需要不断纠正的实习生。

时光荏苒,两年后的今天,我拿到了 Gemini 3 Pro。抱着同样的命题,我再次输入了那个需求:"帮我写一个五子棋人机对战游戏"。

这一次,没有多轮对话,没有报错调试。它直接甩给了我一个单文件,我复制、粘贴、打开------它不仅能跑,而且"懂"战术,甚至连 UI 的渐变色都做好了。

这篇文章,不仅是对代码的复盘,更是对这两年 AI 发展速度的一次微观见证。

1. 直观对比:从"拼积木"到"3D打印"

两年前的 GPT-4 体验

在两年前的那篇文章中,开发过程是碎片化的:

  1. 上下文丢失:代码太长时,GPT-4 会中断,需要我提示"继续"。
  2. 逻辑割裂:HTML、CSS 和 JS 往往是分开生成的,需要我手动组装。
  3. 调试循环:最开始生成的 AI 逻辑经常只会随机落子,或者不仅不堵我的棋,还下在已经被占用的格子上。我需要反复告诉它:"你这里逻辑不对,应该先判断是否为空"。

今天的 Gemini 3 Pro 体验

这是 Gemini 3 Pro 给我生成的完整代码(见文末附录)。

结果是惊人的:

  • One-Shot(一次成型) :它在一个 HTML 文件中完整封装了结构、样式和逻辑,没有任何截断。
  • 审美在线 :它没有给我一个黑白格子的简陋棋盘,而是直接使用了 #dcb35c 木纹底色,棋子甚至使用了 RadialGradient 径向渐变来模拟光影立体感。
  • 逻辑完备 :赢法数组 (wins)、赢法统计 (myWin, computerWin)、启发式评分 (myScore, computerScore) 一气呵成。

2. 代码深度解析:AI 真的懂"算法"了

让我们看看 Gemini 3 Pro 生成的核心 AI 逻辑,这在两年前是需要我引导很久才能写出来的。

赢法数组的预计算

代码中有一个非常经典的五子棋算法实现------赢法数组

JavaScript

csharp 复制代码
// 初始化赢法数组
function initWins(){
    // ... 省略循环 ...
    // 横线、竖线、斜线、反斜线
    // 统计出所有可能连成5子的线,总共572种(15x15棋盘)
}

Gemini 3 Pro 在初始化时,直接计算了棋盘上所有横、竖、撇、捺能构成五连珠的情况,并在内存中构建了一个三维数组。这意味着它"知道"五子棋的胜利条件不仅仅是"看到5个子",而是基于数学上的组合可能性。

启发式评分系统

最让我惊讶的是 computerAI 函数中的评分逻辑:

JavaScript

scss 复制代码
// 拦截玩家
if(myWin[k] == 1) myScore[i][j] += 200;
else if(myWin[k] == 2) myScore[i][j] += 400;
else if(myWin[k] == 3) myScore[i][j] += 2000;
else if(myWin[k] == 4) myScore[i][j] += 10000;

// 电脑进攻
if(computerWin[k] == 1) computerScore[i][j] += 220;
else if(computerWin[k] == 2) computerScore[i][j] += 420;
else if(computerWin[k] == 3) computerScore[i][j] += 2100;
else if(computerWin[k] == 4) computerScore[i][j] += 20000;

注意这里的细节:

  1. 攻守兼备:它同时计算了"封堵玩家"的分数和"自己进攻"的分数。
  2. 权重差异:注意看,同样是连3子,电脑进攻的分数 (2100) 略高于拦截玩家的分数 (2000)。这说明 AI 被设定为**"在确保安全的情况下,优先进攻"**的激进策略。
  3. 绝杀判断:当达到 4 子时,分数直接跳跃到万级,确保 AI 能够识别"冲四"和"防守冲四"的最高优先级。

两年前,GPT-4 生成的代码往往只是随机找空位,或者仅仅判断周围一格是否有子。而现在的 Gemini 3 Pro 直接写出了一个具备贪心算法雏形的 AI。

3. 两年的技术跨越:我们经历了什么?

通过这个五子棋 Demo,我们可以清晰地看到 AI 进化的三个维度:

1. 上下文窗口与推理深度的质变

两年前,我们需要把大任务拆解成小任务喂给 AI。现在,Gemini 3 Pro 的上下文窗口和推理能力允许它在一次输出中处理全局依赖 。它清楚定义在第 10 行的 CSS 类名需要在第 50 行的 HTML 中使用,以及第 100 行的 JS 逻辑要操作第 20 行的 Canvas DOM。这种全局一致性是最大的进步。

2. 从"模仿者"到"工程师"

以前的 AI 像是在 Stack Overflow 上搜索代码片段并拼接(常常拼错)。现在的 AI 更像是一个工程师。它考虑了:

  • UI 交互 :点击后稍作延迟 (setTimeout) 再让电脑落子,为了让 UI 刷新,避免浏览器假死。
  • 边界条件 :游戏结束后锁定点击事件 (if (over) return)。
  • 代码规范:变量命名清晰,注释详尽。

3. 多模态理解的反哺

虽然这次是纯代码生成,但 Gemini 3 Pro 对颜色的运用(木纹色、渐变棋子)暗示了它对物理世界"五子棋"视觉样貌的深刻理解。它不仅仅是在写代码,它是在"构建"一个它认知中的游戏场景。

4. 结语

两年前,我在 Juejin 文章的结尾可能还在感叹:"AI 辅助编程的时代来了,但还需要人来把关。"

今天,看着 Gemini 3 Pro 生成的这个无需修改、直接运行、甚至有点难赢的五子棋游戏,我必须更新我的观点:AI 已经从"副驾驶"开始尝试握住方向盘了。

对于开发者而言,这意味着门槛的再一次提高和降低------编写基础代码的门槛降到了零,但理解复杂系统、优化算法权重的门槛依然存在。

附:Gemini 3 Pro 生成的完整代码与效果图

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>五子棋人机对战</title>
    <style>
        body {
            font-family: 'Microsoft YaHei', sans-serif;
            background-color: #f0f0f0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            margin: 0;
        }

        h1 {
            color: #333;
            margin-bottom: 10px;
        }

        #game-container {
            position: relative;
            box-shadow: 0 10px 25px rgba(0,0,0,0.5);
            border-radius: 4px;
            padding: 10px;
            background-color: #dcb35c; /* 木纹底色 */
        }

        canvas {
            background-color: #dcb35c;
            cursor: pointer;
            display: block;
        }

        .status-bar {
            margin-top: 20px;
            display: flex;
            gap: 20px;
            align-items: center;
        }

        #status {
            font-size: 1.2em;
            font-weight: bold;
            color: #333;
        }

        button {
            padding: 10px 20px;
            font-size: 1em;
            cursor: pointer;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
            transition: background 0.3s;
        }

        button:hover {
            background-color: #45a049;
        }
    </style>
</head>
<body>

    <h1>五子棋 - 人机对战</h1>
    
    <div id="game-container">
        <canvas id="chess" width="450" height="450"></canvas>
    </div>

    <div class="status-bar">
        <div id="status">当前回合: 玩家 (黑棋)</div>
        <button onclick="restartGame()">重新开始</button>
    </div>

    <script>
        // 配置参数
        const canvas = document.getElementById('chess');
        const context = canvas.getContext('2d');
        const statusText = document.getElementById('status');
        
        const gridSize = 30; // 格子大小
        const padding = 15;  // 棋盘边缘留白
        const boardSize = 15; // 15x15 棋盘
        
        let chessBoard = []; // 棋盘状态数组 0:空, 1:黑(玩家), 2:白(电脑)
        let me = true; // true: 玩家回合, false: 电脑回合
        let over = false; // 游戏结束标志
        
        //赢法数组
        let wins = [];
        //赢法统计数组
        let myWin = [];
        let computerWin = [];
        let count = 0; // 赢法总数

        // 初始化游戏
        window.onload = function() {
            initGame();
        };

        function initGame() {
            // 重置变量
            me = true;
            over = false;
            chessBoard = [];
            statusText.innerText = "当前回合: 玩家 (黑棋)";
            statusText.style.color = "#333";

            // 初始化棋盘数组
            for(let i = 0; i < boardSize; i++){
                chessBoard[i] = [];
                for(let j = 0; j < boardSize; j++){
                    chessBoard[i][j] = 0;
                }
            }

            // 初始化赢法统计
            initWins();
            
            // 绘制棋盘
            drawChessBoard();
        }

        // 绘制棋盘网格
        function drawChessBoard() {
            context.clearRect(0, 0, canvas.width, canvas.height);
            context.strokeStyle = "#555";
            
            for (let i = 0; i < boardSize; i++) {
                // 竖线
                context.moveTo(padding + i * gridSize, padding);
                context.lineTo(padding + i * gridSize, canvas.height - padding);
                context.stroke();
                // 横线
                context.moveTo(padding, padding + i * gridSize);
                context.lineTo(canvas.width - padding, padding + i * gridSize);
                context.stroke();
            }
        }

        // 绘制棋子
        function oneStep(i, j, me) {
            context.beginPath();
            context.arc(padding + i * gridSize, padding + j * gridSize, 13, 0, 2 * Math.PI);
            context.closePath();
            
            let gradient = context.createRadialGradient(
                padding + i * gridSize + 2, padding + j * gridSize - 2, 13, 
                padding + i * gridSize + 2, padding + j * gridSize - 2, 0
            );

            if (me) { // 黑棋
                gradient.addColorStop(0, "#0a0a0a");
                gradient.addColorStop(1, "#636766");
            } else { // 白棋
                gradient.addColorStop(0, "#d1d1d1");
                gradient.addColorStop(1, "#f9f9f9");
            }
            
            context.fillStyle = gradient;
            context.fill();
        }

        // 玩家点击落子
        canvas.onclick = function(e) {
            if (over || !me) return;

            let x = e.offsetX;
            let y = e.offsetY;
            
            let i = Math.floor(x / gridSize);
            let j = Math.floor(y / gridSize);

            if (chessBoard[i][j] == 0) {
                oneStep(i, j, true);
                chessBoard[i][j] = 1; // 1代表黑棋

                // 检查玩家是否胜利
                for(let k = 0; k < count; k++){
                    if(wins[i][j][k]){
                        myWin[k]++;
                        computerWin[k] = 6; // 设置异常值,因为对方不可能在这个赢法上赢了
                        if(myWin[k] == 5){
                            statusText.innerText = "恭喜你!你赢了!";
                            statusText.style.color = "red";
                            over = true;
                        }
                    }
                }

                if (!over) {
                    me = !me;
                    statusText.innerText = "当前回合: 电脑 (思考中...)";
                    setTimeout(computerAI, 50); // 稍作延迟,让UI刷新
                }
            }
        }

        // 电脑AI逻辑
        function computerAI() {
            let myScore = []; // 玩家分数(防守)
            let computerScore = []; // 电脑分数(进攻)
            let max = 0; // 最高分
            let u = 0, v = 0; // 最佳落子点

            // 初始化分数数组
            for(let i = 0; i < boardSize; i++){
                myScore[i] = [];
                computerScore[i] = [];
                for(let j = 0; j < boardSize; j++){
                    myScore[i][j] = 0;
                    computerScore[i][j] = 0;
                }
            }

            // 遍历棋盘所有空点进行评分
            for(let i = 0; i < boardSize; i++){
                for(let j = 0; j < boardSize; j++){
                    if(chessBoard[i][j] == 0){
                        // 遍历所有赢法
                        for(let k = 0; k < count; k++){
                            if(wins[i][j][k]){
                                // 计算拦截玩家的分数
                                if(myWin[k] == 1) myScore[i][j] += 200;
                                else if(myWin[k] == 2) myScore[i][j] += 400;
                                else if(myWin[k] == 3) myScore[i][j] += 2000;
                                else if(myWin[k] == 4) myScore[i][j] += 10000;

                                // 计算电脑进攻的分数
                                if(computerWin[k] == 1) computerScore[i][j] += 220;
                                else if(computerWin[k] == 2) computerScore[i][j] += 420;
                                else if(computerWin[k] == 3) computerScore[i][j] += 2100;
                                else if(computerWin[k] == 4) computerScore[i][j] += 20000;
                            }
                        }

                        // 综合评分,决定最佳落子
                        // 只要该点总分比当前最高分高,就更新
                        if(myScore[i][j] > max){
                            max = myScore[i][j];
                            u = i; v = j;
                        } else if(myScore[i][j] == max){
                            if(computerScore[i][j] > computerScore[u][v]){
                                u = i; v = j;
                            }
                        }
                        
                        if(computerScore[i][j] > max){
                            max = computerScore[i][j];
                            u = i; v = j;
                        } else if(computerScore[i][j] == max){
                            if(myScore[i][j] > myScore[u][v]){
                                u = i; v = j;
                            }
                        }
                    }
                }
            }

            // 电脑落子
            oneStep(u, v, false);
            chessBoard[u][v] = 2; // 2代表白棋

            // 检查电脑是否胜利
            for(let k = 0; k < count; k++){
                if(wins[u][v][k]){
                    computerWin[k]++;
                    myWin[k] = 6;
                    if(computerWin[k] == 5){
                        statusText.innerText = "遗憾,电脑赢了!";
                        statusText.style.color = "blue";
                        over = true;
                    }
                }
            }

            if (!over) {
                me = !me;
                statusText.innerText = "当前回合: 玩家 (黑棋)";
            }
        }

        // 初始化赢法数组(这是算法核心:预先计算所有可能的连线)
        function initWins(){
            wins = [];
            for(let i=0; i<boardSize; i++){
                wins[i] = [];
                for(let j=0; j<boardSize; j++){
                    wins[i][j] = [];
                }
            }
            
            count = 0;

            // 横线赢法
            for(let i=0; i<boardSize; i++){
                for(let j=0; j<boardSize-4; j++){
                    for(let k=0; k<5; k++){
                        wins[i][j+k][count] = true;
                    }
                    count++;
                }
            }

            // 竖线赢法
            for(let i=0; i<boardSize; i++){
                for(let j=0; j<boardSize-4; j++){
                    for(let k=0; k<5; k++){
                        wins[j+k][i][count] = true;
                    }
                    count++;
                }
            }

            // 斜线赢法 ( \ )
            for(let i=0; i<boardSize-4; i++){
                for(let j=0; j<boardSize-4; j++){
                    for(let k=0; k<5; k++){
                        wins[i+k][j+k][count] = true;
                    }
                    count++;
                }
            }

            // 反斜线赢法 ( / )
            for(let i=0; i<boardSize-4; i++){
                for(let j=boardSize-1; j>3; j--){
                    for(let k=0; k<5; k++){
                        wins[i+k][j-k][count] = true;
                    }
                    count++;
                }
            }

            // 初始化统计数组
            for(let i=0; i<count; i++){
                myWin[i] = 0;
                computerWin[i] = 0;
            }
        }

        function restartGame() {
            initGame();
        }
    </script>
</body>
</html>
相关推荐
Mr.Daozhi3 天前
从零构建 AI 学术论文助手(四):PDF.js 实时截图 + Gemini 视觉分析
javascript·人工智能·pdf·canvas·pdf.js·gemini
云卷云舒___________3 天前
Gemini 3.5 Pro或17日发布、Grok Imagine新增15秒视频生成、GPT-5.6 Sol 跑30小时超Opus | 7月5日 AI日报
华为·ai·grok·视频生成·gemini·ai日报·gpt56
云卷云舒___________4 天前
Google Gemini 3.5 Pro泄露、GPT-5.6套餐限额放宽、Meta Watermelon追平GPT-5.5 | 7月4日 AI日报
google·meta·openai·gemini·ai日报·gpt56·watermelon
Mac的实验室6 天前
2026年最新谷歌Gemini账号申请注册教程|手把手教你如何注册Gemini跳过手机号验证
gemini
Mac的实验室7 天前
谷歌账号无法使用Gemini?2026最新国内怎么订阅Gemini Pro?三种方法汇总!
gemini
Mac的实验室7 天前
2026年国内怎么订阅Gemini Pro?Gemini一直订阅失败?我差点放弃,结果问题竟然在这…
gemini
Mac的实验室7 天前
2026年登录谷歌账号访问Google Gemini时提示出了点问题稍后再试(Something went wrong)无法使用Gemini的解决办法
gemini
黑暗森林观察者14 天前
Gemini 3.5 Flash 把"操作电脑"塞进了模型——AI从"能说"到"能动手"
人工智能·gemini
寒山李白24 天前
Gemini 2.5 Flash Lite 实效表现与能力边界全景解析
ai·大模型·gemini·评测
SEO_juper25 天前
Semrush 蓝海关键词筛选,AI 一键拓展完整词库
大数据·谷歌·seo·geo·gemini·询盘·b2b