用Gemini AI编写的aardio版本[五子棋]游戏

By admin at 7 天前 • 0人收藏 • 68人看过

全程Gemini Pro AI 一次性生成 , 五子棋游戏, 摸鱼必备!

2026年了,  分分钟一个软件还会远吗? 有想法有创意, 编程的事情交给AI...

提示词: 五子棋了解吗? 帮我用aardio编写一个这样的程序


image.png

import win.ui;
import gdip;

/*DSG{{*/
var winform = win.form(text="五子棋 (双人对战版) - aardio演示";right=560;bottom=580)
winform.add(
plus={cls="plus";left=0;top=0;right=560;bottom=580;db=1;dl=1;dr=1;dt=1;notify=1;z=1}
);
/*}}*/

// ==========================================
// 1. 游戏配置与状态
// ==========================================
var boardSize = 15;   // 15路棋盘
var cellSize = 35;    // 格子大小
var margin = 30;      // 棋盘边缘留白
var pieceRadius = 15; // 棋子半径

// 游戏状态
// 0:空, 1:黑子, 2:白子
var boardData = {}; 
var isBlackTurn = true; // 当前是否黑方落子
var isGameOver = false;
var lastMove = null;    // 记录最后一步 {r, c},用于高亮显示

// 初始化/重置棋盘
var resetGame = function(){
    boardData = ..table.array(boardSize, ..table.array(boardSize, 0));
    isBlackTurn = true;
    isGameOver = false;
    lastMove = null;
    winform.text = "五子棋 - 黑方执黑先行";
    winform.plus.redraw();
}
resetGame();

// ==========================================
// 2. 核心逻辑:胜负判断
// ==========================================
// 检查某个方向是否有5连
// r, c: 当前落子坐标
// dr, dc: 方向增量 (例如 1,0 表示横向)
// color: 当前棋子颜色 (1或2)
var countLine = function(r, c, dr, dc, color){
    var count = 0;
    
    // 正向查找
    var i = 1;
    while(true){
        var nr, nc = r + dr*i, c + dc*i;
        if(nr<1 || nr>boardSize || nc<1 || nc>boardSize) break;
        if(boardData[nr][nc] == color) count++;
        else break;
        i++;
    }
    
    // 反向查找
    i = 1;
    while(true){
        var nr, nc = r - dr*i, c - dc*i;
        if(nr<1 || nr>boardSize || nc<1 || nc>boardSize) break;
        if(boardData[nr][nc] == color) count++;
        else break;
        i++;
    }
    return count + 1; // 加上自己
}

var checkWin = function(r, c, color){
    // 四个方向:横、竖、撇(/)、捺(\)
    if(countLine(r, c, 1, 0, color) >= 5) return true; // 横
    if(countLine(r, c, 0, 1, color) >= 5) return true; // 竖
    if(countLine(r, c, 1, 1, color) >= 5) return true; // 捺
    if(countLine(r, c, 1, -1, color) >= 5) return true; // 撇
    return false;
}

// ==========================================
// 3. 绘图渲染
// ==========================================
winform.plus.onDrawForegroundEnd = function(graphics, rc){
    graphics.smoothingMode = 4/*_SmoothingModeAntiAlias*/;
    
    // 1. 绘制棋盘背景 (木纹色)
    var brushBg = gdip.solidBrush(0xFFDEB887);
    graphics.fillRectangle(brushBg, 0, 0, rc.right, rc.bottom);
    brushBg.delete();
    
    // 2. 绘制网格线
    var penLine = gdip.pen(0xFF000000, 1);
    for(i=1; boardSize; 1){
        var pos = margin + (i-1) * cellSize;
        // 横线
        var startX, endX = margin, margin + (boardSize-1)*cellSize;
        graphics.drawLine(penLine, startX, pos, endX, pos);
        // 竖线
        var startY, endY = margin, margin + (boardSize-1)*cellSize;
        graphics.drawLine(penLine, pos, startY, pos, endY);
    }
    penLine.delete();
    
    // 3. 绘制星位 (天元和四个星)
    var drawStar = function(r, c){
        var x = margin + (c-1) * cellSize;
        var y = margin + (r-1) * cellSize;
        var brush = gdip.solidBrush(0xFF000000);
        graphics.fillEllipse(brush, x-3, y-3, 6, 6);
        brush.delete();
    }
    // 标准15路盘星位:4, 8, 12
    var stars = {4, 8, 12};
    for(i=1; #stars){
        for(j=1; #stars){
            drawStar(stars[i], stars[j]);
        }
    }
    
    // 4. 绘制棋子
    for(r=1; boardSize){
        for(c=1; boardSize){
            var val = boardData[r][c];
            if(val == 0) continue;
            
            var x = margin + (c-1) * cellSize;
            var y = margin + (r-1) * cellSize;
            
            // 棋子带一点阴影效果
            // var brushShadow = gdip.solidBrush(0x50000000);
            // graphics.fillEllipse(brushShadow, x-pieceRadius+2, y-pieceRadius+2, pieceRadius*2, pieceRadius*2);
            // brushShadow.delete();
            
            var color = (val == 1) ? 0xFF000000 : 0xFFFFFFFF;
            var brushPiece = gdip.solidBrush(color);
            graphics.fillEllipse(brushPiece, x-pieceRadius, y-pieceRadius, pieceRadius*2, pieceRadius*2);
            brushPiece.delete();
            
            // 如果是白子,画个细黑边,防止和背景混淆
            if(val == 2){
                var penPiece = gdip.pen(0xFFCCCCCC, 1);
                graphics.drawEllipse(penPiece, x-pieceRadius, y-pieceRadius, pieceRadius*2, pieceRadius*2);
                penPiece.delete();
            }
        }
    }
    
    // 5. 标记最后一步 (红色小方块)
    if(lastMove){
        var x = margin + (lastMove.c-1) * cellSize;
        var y = margin + (lastMove.r-1) * cellSize;
        var brushMark = gdip.solidBrush(0xFFFF0000);
        graphics.fillRectangle(brushMark, x-3, y-3, 6, 6);
        brushMark.delete();
    }
    
    // 6. 游戏结束文字
    if(isGameOver){
        var font = gdip.font("微软雅黑", 24, 1);
        var brushText = gdip.solidBrush(0xFFFF0000);
        var msg = (isBlackTurn ? "白方" : "黑方") + "获胜! (右键重开)";
        graphics.drawString(msg, font, ::RECTF(50, 200, 500, 300), gdip.stringformat(), brushText);
        font.delete(); brushText.delete();
    }
}

// ==========================================
// 4. 鼠标交互
// ==========================================
winform.plus.onMouseDown = function(wParam, lParam){
    // 右键重开
    if(wParam == 0x204/*_WM_RBUTTONDOWN*/){
        if(win.msgboxTest("确定要重新开始吗?", "五子棋")){
            resetGame();
        }
        return;
    }

    if(isGameOver) return;
    
    var x, y = win.getMessagePos(lParam);
    
    // 1. 坐标换算:将屏幕像素转换为网格索引
    // 使用 round 实现"吸附"效果,点击交叉点附近都算该点
    var c = ..math.round((x - margin) / cellSize) + 1;
    var r = ..math.round((y - margin) / cellSize) + 1;
    
    // 2. 边界检查与空位检查
    if(r < 1 || r > boardSize || c < 1 || c > boardSize) return;
    if(boardData[r][c] != 0) return; // 已经有子了
    
    // 3. 落子
    var color = isBlackTurn ? 1 : 2;
    boardData[r][c] = color;
    lastMove = {r=r, c=c};
    winform.plus.redraw(); // 立即重绘显示落子
    
    // 4. 胜负判断
    if(checkWin(r, c, color)){
        isGameOver = true;
        winform.text = "五子棋 - 游戏结束";
        winform.plus.redraw();
        // win.msgbox((isBlackTurn ? "黑方" : "白方") + "获胜!");
    }
    else {
        // 5. 换手
        isBlackTurn = !isBlackTurn;
        winform.text = "五子棋 - 轮到" + (isBlackTurn ? "黑" : "白") + "方";
    }
}

winform.show();
win.loopMessage();


1 个回复 | 最后更新于 7 天前
7 天前   #1

人机对战版:

提示词: 帮我改成人机对战版


import win.ui;
import gdip;

/*DSG{{*/
var winform = win.form(text="五子棋 (人机对战版) - 挑战AI";right=560;bottom=580)
winform.add(
plus={cls="plus";left=0;top=0;right=560;bottom=580;db=1;dl=1;dr=1;dt=1;notify=1;z=1}
);
/*}}*/

// ==========================================
// 1. 游戏配置
// ==========================================
var boardSize = 15;
var cellSize = 35;
var margin = 30;
var pieceRadius = 15;

// 状态: 0:空, 1:黑子(玩家), 2:白子(电脑)
var boardData = {}; 
var isPlayerTurn = true; 
var isGameOver = false;
var lastMove = null;

// 重置游戏
var resetGame = function(){
    boardData = ..table.array(boardSize, ..table.array(boardSize, 0));
    isPlayerTurn = true; // 玩家执黑先行
    isGameOver = false;
    lastMove = null;
    winform.text = "五子棋 (人机对战) - 轮到你了";
    winform.plus.redraw();
}
resetGame();

// ==========================================
// 2. 基础逻辑 (胜负判定)
// ==========================================
var countLine = function(r, c, dr, dc, color){
    var count = 0;
    // 正向
    var i = 1;
    while(true){
        var nr, nc = r + dr*i, c + dc*i;
        if(nr<1 || nr>boardSize || nc<1 || nc>boardSize || boardData[nr][nc] != color) break;
        count++; i++;
    }
    // 反向
    i = 1;
    while(true){
        var nr, nc = r - dr*i, c - dc*i;
        if(nr<1 || nr>boardSize || nc<1 || nc>boardSize || boardData[nr][nc] != color) break;
        count++; i++;
    }
    return count + 1;
}

var checkWin = function(r, c, color){
    if(countLine(r, c, 1, 0, color) >= 5) return true;
    if(countLine(r, c, 0, 1, color) >= 5) return true;
    if(countLine(r, c, 1, 1, color) >= 5) return true;
    if(countLine(r, c, 1, -1, color) >= 5) return true;
    return false;
}

// ==========================================
// 3. AI 核心算法 (评分引擎)
// ==========================================

// 评分表 (权重)
var scoreTable = {
    win5  = 100000; // 连五
    live4 = 10000;  // 活四 (两头空)
    dead4 = 1000;   // 死四 (一头堵)
    live3 = 1000;   // 活三
    dead3 = 100;    // 死三
    live2 = 100;    // 活二
    dead2 = 10;     // 死二
}

// 计算某一点在某个方向上的棋型分数
var evaluateLine = function(r, c, dr, dc, color){
    var count = 1; // 假设落子在此
    var emptyEnds = 0;
    
    // 向前探
    var i = 1;
    while(true){
        var nr, nc = r + dr*i, c + dc*i;
        if(nr<1 || nr>boardSize || nc<1 || nc>boardSize) break; // 边界
        if(boardData[nr][nc] == color) count++;
        else {
            if(boardData[nr][nc] == 0) emptyEnds++; // 遇到空位
            break; // 遇到敌方或空位都停止计数
        }
        i++;
    }
    
    // 向后探
    i = 1;
    while(true){
        var nr, nc = r - dr*i, c - dc*i;
        if(nr<1 || nr>boardSize || nc<1 || nc>boardSize) break;
        if(boardData[nr][nc] == color) count++;
        else {
            if(boardData[nr][nc] == 0) emptyEnds++;
            break;
        }
        i++;
    }
    
    // 评分规则
    if(count >= 5) return scoreTable.win5;
    if(count == 4) return (emptyEnds == 2) ? scoreTable.live4 : (emptyEnds == 1 ? scoreTable.dead4 : 0);
    if(count == 3) return (emptyEnds == 2) ? scoreTable.live3 : (emptyEnds == 1 ? scoreTable.dead3 : 0);
    if(count == 2) return (emptyEnds == 2) ? scoreTable.live2 : (emptyEnds == 1 ? scoreTable.dead2 : 0);
    return 0;
}

// 计算某点总分 (进攻 + 防守)
var getPointScore = function(r, c){
    var score = 0;
    
    // 1. 进攻分 (如果电脑下这,对自己有多大好处)
    var myScore = 0;
    myScore += evaluateLine(r, c, 1, 0, 2); // 横
    myScore += evaluateLine(r, c, 0, 1, 2); // 竖
    myScore += evaluateLine(r, c, 1, 1, 2); // 捺
    myScore += evaluateLine(r, c, 1, -1, 2);// 撇
    
    // 2. 防守分 (如果玩家下这,对电脑有多大威胁)
    var enemyScore = 0;
    enemyScore += evaluateLine(r, c, 1, 0, 1);
    enemyScore += evaluateLine(r, c, 0, 1, 1);
    enemyScore += evaluateLine(r, c, 1, 1, 1);
    enemyScore += evaluateLine(r, c, 1, -1, 1);
    
    // 策略:进攻为主,但如果有致命威胁要防守
    // 简单的加法通常就足够聪明了
    return myScore + enemyScore;
}

// AI 思考并落子
var computerMove = function(){
    var maxScore = -1;
    var bestPoints = {}; // 存所有最高分的点
    
    // 遍历所有空位
    for(r=1; boardSize){
        for(c=1; boardSize){
            if(boardData[r][c] == 0){
                var s = getPointScore(r, c);
                
                // 如果是中心点,略微加分 (开局抢占天元)
                if(r==8 && c==8) s += 10;
                
                if(s > maxScore){
                    maxScore = s;
                    bestPoints = {{r=r, c=c}};
                } elseif(s == maxScore){
                    ..table.push(bestPoints, {r=r, c=c});
                }
            }
        }
    }
    
    // 如果有多个最高分,随机选一个
    var move = bestPoints[1];
    if(#bestPoints > 1){
        move = bestPoints[..math.random(1, #bestPoints)];
    }
    
    if(move){
        boardData[move.r][move.c] = 2; // 白子
        lastMove = move;
        winform.plus.redraw();
        
        if(checkWin(move.r, move.c, 2)){
            isGameOver = true;
            winform.text = "五子棋 - AI获胜! (右键重开)";
            win.msgbox("电脑赢了!人类还需要努力啊。");
        } else {
            isPlayerTurn = true;
            winform.text = "五子棋 - 轮到你了";
        }
    }
}

// ==========================================
// 4. 绘图渲染 (保持不变)
// ==========================================
winform.plus.onDrawForegroundEnd = function(graphics, rc){
    graphics.smoothingMode = 4;
    
    var brushBg = gdip.solidBrush(0xFFDEB887);
    graphics.fillRectangle(brushBg, 0, 0, rc.right, rc.bottom);
    brushBg.delete();
    
    var penLine = gdip.pen(0xFF000000, 1);
    for(i=1; boardSize){
        var pos = margin + (i-1) * cellSize;
        graphics.drawLine(penLine, margin, pos, margin+(boardSize-1)*cellSize, pos);
        graphics.drawLine(penLine, pos, margin, pos, margin+(boardSize-1)*cellSize);
    }
    penLine.delete();
    
    var stars = {4, 8, 12};
    for(i=1; #stars){
        for(j=1; #stars){
            var x, y = margin+(stars[j]-1)*cellSize, margin+(stars[i]-1)*cellSize;
            var b = gdip.solidBrush(0xFF000000); graphics.fillEllipse(b, x-3, y-3, 6, 6); b.delete();
        }
    }
    
    for(r=1; boardSize){
        for(c=1; boardSize){
            var val = boardData[r][c];
            if(val == 0) continue;
            var x, y = margin+(c-1)*cellSize, margin+(r-1)*cellSize;
            var color = (val == 1) ? 0xFF000000 : 0xFFFFFFFF;
            var b = gdip.solidBrush(color);
            graphics.fillEllipse(b, x-pieceRadius, y-pieceRadius, pieceRadius*2, pieceRadius*2);
            b.delete();
            if(val == 2){
                var p = gdip.pen(0xFFCCCCCC, 1); graphics.drawEllipse(p, x-pieceRadius, y-pieceRadius, pieceRadius*2, pieceRadius*2); p.delete();
            }
        }
    }
    
    if(lastMove){
        var x, y = margin+(lastMove.c-1)*cellSize, margin+(lastMove.r-1)*cellSize;
        var b = gdip.solidBrush(0xFFFF0000); graphics.fillRectangle(b, x-3, y-3, 6, 6); b.delete();
    }
}

// ==========================================
// 5. 鼠标交互
// ==========================================
winform.plus.onMouseDown = function(wParam, lParam){
    if(wParam == 0x204){ // 右键重开
        if(win.msgboxTest("确定要重新开始吗?", "五子棋")) resetGame();
        return;
    }
    
    if(isGameOver || !isPlayerTurn) return; // 游戏结束或AI思考时禁止点击
    
    var x, y = win.getMessagePos(lParam);
    var c = ..math.round((x - margin) / cellSize) + 1;
    var r = ..math.round((y - margin) / cellSize) + 1;
    
    if(r < 1 || r > boardSize || c < 1 || c > boardSize) return;
    if(boardData[r][c] != 0) return;
    
    // --- 玩家落子 ---
    boardData[r][c] = 1; // 黑子
    lastMove = {r=r, c=c};
    winform.plus.redraw();
    
    if(checkWin(r, c, 1)){
        isGameOver = true;
        winform.text = "五子棋 - 玩家获胜!";
        win.msgbox("恭喜!你战胜了AI!");
    } else {
        isPlayerTurn = false;
        winform.text = "五子棋 - AI思考中...";
        // 延迟一点点执行,让UI先刷新出玩家的子,看起来更自然
        winform.setTimeout(computerMove, 50); 
    }
}

winform.show();
win.loopMessage();


修改要点解析

  1. AI 评分机制 (getPointScore): 这是 AI 的“大脑”。代码模拟了人类下棋的思维:

  • AI 会遍历棋盘上每一个空点。

  • 进攻(MyScore):计算“如果我下这,能连成什么样?”(例如:下这能连成 4 个,必胜,分数极高)。

  • 防守(EnemyScore):计算“如果我不下这,让玩家下这,他能连成什么样?”(例如:玩家下这就能连成活三,很危险,分数也很高)。

  • 最后取两者的总和。这意味着 AI 既想赢(进攻),也怕输(堵截玩家的关键子)。

  • 权重设计 (scoreTable)

    • win5 (100,000):必须赢,优先级最高。

    • live4 (10,000):活四(两头空),下一步必胜,优先级次之。

    • dead4 / live3 (1,000):死四或者活三,属于极具威胁的棋型。 通过调整这些数值,你可以改变 AI 的性格(比如进攻型或防守型)。

  • 回合制管理

    • 增加了 isPlayerTurn 变量。

    • 在 onMouseDown 中,玩家下完子后,立即锁定输入,设置 isPlayerTurn = false。

    • 使用 winform.setTimeout(computerMove, 50) 稍微延迟执行 AI 代码。这样做的好处是让界面有机会重绘,显示出玩家刚下的那颗黑子,然后再开始卡顿计算 AI。如果不延迟,界面会卡住,感觉像死机了一样。

    如何获胜?

    这个 AI 只有“一步预测”能力(它只看当前局面的最佳落点,不会预测未来几步)。虽然比较基础,但对于初学者来说已经相当难缠了。要赢它,你需要利用“双三”或者“四三”战术,同时制造两个威胁,让它顾此失彼。


    登录后方可回帖

    登 录
    信息栏
    本站域名

    ChengXu.XYZ

    投诉联系:  popdes@126.com



    快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

    这里主要专注于学习交流和经验分享.
    纯私人站,当笔记本用的,学到哪写到哪.
    如果侵权,联系 Popdes@126.com

    友情链接
    Aardio官方
    Aardio资源网


    才仁机械


    网站地图SiteMap

    Loading...