项目分享| 自制井字游戏,人机大战谁赢?代码说了算
只要有一块Arduino开发板、一个可触摸的显示屏就可以制作了。
-
人机大战井字游戏,你猜谁会赢?
想让谁赢,谁就能赢。为啥?因为程序是人编写的呀。想要知道为什么的,接着往下看,如何设计这个游戏(Arduino Tic-Tac-Toe )吧。
只要有一块Arduino开发板、一个可触摸的显示屏就可以制作了。不管是新手,还是老手;不管是有孩子的,还是有女朋友的,都可以玩起来了。
是不是在想用什么人工智能算法?并没有。Arduino 虽然简单易用,但为 Arduino 开发游戏并不容易,而且需要大量时间。
第1步:获取所需硬件
此项目所需的硬件如下:
-
Arduino Uno开发板
-
2.8 英寸触摸屏
由此可见,搭建这个游戏的成本极低,不会超过100元,如果手头上有现成的就更棒了,拿来就能用。
第2步:用于 Arduino 的 2.8" 触摸彩色显示屏
在某宝上,此类屏幕一大把,任君挑选,50元以内搞定。
视频中用的显示屏分辨率为320x240,并且以电路板的形式封装好,这这样屏幕和Arduino之间的连接变得非常容易。电路板另一个优点是提供了一个非常易于使用的 micro SD 插槽。
显示屏几乎使用了 Arduino Uno 的所有数字和模拟引脚。使用电路连接板就只剩下 2 个数字引脚和 1 个模拟引脚。显示屏也可以与 Arduino Mega 配合使用,因此当需要更多引脚时,可以使用 Arduino Mega 或其他的MCU。
大家在选用显示屏的时候,需要确认下是否和自己的MCU匹配。比如这个项目中用的显示屏就不适用于 Arduino Due 或 Wemos D1 ESP8266 板。
第3步:搭建并测试
将屏幕连接到 Arduino Uno 后,就可以加载代码并准备玩起来。
首先,按下“开始游戏”按钮,游戏开始。Arduino首先会下第一颗棋子,然后我们只需触摸屏幕即可下棋。成功将三个棋子放置在水平、垂直或对角线中的玩家赢得游戏。游戏结束时,会出现“游戏结束”提示。然后可以按下再次播放按钮,重新开始游戏。
Arduino非常擅长这个游戏,大部分的比赛它都能赢,除非你是一个高手,才可能以很小的概率赢得比赛或是平局。2 美元的 Arduino CPU 芯片怎么能打败人脑呢?我们开发的程序肯定不会比人脑更聪明的。前面说了,想要让人赢得Arduino,只要在代码里添加两行即可。
所以,接下来的算法,是游戏的核心所在。
第4步:游戏算法
先来看一下视频里实现的算法。
Arduino先下第一手棋(玩过这个游戏的人就知道,先出手会更容易赢得比赛)。Arduino的第一步永远是一个角落,第二步也是剩余的随机角落,根本不关心玩家是怎么放棋子。
从第三步开始,Arduino 就会检查玩家是否可以在下一步中获胜并放置棋子阻止。如果玩家不能在这一步中获胜,Arduino 会在可用的情况下进行角移动,或者从剩余移动中随机移动。就是这样,这个简单的算法每次都可以击败人类玩家,或者在最坏的情况下,游戏平局。这不是最好的井字游戏算法,而是最简单的算法之一。
井字游戏非常简单,我们可以很容易地分析,所以这个算法很容易在 Arduino 中实现。如果我们设计博弈树状图,就可以发现一些获胜策略并在代码中轻松实现它们,或者我们可以让 CPU 实时计算博弈树并自行选择最佳移动位置。
第5步:项目代码
首先,需要三个库来编译代码。
📥 修改后的Adafruit TFTLCD:
https://educ8s.tv/wp-content/uploads/2016/11/Adafruit_TFTLCD.zip
📥 Adafruit GFX:https ://github.com/adafruit/Adafruit-GFX-Library
📥 触摸屏:https ://github.com/adafruit/Touch-Screen-Library
一直说这是一个非常简单的游戏,但代码却是超过600行了。代码很复杂,这里不多解释了,感兴趣的可以下载学习。(在“达尔闻说”微信回复:井字游戏)
这里,为大家展示 Arduino 移动算法的实现。
首先,我们玩两个随机角。
int firstMoves[]={0,2,6,8}; // will use these positions first
for(counter=0;counter<4;counter++) //Count first moves played
{
if(board[firstMoves[counter]]!=0) // First move is played by someone
{
movesPlayed++;
}
}
do{
if(moves<=2)
{
int randomMove =random(4);
int c=firstMoves[randomMove];
if (board[c]==0)
{
delay(1000);
board[c]=2;
Serial.print(firstMoves[randomMove]);
Serial.println();
drawCpuMove(firstMoves[randomMove]);
b=1;
}
}
接下来,在每一轮中,我们检查玩家是否可以在下一步中获胜。
<p>int checkOpponent()<br>{
if(board[0]==1 && board[1]==1 && board[2]==0)
return 2;
else if(board[0]==1 && board[1]==0 && board[2]==1)
return 1;
else if (board[1]==1 && board [2]==1 && board[0]==0)
return 0;
else if (board[3]==1 && board[4]==1 && board[5]==0)
return 5;
else if (board[4]==1 && board[5]==1&& board[3]==0)
return 3;
else if (board[3]==1 && board[4]==0&& board[5]==1)
return 4;
else if (board[1]==0 && board[4]==1&& board[7]==1)
return 1;
else
return 100;
}
如果是,在大多数情况下都会阻止。我们不会为了给人类玩家一个获胜的机会而阻止所有的动作。你能找出哪些动作没有被阻止吗?阻止移动后,我们玩剩余的角落,或随机移动。可以研究代码,轻松实现自己无与伦比的算法。
第6步:最后的想法和改进
即使使用 Arduino Uno,我们也可以为简单游戏构建无与伦比的算法。这个项目很有趣,也很容易复制,同时也很好地介绍了人工智能和游戏编程。感兴趣的小伙伴可以试试使用性能更高的控制器实现五子棋的游戏,相信这会是一个不小的挑战哟。
来源:hackster.io
作者:Nick Koumaris
-
-