• 教你写一个入门级别的五子棋AI


    前言

    本文只是介绍五子棋AI的实现,最终的成品只是一个 AI 接口,并不包括 GUI,且不依赖 GUI

    五子棋 AI 的实现并不难,只需要解决一个问题就行:

    怎么确定AI的最佳落子位置?

    一般情况下,五子棋棋盘是由15条横线和15条纵线组合而成的,15x15 的棋盘共有 225 个交叉点,也就是说共有 225 个落子点。

    假如说,AI 是黑棋,先行落子,所以 AI 总共有 225 个落子点可以选择,我们可以对每个落子点进行评估打分,哪个分高下哪里,这样我们就能确定最佳落子点了。

    但这样又引出了一个新的问题:

    怎么对落子点进行评估打分呢?

    这就是本文的重点了,请看后文!

    实现过程

    抽象

    注:部分基础代码依赖于 lombok,请自行引入,或手写基础代码。

    落子位置实体类,这里我们定义棋子类型字段:type1表示黑子,2表示白子。

    1. /**
    2. * 棋子点位
    3. *
    4. * @author anlingyi
    5. * @date 2021/11/10
    6. */
    7. @AllArgsConstructor
    8. @NoArgsConstructor
    9. @ToString
    10. public class Point {
    11. /**
    12. * 横坐标
    13. */
    14. int x;
    15. /**
    16. * 纵坐标
    17. */
    18. int y;
    19. /**
    20. * 棋子类型 1.黑 2.白
    21. */
    22. int type;
    23. }
    24. 复制代码

    AI 对外提供的接口,不会依赖任何 GUI 代码,方便其他程序调用。

    1. /**
    2. * 五子棋AI接口
    3. *
    4. * @author anlingyi
    5. * @date 2021/11/10
    6. */
    7. public interface AIService {
    8. /**
    9. * 获取AI棋位
    10. *
    11. * @param chessData 已下棋子数据
    12. * @param point 对手棋位
    13. * @param started 是否刚开局
    14. * @return
    15. */
    16. Point getPoint(int[][] chessData, Point point, boolean started);
    17. }
    18. 复制代码

    这个接口需要知道我们现在的棋盘落子数据 chessData,还有对手上一步的落子位置 pointstarted 参数表示是否是刚开局,后续可能对刚开局情况做单独的处理。

    实现AI接口

    我们创建一个类 ZhiZhangAIService,这个类实现 AIService 接口,来写我们的实现逻辑。

    1. /**
    2. *
    3. * 五子棋AI实现
    4. *
    5. * @author anlingyi
    6. * @date 2021/11/10
    7. */
    8. public class ZhiZhangAIService implements AIService {
    9. /**
    10. * 已下棋子数据
    11. */
    12. private int[][] chessData;
    13. /**
    14. * 棋盘行数
    15. */
    16. private int rows;
    17. /**
    18. * 棋盘列数
    19. */
    20. private int cols;
    21. /**
    22. * AI棋子类型
    23. */
    24. private int ai;
    25. /**
    26. * 声明一个最大值
    27. */
    28. private static final int INFINITY = 999999999;
    29. @Override
    30. public Point getPoint(int[][] chessData, Point point, boolean started) {
    31. // 初始化棋盘数据
    32. initChessData(chessData);
    33. // 计算AI的棋子类型
    34. this.ai = 3 - point.type;
    35. if (started) {
    36. // AI先下,首子天元
    37. int centerX = this.cols / 2;
    38. int centerY = this.rows / 2;
    39. return new Point(centerX, centerY, this.ai);
    40. }
    41. // 获取最佳下棋点位
    42. return getBestPoint();
    43. }
    44. /**
    45. * 初始化棋盘数据
    46. *
    47. * @param chessData 当前棋盘数据
    48. */
    49. private void initChessData(int[][] chessData) {
    50. // 获取棋盘行数
    51. this.rows = chessData.length;
    52. // 获取棋盘列数
    53. this.cols = chessData[0].length;
    54. // 初始化棋盘数据
    55. this.chessData = new int[this.cols][this.rows];
    56. // 深拷贝
    57. for (int i = 0; i < cols; i++) {
    58. for (int j = 0; j < rows; j++) {
    59. this.chessData[i][j] = chessData[i][j];
    60. }
    61. }
    62. }
    63. /**
    64. * 获取最佳下棋点位
    65. *
    66. * @return
    67. */
    68. private Point getBestPoint() {
    69. Point best = null;
    70. // 初始分值为最小
    71. int score = -INFINITY;
    72. /* 遍历所有能下棋的点位,评估各个点位的分值,选择分值最大的点位 */
    73. for (int i = 0; i < this.cols; i++) {
    74. for (int j = 0; j < this.rows; j++) {
    75. if (this.chessData[i][j] != 0) {
    76. // 该点已有棋子,跳过
    77. continue;
    78. }
    79. Point p &
  • 相关阅读:
    气相色谱质谱仪样品传输装置中电动针阀和微泄漏阀的解决方案
    【数据结构与算法】手撕链表OJ题
    Redis持久化策略AOF、RDB详解及源码分析
    指令系统(408)
    关于JAVA进阶你需要学习什么?
    防火墙的策略路由PBR
    深度学习七 —— BN & LN & IN & GN
    Matlab代码格式一键美化神器
    Electron程序逆向(asar归档解包)
    小节9:Python之numpy
  • 原文地址:https://blog.csdn.net/ch98000/article/details/126892117