五子棋-人人对战
date: 2019-03-07
五子棋是国内受到普遍欢迎的一款游戏,规则简单,趣味不俗。作为一名程序员,自然也希望将它移植到电脑上。
这篇我们要讲的主要就是实现简单的人人对战,AI算法放到以后单独说。
我们先来整理一下脉络,看看实现五子棋需要哪些内容:
- 棋盘。这毋庸置疑
- 落子监听。下棋当然要把棋子画出来,显然我们是用鼠标来下棋,这里就需要用到鼠标的监听
- 胜负判断。下棋自然有输赢,每一步棋后都需要进行判断
棋盘
棋盘的绘制应该是十分简单,就不多说了,画成什么样就看自己的心情。当然,为了使用起来更加,我们可以加上开始游戏、悔棋、认输等按钮,按钮的监听我之前的文章也有讲过,不清楚的欢迎大家去看一下。其中,为了更合理一点,在开始游戏之前显然是不能悔棋和认输的,所以我们需要在开始游戏按钮按下之前将这两个按钮设置为无法使用,调用setEnabled方法就可以实现,需要一个参数,类型为布尔。
落子监听
按钮的监听我们添加在actionPerformed方法(使用这个方法需要添加ActionListener接口)里,通过e.getActionCommand来获得按钮的名字来判断是哪个按钮,实现相应的功能。而落子的监听我们通过mousePressed、mouseReleased或mouseClicked来实现(需要继承MouseAdapter类或者添加MouseListener接口)。
其中mouseClicked不推荐使用,因为不好界定click的时间,本身似乎也有些问题,有些时候会监听不到,而前两个则没有上述问题。我则选择了mousePressed。
棋盘已经绘制完成,而五子棋的子下在棋盘线的交点处,为了棋盘的公整,应当将棋下在交点上,这只需要简单的数学计算就可以算出来,至于棋子长什么样,大家自己动手。
棋子已经能画出来了,但这显然是不够的,因为之后还有胜负判断,人可以一眼看到棋盘上子落在何处,计算机可不行,我们得用容器将棋子落下的位置保存下来,一个二维数组即可(0表示空,1表示黑子,2表示白子,当然其他方法也可以)。此外如果我们还要添加悔棋功能,那么仅保存棋子落下的位置是完全不够的,我们需要知道落子的先后顺序,所以我们应当选择使用有序容器。这里我选择了Vector,当然其他有序容器也都可以,自己选择。
为了储存和之后的操作方便,我们把棋子的位置(x和y)用一个类来保存,这个类十分简单,只需要两个int即可。这里,我储存的x和y并非是棋子在棋盘上的绝对位置,而是棋子的序号(0-14),这样的好处是在中间使用的时候十分清楚,并且如果要改变棋盘的大小等属性,只需要在绘画时更改公式即可,中间过程一概不用动。
到这里,落子的监听基本就完成了,总结一下:
- 借助mousePressed方法,监听鼠标事件
- 通过二维数组储存棋盘各个位置的状态,方便判断胜负
- 通过Vector储存落子的顺序,方便悔棋
- 将棋子的坐标打包成一个类,储存其在棋盘上的序号,避免棋盘变化导致大量的改动需求
胜负判断
最后这一部分非常简单,只需要在每次落子之后判断一下是否达成五子即可。又因为五子棋规则简单,在落子之后棋子的位置不会再发生变化,所以只需要判断落子点是否会形成五子就可以,没必要每次都遍历全局。五子棋共有8个方向,但是形成连子其实只有四条直线,所以只需要判断四次。
先往上再往下,遇到异色子或者边界就停下,每个同色自给计数变量+1,加上自身含有5个即可达成胜利。这里基本不会遇到什么问题,只要细心判断边界,保证下标不越界就不会有任何问题。
重绘
上述三个部分完成,五子棋-人人对战基本就完成了,但是重绘是每次绘图都会遇到的问题,在这里就提醒一下不要忘记重绘,不懂重绘的可以去搜索一下关于重绘的文章,本身并不是很难。
个人博客:https://wilfredshen.cn/
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号