资讯动态

Java图形化编程笔记:哈希表与简易五子棋AI

发布时间:2026/8/22 17:59:44 来源:尧图企业网站定制
前言本文面向编程零基础小白用生活化案例通俗讲解 Java 中哈希表HashMap的核心概念、组成要素与完整实操流程手把手演示简易五子棋AI的完整可运行代码示例。一、核心概念哈希表HashMap哈希表也是一种数据结构。它跟数组的区别是数组的索引必须是数字0、1、2…哈希表的索引可以是任何东西字符串、数字、引用类型都行。比如//这里用泛型规范了它的索引与内容字符串整型hmnewHashMapString,Integer();//带双引号的数字是字符串纯数字是整型hm.put(1,20);hm.put(11,200);hm.put(111,2000);hm.put(1111,3000);想拿 20 的时候通过调用 hm.get(“1”) 方法就能拿到。在五子棋 AI 里哈希表存的是“棋形”和与其对应的“分数”。我用一个整型二维数组保存棋盘的情况0表示空1表示黑子2表示白子。于是111 就表示“三个黑棋连在一起”对应的分数是 2000。AI 在遍历棋盘时看到什么棋形就去哈希表查对应的分数然后累加到空位的权值上。权值权值可以理解成“这个位置有多重要”的分数。AI 在计算时会给棋盘上每个空位打一个分数。分数越高说明这个位置越重要。要么是进攻自己能连成五子要么是防守堵住对方的棋。打分的逻辑就是以一个空位为中心往八个方遍历把看到的棋子一颗一颗拼成一个字符串比如 “111”、“12”然后去哈希表里查这个棋形对应的分数八个方向的分数累加起来就是这个空位的总权值。接着去到下一个空位做同样的事。最后 AI 选权值最高的位置下棋。二、五子棋 AI 的组成要素权值表哈希表权值表里面存了各种棋形对应的分数让 AI 有一个基础的对棋局的判断能力做出权值分最高的反应对AI来说是最值得做的选择。不过以玩家的角度来看是不是一步好棋就不一定了。需要存两类棋形黑棋的棋形“1”、“11”、“111”、“1111”这是 AI 用来防守的因为黑棋是玩家的棋子白棋的棋形“2”、“22”、“222”、“2222”这是 AI 用来进攻的因为白棋是 AI 自己的棋子混合棋形如 “112” 表示两个黑棋后面跟了一个白棋表示这条线被对方或我方堵住了。虽然还有威胁、或者进攻价值但已经没那么大了所以分数比纯连子低。这些混合棋形同样重要否则AI在遇到被堵的情况时查不到分数会漏掉这些比较关键的信息。决策方法AI 的核心方法会做这几件事遍历棋盘上所有空位对每个空位往八个方向看把看到的棋子拼成字符串用拼好的字符串去权值表里查分数累加到权值数组里找出权值最高的位置在那个位置下棋八个方向分别是右、左、下、上、右下、左上、左下、右上。每个方向都要单独检查检查完后重置字符串防止不同方向之间互相干扰。随机选择如果多个位置的权值相同AI 每次都会选择第一个导致每局棋的走法都一样大大削减游戏的可玩性和乐趣。所以我通过查资料研究了一套简单的随机算法.当多个位置分数相同且并列最高时在AI看来它们同等重要选择任何一个都不会降低棋力。用随机选择在这些同等好的位置中挑一个既保证了AI的水平又让每局棋的走法不同增加了游戏的可玩性。我用Java标准库自带的动态数组ArrayList做了一个简单的“盲盒”随后定义了一个变量用来记录所有的最高分。首先遍历一遍棋盘记录第一个遍历的位置x1,y1的分数再到第二个位置x1,y2如果这个位置的分数比上一个小就不管。如果比上一个大就清空数组只记录这个。如果一样大那就一起记录下来。最后数组里只会剩下几个相同的分数对应几个不同的位置它们在 AI 看来都是最适合下棋的位置接下来就在其中随机选一个下就好了。intmaxScore-1;//定义变量用来记录最大值。ArrayListint[]bestPositionsnewArrayListint[]();for(inti0;iLINE;i){for(intj0;jLINE;j){//这两行用来遍历棋盘if(chessValue[i][j]maxScore){//如果该位置比最大值还大maxScorechessValue[i][j];//新的最大值诞生bestPositions.clear();//清空原先的数组bestPositions.add(newint[]{i,j});//往数组中放入该位置}elseif(chessValue[i][j]maxScore){//如果一样大bestPositions.add(newint[]{i,j});//一起存进去}}}intaiRow-1,aiCol-1;//定义变量AI 下棋的位置if(!bestPositions.isEmpty()){//如果“盲盒”不是空的Randomrandnewjava.util.Random();//创建筛子对象//从“盲盒”中随机选一对坐标int[]chosenbestPositions.get(rand.nextInt(bestPositions.size()));aiRowchosen[0];aiColchosen[1];三、实操案例五子棋棋盘与 AI 以外玩法逻辑完整代码请见“Java图形化编程笔记五子棋——从下棋、判输赢到复盘”构造方法内给哈希表publicMPanel(){hmnewHashMapString,Integer();//黑棋防守hm.put(1,20);hm.put(11,200);hm.put(111,2000);hm.put(1111,3000);//白棋进攻hm.put(2,20);hm.put(22,200);hm.put(222,2000);hm.put(2222,3000);//混合情况hm.put(12,10);hm.put(112,100);hm.put(1112,1000);hm.put(11112,2000);hm.put(21,10);hm.put(221,100);hm.put(2221,1000);hm.put(22221,2000);}AI 方法部分代码遍历棋盘上每个空位往八个方向检查拼棋形字符串累加权值随机选择最终位置。importjava.util.ArrayList;importjava.util.Random;publicvoidAI(){int[][]chessValuenewint[LINE][LINE];for(inti0;iLINE;i){for(intj0;jLINE;j){if(board[i][j]!0)continue;Stringcode;intcolor0;//往右for(intkj1;kLINE;k){if(board[i][k]0)break;if(color0){colorboard[i][k];codeboard[i][k];}elseif(board[i][k]color){codeboard[i][k];}else{codeboard[i][k];break;}}Integervaluehm.get(code);if(value!null)chessValue[i][j]value;//往左code;color0;for(intkj-1;k0;k--){if(board[i][k]0)break;if(color0){colorboard[i][k];codeboard[i][k];}elseif(board[i][k]color){codeboard[i][k];}else{codeboard[i][k];break;}}valuehm.get(code);if(value!null)chessValue[i][j]value;//往上code;color0;for(intki1;kLINE;k){if(board[k][j]0)break;if(color0){colorboard[k][j];codeboard[k][j];}elseif(board[k][j]color){codeboard[k][j];}else{codeboard[k][j];break;}}valuehm.get(code);if(value!null)chessValue[i][j]value;//往下code;color0;for(intki-1;k0;k--){if(board[k][j]0)break;if(color0){colorboard[k][j];codeboard[k][j];}elseif(board[k][j]color){codeboard[k][j];}else{codeboard[k][j];break;}}valuehm.get(code);if(value!null)chessValue[i][j]value;//右上code;color0;for(intk1;ikLINEjkLINE;k){if(board[ik][jk]0)break;if(color0){colorboard[ik][jk];codeboard[ik][jk];}elseif(board[ik][jk]color){codeboard[ik][jk];}else{codeboard[ik][jk];break;}}valuehm.get(code);if(value!null)chessValue[i][j]value;//右下code;color0;for(intk1;i-k0j-k0;k){if(board[i-k][j-k]0)break;if(color0){colorboard[i-k][j-k];codeboard[i-k][j-k];}elseif(board[i-k][j-k]color){codeboard[i-k][j-k];}else{codeboard[i-k][j-k];break;}}valuehm.get(code);if(value!null)chessValue[i][j]value;//左上code;color0;for(intk1;i-k0jkLINE;k){if(board[i-k][jk]0)break;if(color0){colorboard[i-k][jk];codeboard[i-k][jk];}elseif(board[i-k][jk]color){codeboard[i-k][jk];}else{codeboard[i-k][jk];break;}}valuehm.get(code);if(value!null)chessValue[i][j]value;//左下code;color0;for(intk1;ikLINEj-k0;k){if(board[ik][j-k]0)break;if(color0){colorboard[ik][j-k];codeboard[ik][j-k];}elseif(board[ik][j-k]color){codeboard[ik][j-k];}else{codeboard[ik][j-k];break;}}valuehm.get(code);if(value!null)chessValue[i][j]value;}}intmaxScore-1;ArrayListint[]bestPositionsnewArrayListint[]();for(inti0;iLINE;i){for(intj0;jLINE;j){if(chessValue[i][j]maxScore){maxScorechessValue[i][j];bestPositions.clear();bestPositions.add(newint[]{i,j});}elseif(chessValue[i][j]maxScore){bestPositions.add(newint[]{i,j});}}}intaiRow-1,aiCol-1;if(!bestPositions.isEmpty()){Randomrandnewjava.util.Random();int[]chosenbestPositions.get(rand.nextInt(bestPositions.size()));aiRowchosen[0];aiColchosen[1];}if(aiRow!-1aiCol!-1){board[aiRow][aiCol]cut;repaint();rexArr[step]aiCol;reyArr[step]aiRow;step;if(checkWin(aiRow,aiCol,cut)){if(cut1){JOptionPane.showMessageDialog(this,黑棋获胜);}else{JOptionPane.showMessageDialog(this,白棋获胜);}gamefalse;return;}cut(cut1)?2:1;}}

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价