public int row; //行 public int col; //列 2、检查越位
棋子的位置并非是任意的,玩家和计算机每走一步棋之前都要线检查该位置的合法性,即棋子是否在棋盘上,否则判为无效落子。检查是否越界的代码如下:
public boolean is In Board(int board Size) //判断棋子是否越界(超出棋盘) {
return row >= 0 && row < board Size && col >= 0 && col < board Size; }
3、修改棋子位置
在创建好 Dot 对象后,Dot 类提供了两种方法更改棋子位置,包括设置行列位置和从已有棋子中复制参数。
public void set Row Col(int r, int c) //设置棋子位置 {
row = r; col = c; }
public void copy From(Dot d) //复制已有的棋子 {
row = d.row; col = d.col; }
4.3.4 对战逻辑类的实现
1、建立数据结构
本程序以数组保存当前盘面的情况,每个位置可能有三种状态:空、玩家的落子、计算机的落子,分别用 0、1、2 来表示。代码如下:
public static int PLAYER_NONE = 0; //该位置为空
public static int PLAYER_COMPUTER = 1; //该位置有电脑的落子
public static int PLAYER_HUMAN = 2; //该位置有玩家的落子
棋盘在初始情况下为空,即棋子上没有任何棋子,在Gobang Logic类的构造函数中对棋盘进行初始化:
table = new int[board Size][board Size];//创建棋盘数组 for(int r = 0; r < board Size; r++) {
for(int c = 0; c < board Size; c++) table[r][c] = 0; //初始化盘面为空 }
除了记录棋盘上每个位置的落子状态外,程序还将对每种状态的位置个数进行统计,以对算法进行简化。对三种状态的统计存储在整型数组中,该数组为全局变量。
private int player Counter[];
在 Gobang Logic 类的构造函数中对三种状态的计数进行初始化,即棋盘上都是空、计算机的落子或玩家的落子状态的个数为 0,在数据结构上,把空也当做某一特殊玩家。
初始化代码如下:
player Counter = new int[3]; //落子状态计数器
player Counter[0] = board Size * board Size; //整个棋盘都是空的状态 player Counter[1] = 0; //电脑落子0 player Counter[2] = 0; //玩家落子0 2、落子和悔棋
这里使用了一个 Dot 类棋子对象来记录最后一步棋的位置,当玩家下了一步棋后需要将上一步重新绘制,以消除旗子上的引导框。另外,还是用了堆栈来存储最近的几步落子,以便玩家悔棋。
private Dot last Dot; //棋子对象,存储最后一步落子 private Stack steps; //棋子对象的堆栈
最后一步棋子和棋子堆栈在 Gobang Logic 类的构造函数中进行初始化; last Dot = new Dot(board Size); //创建棋子对象用来存储最后一步棋,初始化
位置为棋盘中央steps = new Stack();//堆栈对象,用来存储最近的几部棋在棋盘上落子的代码如下:
private void go At(int row, int col, int player) //电脑或人在 row、col 位置上走 {
int last Row = last Dot.row; //记录上一步的行坐标 int last Col = last Dot.col; //记录上一步的列坐标 table[row][col] = player; //当前位置填充玩家代码
last Dot.set Row Col(row, col); //将这一部设置为“最后一步” game Canvas.repaint At(last Row, last Col); //重新绘制上一步(将引导框去掉)
game Canvas.repaint At(row, col); //绘制当前这步 switch(player) //统计双方落子数量 { case 1:
player Counter[1]++; //电脑的步数 break; case 2:
player Counter[2]++; //玩家的步数 break; }
player Counter[0]--; //空白的个数
if(steps.size() > 10) //堆栈数量超过上限(10) steps.remove Element At(0); //清除栈底
steps.push(new Dot(row, col)); //将当前这步棋子压入堆栈 }
Stack(堆栈类)从 Vector 集成而来,它使用 push()方法进入堆栈,需要时使用 pop()方法从堆栈的顶部将其取出。悔棋动作由玩家做出,从数据结构来看,是同时后退两步(将最后两步棋位置的落子状态设置为空)。
Stack 类的 peek()方法将获取栈顶对象,但不移。悔棋代码如下: :
public boolean undo()//悔棋 {
if(steps.size() >= 3) {
Dot d = new Dot();//创建棋子对象
d.copy From((Dot)steps.pop());//从堆栈弹出的棋子中复制行列位置坐标 table[d.row][d.col] = 0;//将该位置设置为空
game Canvas.repaint At(d.row, d.col); //在棋盘上重新绘制该位置 d.copy From((Dot)steps.pop());//从堆栈弹出的棋子中复制行列位置坐标 table[d.row][d.col] = 0; //将该位置设置为空
game Canvas.repaint At(d.row, d.col); //在棋盘上重新绘制该位置 d.copy From((Dot)steps.peek());//获取栈顶对象,作为最后一步棋存储 last Dot.copy From(d);
game Canvas.repaint At(d.row, d.col); //重新绘制最后一步(添加引导框) return true; //悔棋成功 } else {
return false; //悔棋失败 } }
4.4 本章小结
本章主要内容是游戏的实现,包括主类的实现,如构造函数、事件处理等,游戏帮助和介绍表单类的实现,游戏设置类的实现,如棋盘、选手、难度等,旗子类的实现,如棋子行列位置、检查越界等,对战逻辑类的实现,如落子和悔棋、逻辑运算等的实现。