在经过了几天的学习后,已经可以实现一个简单的五子棋游戏了,下面我就写一下编写程序 的过程和自己在这个过程中的心得体会。
第一步:绘制棋盘和实现落子
具体的过程就不写了,我是绘制了一个15*15的棋盘,在棋盘的右侧添加了几个按钮分别是“开始游戏”、“悔棋”、“认输”、“人人对战”、“人机对战”。这里用到的API类主要有JFrame、JPanel、BorderLayout、JButton、JRadioButton、ButtonGroup、Dimension、MouseAdapter(MouseListener)、MouseEvent、ActionListener、ActionEvent、Graphics2D、Color。在实现落子的时候主要要考虑这几个问题。如何让棋子落在交叉点上,如何让一个交叉点只安放一个棋子,让黑棋和白旗按照顺序落下。因为鼠标点击的位置不可能每次都正好在交叉点上,所以要设置一个范围,只要在交叉点的这个范围内点击就能落子。创建一个保存棋子位置的二维数组,只要落了子就保存在数组中,这样一个点就只能下一个棋子了。最后设置一个计数器count,只要count=0就下黑棋,count=1下白棋即可。这里主要还有一个问题,因为每次添加JPanel面板时画笔就会重绘一次,这样会覆盖掉画好的棋子和棋盘,如果将窗口最小化再打开,就什么都没有了。这时候需要重写JPanel里的paint方法,将绘制棋盘和棋子的方法写入就可以了。
第二步:实现按钮功能和人人对战
“开始游戏”:将存放棋子位置的二位数组全部清零之后调用paint方法重绘棋盘即可。
“认输”:读取计数器count,如果是1则黑棋获胜,0则白棋获胜。
“悔棋”:我认为悔棋有两种方式,一种是刚刚下棋的一方悔一次棋,另一种是能够不断悔棋。我使用的是第二种方法。创建两个数组存放每次落子的横坐标和纵坐标,当点击按钮时将这一位置清零然后重绘棋盘即可。
人人对战的算法比较好实现,只要判断左右,上下,y=x,y=-x这八个方向上有没有连续的相同颜色的五个棋子就行。
public int checkrow(int x, int y){
int count1=0;//存放连续的相同颜色的棋子数for(int i=x+1;i<15;i++){
if(chess[i][y]==chess[x][y]){
count1++;
}
else {
break;
}
}
for(int i=x;i>=0;i--){
if(chess[i][y]==chess[x][y]){
count1++;
}
else {
break;
}
}
return count1;
}
这是左右方向的算法,其他方向的以此类推。这样,只要每次下完棋都判断一次,就能知道那方获胜。
第三步:实现人机对战
查看了网上的资料后,发现五子棋的AI主要有两个算法,一个是博弈树,另一个是权值算法。因为博弈树算法比较复杂 ,所以我使用的是权值算法。权值算法就是在每次落子之后,在落子的周围空位上生成权值,哪个空位的权值大,就让AI下在那个位置。这就需要我们创建一个哈希表,将每一种棋子相连的情况对应一个权值.
HashMap hm = new HashMap();
public void hxb(){
hm.put("2", 30);
hm.put("1", 10);
hm.put("22", 1000);
hm.put("21", 20);
hm.put("11", 1500);
hm.put("12", 15);
hm.put("222", 10000);
hm.put("221", 150);
hm.put("112", 100);
hm.put("111", 3000);
hm.put("1111", 20000);
hm.put("2222", 100000);
hm.put("1112", 2000);
hm.put("2221", 1900);
hm.put("22221", 50000);
hm.put("11112", 15000);
}
这里我使用字符串来保存棋子相连的情况,1对应黑棋,2对应白棋,12就是一个黑棋和一个白棋相连。对应的权值大小可以自行调整。
在创建好哈希表后,接下来要做的就是写一个方法,给予每一个空位权值。
public void AI(){
for(int i=0;i<15;i++){
for(int j=0;j<15;j++){
if(chess[i][j]==0){
//搜索该空位八个方向上棋子相连情况//定义:chess变量记录棋子相连情况,color记录棋子颜色String czf="";
int color=0;
for(int k=i+1;k<15;k++){
if(chess[k][j]==0){
break;
}else{ if(color==0){
czf+=chess[k][j];
color=chess[k][j];
}else if(color==chess[k][j]){
czf+=chess[k][j];
}else{
czf+=chess[k][j];
break;
}
}
}
//根据棋子相连情况取出对应的权值累加Integer value = hm.get(czf);
if(value!=null){
chessValue[i][j]+=value;
}
czf="";
color=0;
//向左 }
}
}
}
这里的是根据左右方向给予权值,其他方向以此类推。之后就是根据权值让AI落子。要注意的是每一次AI落子后都要讲存放空位权值的数组chessValue清零。剩下的就是把一些细节部分给完善,这样,一个简单的五子棋游戏就完成了。
在写这个游戏的过程中出现了许许多多的错误,也收获了很多的东西。真正写起来,算法的部分其实不是很难完成,主要是细节方面的错误太多了,也浪费了很多时间。写程序的时候,一个清晰的思路十分重要,脑海里还要有一个大概的框架。在出现问题时,要仔细分析问题,寻找问题的源头。与同伴的交流也十分的重要,因为每个人的看法不同,所以和同伴沟通能够提供新的思路,碰撞出新的火花,解决问题的时候也能大大提升效率。最重要的,和同伴一起完整一项工作是一件挺开心的事:-D。