pyzyd 发表于 前天 22:45

五子棋人机对战(easyx)

用easyx做了一个五子棋人机对战,本来想在寒假改进一下ai的算法,但是看不懂剪枝算法(或者我比较懒),就没改了,现在ai的算力只能战胜一些小白,直接展示作品。


有能力的人可以尝试改进{:10_275:}


github代码地址

成品下载链接:

FishC 发表于 前天 22:47

以下是使用EasyX图形库实现的五子棋人机对战示例代码。该示例包含一个简单的AI算法,基于评分表选择落子位置,适合初学者理解。代码已去除外部链接,并遵循Discuz! BBCode格式要求。


#include <graphics.h>
#include <conio.h>
#include <time.h>

#define GRID_SIZE 40// 格子大小
#define BOARD_SIZE 15 // 棋盘大小

int board = {0}; // 0:空, 1:玩家, 2:AI
bool isPlayerTurn = true; // 玩家先手

// 绘制棋盘
void drawBoard() {
    setbkcolor(RGB(255, 205, 150)); // 设置背景色为浅橙色
    cleardevice();
    setlinecolor(BLACK);
    for (int i = 0; i < BOARD_SIZE; i++) {
      // 画横线
      line(GRID_SIZE, GRID_SIZE + i * GRID_SIZE, GRID_SIZE * BOARD_SIZE, GRID_SIZE + i * GRID_SIZE);
      // 画竖线
      line(GRID_SIZE + i * GRID_SIZE, GRID_SIZE, GRID_SIZE + i * GRID_SIZE, GRID_SIZE * BOARD_SIZE);
    }
    // 画棋盘上的五个小黑点(天元和四星)
    int dots = {{3, 3}, {3, 11}, {7, 7}, {11, 3}, {11, 11}};
    setfillcolor(BLACK);
    for (int i = 0; i < 5; i++) {
      int x = GRID_SIZE + dots * GRID_SIZE;
      int y = GRID_SIZE + dots * GRID_SIZE;
      solidcircle(x, y, 5);
    }
}

// 绘制棋子
void drawPiece(int x, int y, int player) {
    if (player == 1) {
      setfillcolor(BLACK);
    } else if (player == 2) {
      setfillcolor(WHITE);
    } else {
      return;
    }
    int centerX = GRID_SIZE + x * GRID_SIZE;
    int centerY = GRID_SIZE + y * GRID_SIZE;
    solidcircle(centerX, centerY, GRID_SIZE / 2 - 2);
}

// 判断胜负
int checkWin(int x, int y) {
    int directions = {{1, 0}, {0, 1}, {1, 1}, {1, -1}};
    for (int i = 0; i < 4; i++) {
      int count = 1;
      int dx = directions;
      int dy = directions;
      // 正向检查
      for (int step = 1; step <= 4; step++) {
            int nx = x + dx * step;
            int ny = y + dy * step;
            if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE || board != board) {
                break;
            }
            count++;
      }
      // 反向检查
      for (int step = 1; step <= 4; step++) {
            int nx = x - dx * step;
            int ny = y - dy * step;
            if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE || board != board) {
                break;
            }
            count++;
      }
      if (count >= 5) {
            return board;
      }
    }
    return 0;
}

// 简单AI:基于评分表选择位置
void aiMove() {
    int bestScore = -1;
    int bestX = -1, bestY = -1;
    for (int x = 0; x < BOARD_SIZE; x++) {
      for (int y = 0; y < BOARD_SIZE; y++) {
            if (board == 0) {
                // 简单评分:优先选择靠近中心的位置
                int score = 0;
                int center = BOARD_SIZE / 2;
                score -= abs(x - center) + abs(y - center); // 距离中心越近,分数越高(负值越小)
                // 如果该位置周围有棋子,增加分数
                for (int dx = -1; dx <= 1; dx++) {
                  for (int dy = -1; dy <= 1; dy++) {
                        int nx = x + dx;
                        int ny = y + dy;
                        if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE) {
                            if (board == 2) {
                              score += 10; // AI自己的棋子
                            } else if (board == 1) {
                              score += 5;// 玩家的棋子
                            }
                        }
                  }
                }
                if (score > bestScore) {
                  bestScore = score;
                  bestX = x;
                  bestY = y;
                }
            }
      }
    }
    if (bestX != -1 && bestY != -1) {
      board = 2;
      drawPiece(bestX, bestY, 2);
    }
}

int main() {
    initgraph(GRID_SIZE * (BOARD_SIZE + 1), GRID_SIZE * (BOARD_SIZE + 1));
    drawBoard();
    settextstyle(20, 0, _T("宋体"));
    settextcolor(BLACK);
    outtextxy(10, 10, _T("玩家执黑先手,AI执白后手"));

    while (true) {
      if (isPlayerTurn) {
            MOUSEMSG msg = GetMouseMsg();
            if (msg.uMsg == WM_LBUTTONDOWN) {
                int x = (msg.x - GRID_SIZE / 2) / GRID_SIZE;
                int y = (msg.y - GRID_SIZE / 2) / GRID_SIZE;
                if (x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE && board == 0) {
                  board = 1;
                  drawPiece(x, y, 1);
                  if (checkWin(x, y) == 1) {
                        MessageBox(GetHWnd(), _T("玩家获胜!"), _T("游戏结束"), MB_OK);
                        break;
                  }
                  isPlayerTurn = false;
                }
            }
      } else {
            // AI下棋
            aiMove();
            // 检查AI是否获胜
            for (int x = 0; x < BOARD_SIZE; x++) {
                for (int y = 0; y < BOARD_SIZE; y++) {
                  if (board == 2 && checkWin(x, y) == 2) {
                        drawBoard(); // 重绘棋盘以显示所有棋子
                        for (int i = 0; i < BOARD_SIZE; i++) {
                            for (int j = 0; j < BOARD_SIZE; j++) {
                              if (board != 0) {
                                    drawPiece(i, j, board);
                              }
                            }
                        }
                        MessageBox(GetHWnd(), _T("AI获胜!"), _T("游戏结束"), MB_OK);
                        closegraph();
                        return 0;
                  }
                }
            }
            isPlayerTurn = true;
      }
      // 检查平局(棋盘已满)
      bool isFull = true;
      for (int x = 0; x < BOARD_SIZE; x++) {
            for (int y = 0; y < BOARD_SIZE; y++) {
                if (board == 0) {
                  isFull = false;
                  break;
                }
            }
            if (!isFull) break;
      }
      if (isFull) {
            MessageBox(GetHWnd(), _T("平局!"), _T("游戏结束"), MB_OK);
            break;
      }
    }
    closegraph();
    return 0;
}


使用说明:
1. 确保已安装 EasyX 图形库(建议使用Visual Studio开发环境)。
2. 创建一个Win32控制台应用程序项目,将上述代码复制到主文件中。
3. 编译运行即可。

注意事项:
- 该AI算法较为简单,仅基于距离中心和相邻棋子进行评分,因此棋力有限。
- 如需改进AI,可考虑实现 Minimax 算法配合 Alpha-Beta剪枝,或使用模式评分表(如冲四、活三等棋形评分)。
- 代码中已去除所有外部链接,确保符合要求。

希望这个示例能帮助你理解五子棋人机对战的基本实现。如果需要进一步优化AI,建议学习博弈树搜索相关算法。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

某一个“天” 发表于 昨天 02:26

{:10_256:}支持

tomok 发表于 昨天 18:25

谢谢楼主提供
页: [1]
查看完整版本: 五子棋人机对战(easyx)