1.1 引言
控制台五子棋,顾名思义,就是在 Java 控制台运行的五子棋游戏,需要用户用键盘输入棋子的位置来进行游戏。
由于是在控制台下面运行的程序,所以并没有漂亮的游戏界面,与及鼠标操作等东西,只是在一片黑色控制台环境下进行游戏,游戏的可玩性并不高,似乎这并不是一个完整的游戏。虽然如此,但事实上,一个程序最重要的并不是界面,而是处理各种业务逻辑与数据的方法,只要掌握了核心的方法,掌握基础的知识,便更容易学习 awt,swing 等图形用户界面的编写,万变不离其宗,写起有操作界面的程序也会变得更加容易,更加随心应手。
1.1.1 五子棋介绍
五子棋的玩法与规则如下:
(1)五子棋是两个人之间进行的竞技活动,由于对黑方白方规则不同,黑棋必须先行(本章节设计的游戏,黑棋与白棋的规则一样,但一样由黑棋先下)。
(2)五子棋专用盘为 15×15 ,五连子的方向为横、竖、斜。
(3)在棋盘上以对局双方均不可能形成五连为和棋。
(4)首先形成五连子的一方为赢。
1.1.2 输入输出约定
玩家必须以(x,y)的方式输入棋盘的坐标,其中,x 代表棋坐标,y 代表竖坐标。x 与 y 的值必须是 1 到 N(棋盘的大小)的正数。
系统询问玩家是否继续游戏时,玩家输入 y 是代表继续,输入其它则代表退出游戏。
“●”代表黑子,“○”代表白子。当玩家以(x,y)的形式输入下棋的坐标后,游戏中就可以根据玩家所下的坐标,再去将棋子放置到棋盘中。我们可以将棋盘看作一个二维数组,填充着棋盘式的标志(“十”),玩家下棋后,将棋子替换原来的标志,最后再执行输入。由于本章是在控制台中进行打印,因此只需要使用 System.out.println 来进行打印即可,如果需要实现有界面的五子棋游戏,例如使用swing 或者 awt,可以使用相应的方法,将二维数组“画”到界面中。因此,不管是使用 swing、awt或者其他界面技术,五子棋的实现原理几乎大同小异。
1.2 了解游戏流程描述
在开发五子棋之前,我们先了解一下游戏的整个游戏流程,了解游戏的流程,有助于我们在开发的过程中可以清晰的掌握程序结构,对于实现功能有莫大的帮助,五子棋的具体流程如图 1.1 所示。
1.2.1 玩家输入坐标
游戏开始,系统在控制台中打印出棋盘,玩家根据这个棋盘,选定下棋的位置坐标后,在控制台中输入相应的坐标,系统读取玩家所输入的坐标并进行相应的分析,如果玩家所下的棋使得玩家游戏胜利,则系统询问是否继续游戏。
系统读取了玩家输入的坐标后,除了判断游戏是否胜利外,还需要判断玩家输入的坐标中是否已经存在了相应的棋子,如果存在的话,需要再次提示玩家,重新输入。
1.2.2 “电脑”下棋
玩家输入了坐标,系统判断玩家没有游戏胜利后,就应该轮到“电脑”下棋,在本章的开头中我们已经讲到,本章可以实现一个简单的电脑来进行游戏,只需要随便的产生棋盘坐标,就可以让“电脑”在相应的坐标中下棋。如果电脑随机产生的坐标中已经存在棋子,那么我们可以重新随机产生坐标,直到产生的坐标上没有存在棋子为止。当“电脑”下完棋后,就可以使用同样的判断方式(判断是否五子相连)来判断“电脑”所下的棋子是否已经使得游戏胜利,如果游戏胜利,同样地去提示玩家,电脑已经胜利了。
在本章我们并不需要实现强大的人工智能“电脑”,只需要简单的随机产生坐标即可。
1.3 创建游戏的各个对象
这里设计三个类来完成游戏的功能,棋盘类(Chessboard),游戏类(GobangGame)与棋子类(Chessman) (枚举类),类的关系如图1.2 所示,从图中可以看出,Chessboard 依赖于 GobangGame,
gobangGame 的改变,会影响到 Chessboard 状态的改变,而Chessman 与 GobangGame 是一个聚合关系。下面一一介绍。
1.3.1 Chessboard类
这个类包含以下方法:
(1)void initBoard(),这个方法用于初始化棋盘,开始新的游戏时,应该调用此方法,初始化出一个新的空棋盘。
(2)void printBoard(),此方法用于在控制台输出棋盘,各方每一完一颗棋子后,由于棋盘上棋子的状态有改变,所以必须调用此方法重新输入棋盘。
(3)void setBoard( int posX , int posY , String chessman ),posX 与 posY 是新下棋子的 x 与 y 坐标,,chessman 是新下棋子的类型(黑子与白子),每下完一颗棋子后,通过调用此方法把棋子设置到棋盘上。
(4)String[][] getBoard(),返回棋盘,返回类型是保存棋盘的二维数组。
1.3.2 Chessman类
Chessman 类是一个枚举类,此类是构造器私有的,不能直接创建,里面有 BLACK 与 WHITE 两个静态属性,代表黑子与白子枚举类,两个表态属性都是 Chessman 类型的,要获取棋子,则通过这两个属性调用以下的方法获取棋子:
String getChessman(),返回 String 类型的棋子实例,“●”或者“○”。
1.3.3 GobangGame类
主要包含以下构造器与方法:
(1)GobangGame(),默认无参数构造器。
(2)GobangGame( Chessboard chessboard ),有参数构造器,以一个 Chessboard 实例去初始化这个类。
(3)boolean isValid( String inputStr ),此方法验证控制台的输入字符串是否合法,如果合法,返回true,如果不合法,则返回 false,此方法抛出 Exception 异常。
(4)void start(),开始游戏。此方法抛出 Exception 异常。
(5)boolean isReplay( String chessman ),是否重新开始游戏,如果是,返回 true,否则返回 false,参数 chessman 代表黑子或白子。
(6)int[] computerDo(),计算机随机下棋,由计算机自动设置棋盘,并返回包含新下棋子位置 x 与y 坐标的 int[]数组类型。
(7)boolean isWon( int posX , int posY , String ico ),判断输赢,参数 posX 与 posY 代表新下棋子的 x 与 y 坐标,ico 代表新下的棋子类型,如果赢了,返回 true,否则返回 false。
1.4 棋盘类实现
在此类中,主要是用一个 String[][]类型的二维数组 board 去保存棋盘,board [i][j]代表棋盘的某个位置(i 代表 x 坐标,j 代表 y 坐标),如果此位置没有棋子,默认值为“十”,如果有棋子,board[i][j]的值为“●”或者“○”。用一个不可改变的常量 BOARD_SIZE来表示棋盘的大小,所以保存这个棋盘的是一个BOARD_SIZE*BOARD_SIZE 的二维数组。图 1.3 描述了为什么需要使用一个二维数组来代表一个棋盘,如果把棋盘的一列当做一个数组,那么 N 列的棋盘就是一个二维数组,用数组能很好的存储与表现这个棋盘。
1.4.1 初始化棋盘
public void initBoard() {
//初始化棋盘数组
board = new String[BOARD_SIZE][BOARD_SIZE];
//把每个元素赋值为“十”,用于控制台输出棋盘
for( int i = 0 ; i < BOARD_SIZE ; i++ ) {
for( int j = 0 ; j < BOARD_SIZE ; j++ ) {
board[i][j] = "十";
}
}
}
1.4.2 输出棋盘
public void printBoard() {
//打印每个数组元素
for( int i = 0 ; i < BOARD_SIZE ; i++ ) {
for( int j = 0 ; j < BOARD_SIZE ; j++ ) {
//打印后不换行
System.out.print( board[i][j] );
}
//每打印完一行数组元素就换行一次
System.out.print("\n");
}
}
1.4.3 获取棋盘
/**
* 返回棋盘
* @return 返回棋盘
*/
public String[][] getBoard() {
return this.board;
}
1.5 棋子枚举类实现
public enum Chessman {
BLACK(" ●"),WHITE(" ○");
private String chessman;
/**
* 私有构造器
*/
private Chessman(String chessman) {
this.chessman = chessman;
}
/**
* @return 黑棋或者白棋
*/
public String getChessman() {
return this.chessman;
}
}
BLACK(” ●”),WHITE(” ○”);这行代码相当于:
public static final Chessman BLACK = new Chessman(“●”);
public static final Chessman WHITE = new Chessman(“○”);
1.6 游戏类实现
本章中的游戏类是 GogangGame,在该类中,主要控制游戏的开始,重新开始与结束,验证玩家输入的合法性,判断游戏的输与赢,调用棋盘类来初始化棋盘,打印棋盘,使用棋子类去设置棋盘等。此类中有四个属性,两个 int 类型的 posX 与 poxY,用来存储玩家现在输入的 x 与 y 坐标(x 和 y 坐标是指玩家输入的数字对应棋盘数组中的一维值与二维值),一个默认值为5的int类型常量WIN_COUNT,游戏胜利需要连接的棋子达到的连子数目,由于是五子棋,因此只需要 5 个棋子相连,游戏就胜利。还有一个 Chessboard 类型的变量 chessboard,用来表示棋盘,游戏中就只用到一个棋盘,该对象可以使用初始化棋盘、打印棋盘、获得棋盘(数组)等方法。
1.6.1 使用BufferedReader获取键盘输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inputStr = null;
//br.readLine:每当键盘输入一行内容按回车键,则输入的内容被 br 读取到
while( (inputStr = br.readLine()) != null ) {
/**
* 处理键盘输入
*/
}
BufferedReader 中有一个 readLine()方法,此方法总是读取下一行的输入字符串,如果没有下一行,则返回null。当得到玩家输入的字符后,我们可以进这些字符进行验证,验证完后,如果字符串符合系统要求,可以在验证处使用continue跳出本次循环。
如果需要读取输入,我们就需要为这些输入作出不同的判断,例如,玩家输入了 y(继续游戏),那么我们就需要判断玩家输入了 y 后程序所需要执行哪些操作,因此,这样会为 while 循环体中增加许多的 if 语句,这些 if 语句会影响程序的可读性,如果需要将这些 if 语句去掉,我们可以将每个 if 中的代码抽取出来,作为具体的一个处理类。这样做不仅减少 while 循环体中的代码,而且可以使得程序更加清晰,程序的耦合度更低,while 循环体中只负责读取玩家输入的字符串,而具体的处理则不必由该方法来执行。由于本章中的代码与动作相对较少,因此并不涉及如何实现以上所说的处理模式。
1.6.2 验证玩家输入字符串的合法性
//将用户输入的字符串以逗号(,)作为分隔,分隔成两个字符串
String[] posStrArr = inputStr.split(",");
try {
posX = Integer.parseInt( posStrArr[0] ) - 1;
posY = Integer.parseInt( posStrArr[1] ) - 1;
} catch (NumberFormatException e) {
chessboard.printBoard();
System.out.println("请以(数字,数字)的格式输入:");
return false;
}
//检查输入数值是否在范围之内
if( posX < 0 || posX >= Chessboard.BOARD_SIZE || posY < 0
|| posY >= Chessboard.BOARD_SIZE ) {
chessboard.printBoard();
System.out.println( "X 与 Y 坐标只能大于等于 1,与小于等于"
+ Chessboard.BOARD_SIZE + ",请重新输入:" );
return false;
}
//检查输入的位置是否已经有棋子
String[][] board = chessboard.getBoard();
if( board[posX][posY] != "十" ) {
chessboard.printBoard();
System.out.println( "此位置已经有棋子,请重新输入:" );
return false;
}
1.6.3 判断输赢
判断游戏输赢,需要在玩家输入了坐标并通过了合法性验证后(输入的坐标),再执行输赢的验证,同样地,如果是“电脑”随机生成的坐标,我们同样的需要进行输赢验证,因此,我们已经将判断输赢的行为,独立成一个 isWon 方法。
判断输赢在本章的程序中稍微复杂,有两种方法来判断输赢:
(1)每次下完一颗棋子,就通过程序从横、竖、斜各个方向扫描棋盘,如果在某个方向中,有同种颜色的棋子达到五连子,则此颜色的玩家为赢。如果没有相同颜色的棋子达到五连子,则继续游戏。该判断方法需要遍历整个棋盘,也就是意味着每次下棋后(玩家或者“电脑”)都需要对棋盘进行遍历,这样对程序的性能会造成一定的影响。
(2)每次下完一颗棋子,以该棋子为中心,扫描在此棋子所在范围内的横、竖、斜方向,验证加上此棋子有没有形成五连子,如果形成五连子,则下棋子的玩家为赢。此方法与前面的方法比较,因为不需要扫描整个棋盘,所以更加快速,本章程序使用的是此方法,该方法的原理如图 1.6所示。
在图 1.6 中可以看出,(0,0),(0,3),(0,6),(3,0),(6,0),(3,7),(7,3),(7,7)这些坐标都是此黑棋能形成五连子的最小或者最大位置的棋子,如果各个方向有足够的空间,就延伸到第五颗棋子,如果没有,就只延伸到边界。所以,只要能计算出任意一颗棋子的这些位置,我们就可以判断游戏的输赢,并且是以该棋子为中心向周围进行遍历。以下是判断输赢的代码实现。
//直线起点的横,纵坐标
int startX=0;
int startY=0;
//直线终点的横,纵坐标
int endX=chessboard.BOARD_SIZE-1;
int endY=chessboard.BOARD_SIZE-1;
//同一条直线上相同棋子累积数
int sameCount=0;
int temp=0;
//计算起点的最小X坐标和Y坐标
temp=posXXX-WIN_COUNT+1;
startX=temp<0?0:temp;
temp=posYYY-WIN_COUNT+1;
startY=temp<0?0:temp;
//计算终点的最大X和Y坐标
temp=posXXX+WIN_COUNT-1;
endX=temp>chessboard.BOARD_SIZE-1?chessboard.BOARD_SIZE-1:temp;
temp=posYYY+WIN_COUNT-1;
endY=temp>chessboard.BOARD_SIZE-1?chessboard.BOARD_SIZE-1:temp;
//横向判断
for(int i=startY;i<=endY;i++)
{
if(chessboard.board[posXXX][i]==chessboard.board[posXXX][posYYY])
{
sameCount++;
if(sameCount==WIN_COUNT) return true;
}
else
{
sameCount=0;
}
}
sameCount=0;
//纵向判断
for(int j=startX;j<=endX;j++)
{
if(chessboard.board[j][posYYY]==chessboard.board[posXXX][posYYY])
{
sameCount++;
if(sameCount==WIN_COUNT) return true;
}
else
{
sameCount=0;
}
}
sameCount=0;
//主斜向判断
for(int i=posXXX,j=posYYY;i>startX && j>startY;i--,j--)
{
if(chessboard.board[i-1][j-1]==chessboard.board[i][j])
{
sameCount++;
if(sameCount==WIN_COUNT-1) return true;
}
else break;
}
for(int i=posXXX,j=posYYY;i<endX && j<endY;i++,j++)
{
if(chessboard.board[i+1][j+1]==chessboard.board[i][j])
{
sameCount++;
if(sameCount==WIN_COUNT-1) return true;
}
else break;
}
if(sameCount==WIN_COUNT-1) return true;
else sameCount=0;
//逆斜向判断
for(int i=posXXX,j=posYYY;i>startX && j<endY;i--,j++)
{
if(chessboard.board[i-1][j+1]==chessboard.board[i][j])
{
sameCount++;
if(sameCount==WIN_COUNT-1) return true;
}
else break;
}
for(int i=posXXX,j=posYYY;i<endX && j>startX;i++,j--)
{
if(chessboard.board[i+1][j-1]==chessboard.board[i][j])
{
sameCount++;
if(sameCount==WIN_COUNT-1) return true;
}
else break;
}
if(sameCount==WIN_COUNT-1) return true;
else{
sameCount=0;
return false;
}
}
1.6.4 计算机随机下棋
public void computerDo()
{
int posXX=(int)(Math.random()*(chessboard.BOARD_SIZE-1));
int posYY=(int)(Math.random()*(chessboard.BOARD_SIZE-1));
while(chessboard.board[posXX][posYY]!="✚")
{
posXX=(int)(Math.random()*(chessboard.BOARD_SIZE-1));
posYY=(int)(Math.random()*(chessboard.BOARD_SIZE-1));
}
}
1.6.5 是否重新游戏
/**
* 是否重新开始下棋。
* @param chessman "●"为用户,"○"为计算机。
* @return 开始返回 true,反则返回 false。
*/
public boolean isReplay( String chessman )
throws Exception {
chessboard.printBoard();
String message = chessman.equals(Chessman.BLACK.getChessman())
? "恭喜您,您赢了," : "很遗憾,您输了,";
System.out.println( message + "再下一局?(y/n)" );
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
if( br.readLine().equals("y") ) {
//开始新一局
return true;
}
return false;
}
1.6.6 游戏过程实现
(1)首先调用 Chessboard 类型的 chessboard 属性中的 initBoard()与 printBoard()方法去初始化与打印棋盘。
(2)从控制台获取用户的输入。
(3)再调用本类的 isValid()方法去验证玩家输入的合法性,如果输入不合法,返回第 2 步继续,否则到第 4 步。
(4)把玩家下的棋子位置赋值为”●”。
(5)调用 isWon( int posX , int posY , String chessman )判断玩家是否赢了。如果玩家赢了,则调用 isReply()方法输出的信息询问玩家是否重新游戏,如果玩家输入 y,则返回第 1 步重新开始。
(6)调用 computerDo()方法随机生成计算机的 x,y 坐标,并把 board[x][y] 赋值为”○”。如果计算机赢了,则调用 isReply()方法输出的信息询问玩家是否重新游戏,如果玩家输入 y,则返回第 1 步重新开始,否则返回第 2 步轮到用户输入。
boolean isOver=false;
GobangGame gb=new GobangGame();
//输出棋盘
gb.chessboard.initBoard();
gb.chessboard.printBoard();
//输入下棋坐标
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
while((gb.inputStr=br.readLine())!=null)
{
isOver=false;
//判断输入字符是否合法
if(!gb.isValid()){
//如果不合法,要求重新输入,再继续
continue;
}
//把对应数组元素赋为"●"
String chessman=Chessman.BLACK.getChessman();
gb.chessboard.setBoard(gb.posX,gb.posY,chessman);
//判断是否赢了
if(gb.isWon(gb.posX,gb.posY,chessman)){
isOver=true;
}else{
gb.computerDo();
chessman=Chessman.WHITE.getChessman();
gb.chessboard.setBoard(gb.posXX,gb.posYY,chessman);
//判断计算机是否赢了
if(gb.isWon(gb.posXX,gb.posYY,chessman)){
isOver=true;
}
}
//如果产生胜者,询问用户是否继续游戏
if( isOver ){
//如果继续,重新初始化棋盘,继续游戏
if( gb.isReplay( chessman ) ) {
gb.chessboard.initBoard();
gb.chessboard.printBoard();
continue;
}
//如果不继续,退出程序
break;
}
gb.chessboard.printBoard();
System.out.println("请输入您下棋的坐标,应以x,y的格式:");
}
}
完整代码如下:
棋盘类代码:
package Gogame;
public class Chessboard
{
final int BOARD_SIZE=15;
String[][] board=new String[BOARD_SIZE][BOARD_SIZE];
public void initBoard()
{
//初始化棋盘
for(int i=0;i<BOARD_SIZE;i++)
{
for(int j=0;j<BOARD_SIZE;j++)
{
board[i][j]="✚";
}
}
}
public void printBoard()
{
//打印每个数组元素
for(int i=0;i<BOARD_SIZE;i++)
{
for(int j=0;j<BOARD_SIZE;j++)
{
System.out.print(board[i][j]);
}
System.out.print("\n");
}
}
public void setBoard(int x,int y,String s)
{
board[x][y]=s;
}
/**
* @return 返回棋盘
*/
public String[][] getBoard()
{
return this.board;
}
}
棋子类代码:
package Gogame;
public enum Chessman
{
BLACK("●"),WHITE("○");
private String chessman;
private Chessman(String chessman)
{
this.chessman=chessman;
}
/**
* @return 黑棋或白棋
*/
public String getChessman()
{
return this.chessman;
}
}
游戏类代码:
package Gogame;
import java.io.*;
import java.lang.Math;
public class GobangGame {
final int WIN_COUNT=5;
//人下棋的坐标
int posX=0;
int posY=0;
//电脑下棋的坐标
int posXX=0;
int posYY=0;
String inputStr=null;
Chessboard chessboard=new Chessboard();
/*
* 判断输入字符是否合法
*/
public boolean isValid(){
//判断输入的字符是否为数字
String [] posStrArr=inputStr.split(",");
try{
posX=Integer.parseInt(posStrArr[0])-1;
posY=Integer.parseInt(posStrArr[1])-1;
}
catch(NumberFormatException e){
System.out.println("请输入坐标(数字,数字)形式:");
return false;
}
// 判断输入的字符是否超出范围
if(posX<0 || posX>=chessboard.BOARD_SIZE || posY<0 || posY>chessboard.BOARD_SIZE){
System.out.println("输入的数字不小于1,不超过15,请重新输入数字:");
return false;
}
//判断输入的位置是否有棋子
if(chessboard.board[posX][posY]!="✚"){
System.out.println("该位置已经有棋子,请重新输入:");
return false;
}
return true;
}
/*
*判断输赢
*/
public boolean isWon(int posXXX,int posYYY,String ch){
//直线起点的横,纵坐标
int startX=0;
int startY=0;
//直线终点的横,纵坐标
int endX=chessboard.BOARD_SIZE-1;
int endY=chessboard.BOARD_SIZE-1;
//同一条直线上相同棋子累积数
int sameCount=0;
int temp=0;
//计算起点的最小X坐标和Y坐标
temp=posXXX-WIN_COUNT+1;
startX=temp<0?0:temp;
temp=posYYY-WIN_COUNT+1;
startY=temp<0?0:temp;
//计算终点的最大X和Y坐标
temp=posXXX+WIN_COUNT-1;
endX=temp>chessboard.BOARD_SIZE-1?chessboard.BOARD_SIZE-1:temp;
temp=posYYY+WIN_COUNT-1;
endY=temp>chessboard.BOARD_SIZE-1?chessboard.BOARD_SIZE-1:temp;
//横向判断
for(int i=startY;i<=endY;i++)
{
if(chessboard.board[posXXX][i]==ch)
{
sameCount++;
if(sameCount==WIN_COUNT) return true;
}
else
{
sameCount=0;
}
}
sameCount=0;
//纵向判断
for(int j=startX;j<=endX;j++)
{
if(chessboard.board[j][posYYY]==ch)
{
sameCount++;
if(sameCount==WIN_COUNT) return true;
}
else
{
sameCount=0;
}
}
sameCount=0;
//主斜向判断
for(int i=posXXX,j=posYYY;i>startX && j>startY;i--,j--)
{
if(chessboard.board[i-1][j-1]==chessboard.board[i][j])
{
sameCount++;
if(sameCount==WIN_COUNT-1) return true;
}
else break;
}
for(int i=posXXX,j=posYYY;i<endX && j<endY;i++,j++)
{
if(chessboard.board[i+1][j+1]==chessboard.board[i][j])
{
sameCount++;
if(sameCount==WIN_COUNT-1) return true;
}
else break;
}
if(sameCount==WIN_COUNT-1) return true;
else sameCount=0;
//逆斜向判断
for(int i=posXXX,j=posYYY;i>startX && j<endY;i--,j++)
{
if(chessboard.board[i-1][j+1]==chessboard.board[i][j])
{
sameCount++;
if(sameCount==WIN_COUNT-1) return true;
}
else break;
}
for(int i=posXXX,j=posYYY;i<endX && j>startX;i++,j--)
{
if(chessboard.board[i+1][j-1]==chessboard.board[i][j])
{
sameCount++;
if(sameCount==WIN_COUNT-1) return true;
}
else break;
}
if(sameCount==WIN_COUNT-1) return true;
else{
sameCount=0;
return false;
}
}
/*
* 是否重新游戏
*/
public boolean isReplay(String chessman) throws Exception{
chessboard.printBoard();
String message=chessman.equals(Chessman.BLACK.getChessman())?"恭喜您,您赢了!":"很遗憾,您输了!";
System.out.println(message+"下一局?(y/n)");
BufferedReader cr=new BufferedReader(new InputStreamReader(System.in));
if(cr.readLine().equals("y")) return true;
else return false;
}
/**
* 电脑随机下棋
*/
public void computerDo()
{
posXX=(int)(Math.random()*(chessboard.BOARD_SIZE-1));
posYY=(int)(Math.random()*(chessboard.BOARD_SIZE-1));
while(chessboard.board[posXX][posYY]!="✚")
{
posXX=(int)(Math.random()*(chessboard.BOARD_SIZE-1));
posYY=(int)(Math.random()*(chessboard.BOARD_SIZE-1));
}
}
public static void main(String[] args) throws Exception{
boolean isOver=false;
GobangGame gb=new GobangGame();
//输出棋盘
gb.chessboard.initBoard();
gb.chessboard.printBoard();
//输入下棋坐标
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
while((gb.inputStr=br.readLine())!=null)
{
isOver=false;
//判断输入字符是否合法
if(!gb.isValid()){
//如果不合法,要求重新输入,再继续
continue;
}
//把对应数组元素赋为"●"
String chessman=Chessman.BLACK.getChessman();
gb.chessboard.setBoard(gb.posX,gb.posY,chessman);
//判断是否赢了
if(gb.isWon(gb.posX,gb.posY,chessman)){
isOver=true;
}else{
gb.computerDo();
chessman=Chessman.WHITE.getChessman();
gb.chessboard.setBoard(gb.posXX,gb.posYY,chessman);
//判断计算机是否赢了
if(gb.isWon(gb.posXX,gb.posYY,chessman)){
isOver=true;
}
}
//如果产生胜者,询问用户是否继续游戏
if( isOver ){
//如果继续,重新初始化棋盘,继续游戏
if( gb.isReplay( chessman ) ) {
gb.chessboard.initBoard();
gb.chessboard.printBoard();
continue;
}
//如果不继续,退出程序
break;
}
gb.chessboard.printBoard();
System.out.println("请输入您下棋的坐标,应以x,y的格式:");
}
}
}
将三个类放在同一个包Gogame下即是实现控制台五子棋的最终代码。