疯狂java实战演义第1章 控制台五子棋.docx

上传人:b****6 文档编号:7237079 上传时间:2023-01-22 格式:DOCX 页数:19 大小:114.78KB
下载 相关 举报
疯狂java实战演义第1章 控制台五子棋.docx_第1页
第1页 / 共19页
疯狂java实战演义第1章 控制台五子棋.docx_第2页
第2页 / 共19页
疯狂java实战演义第1章 控制台五子棋.docx_第3页
第3页 / 共19页
疯狂java实战演义第1章 控制台五子棋.docx_第4页
第4页 / 共19页
疯狂java实战演义第1章 控制台五子棋.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

疯狂java实战演义第1章 控制台五子棋.docx

《疯狂java实战演义第1章 控制台五子棋.docx》由会员分享,可在线阅读,更多相关《疯狂java实战演义第1章 控制台五子棋.docx(19页珍藏版)》请在冰豆网上搜索。

疯狂java实战演义第1章 控制台五子棋.docx

疯狂java实战演义第1章控制台五子棋

第1章控制台五子棋

1.1引言

控制台五子棋,顾名思义,就是在Java控制台运行的五子棋游戏,需要用户用键盘输入棋子的位置来进行游戏。

由于是在控制台下面运行的程序,所以并没有漂亮的游戏界面,与及鼠标操作等东西,只是在一片黑色控制台环境下进行游戏,游戏的可玩性并不高,似乎这并不是一个完整的游戏。

虽然如此,但事实上,一个程序最重要的并不是界面,而是处理各种业务逻辑与数据的方法,只要掌握了核心的方法,掌握基础的知识,便更容易学习awt,swing等图形用户界面的编写,万变不离其宗,写起有操作界面的程序也会变得更加容易,更加随心应手。

而本章的主要目的让读者掌握与理解Java编程的基础知识,因此,掌握本章五子棋的实现原理,对于学习以后的章节将会非常有帮助。

作为本书的第一章内容,我们在本章中将使用最简单的方式来实现一个控制台五子棋游戏。

1.1.1五子棋介绍

五子棋是起源于中国古代的传统黑白棋种之一。

现代五子棋日文称之为“连珠”,英译为”Renju”,英文称之为”Gobang”或”FIR”(FiveinaRow的缩写),亦有“连五子”、“五子连”、“串珠”、“五目”、“五目碰”、“五格”等多种称谓。

五子棋游戏是一个比较大众的棋类游戏,大多数人都会玩这个游戏,五子棋的玩法与规则如下:

❑五子棋是两个人之间进行的竞技活动,由于对黑方白方规则不同,黑棋必须先行(本章节设计的游戏,黑棋与白棋的规则一样,但一样由黑棋先下)。

❑五子棋专用盘为15×15,五连子的方向为横、竖、斜。

❑在棋盘上以对局双方均不可能形成五连为和棋。

❑首先形成五连子的一方为赢。

五子棋必须由双方进行游戏,当某一方按照一定规则连成五个棋子的时候,该游戏方就胜利,在本章中,我们并不需要做到对战形式的,我们可以设计一个简单的“电脑”来做我们的对手,当我们下完棋后,这个简单的“电脑”就随便在棋盘中下一个棋,当然,如果想做更强大的“电脑”我们可以编写程序来实现,当我们下棋的时候,这个“电脑”就对我们所下的棋子进行检测,并将棋子下到最恰当的位置。

本章主要目的是展现五子棋的实现原理,如果读者有兴趣,可以自行开发强大的“人工智能电脑”来进行游戏。

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.1五子棋游戏流程

1.2.1玩家输入坐标

游戏开始,系统在控制台中打印出棋盘,玩家根据这个棋盘,选定下棋的位置坐标后,在控制台中输入相应的坐标,系统读取玩家所输入的坐标并进行相应的分析,如果玩家所下的棋使得玩家游戏胜利,则系统询问是否继续游戏。

系统读取了玩家输入的坐标后,除了判断游戏是否胜利外,还需要判断玩家输入的坐标中是否已经存在了相应的棋子,如果存在的话,需要再次提示玩家,重新输入。

1.2.2“电脑”下棋

玩家输入了坐标,系统判断玩家没有游戏胜利后,就应该轮到“电脑”下棋,在本章的开头中我们已经讲到,本章可以实现一个简单的电脑来进行游戏,只需要随便的产生棋盘坐标,就可以让“电脑”在相应的坐标中下棋。

如果电脑随机产生的坐标中已经存在棋子,那么我们可以重新随机产生坐标,直到产生的坐标上没有存在棋子为止。

当“电脑”下完棋后,就可以使用同样的判断方式(判断是否五子相连)来判断“电脑”所下的棋子是否已经使得游戏胜利,如果游戏胜利,同样地去提示玩家,电脑已经胜利了。

在本章我们并不需要实现强大的人工智能“电脑”,只需要简单的随机产生坐标即可。

1.3创建游戏的各个对象

这里设计三个类来完成游戏的功能,棋盘类(Chessboard),游戏类(GobangGame)与棋子类(Chessman)(枚举类),类的关系如图1.2所示,从图中可以看出,Chessboard依赖于GobangGame,gobangGame的改变,会影响到Chessboard状态的改变,而Chessman与GobangGame是一个聚合关系。

下面一一介绍。

图1.2五子棋类图

1.3.1Chessboard类

要进行五子棋游戏,必须有有一个棋盘,而这个类主要控制棋盘的初始化,输出与及增加新的棋子。

这个类包含以下方法:

❑voidinitBoard(),这个方法用于初始化棋盘,开始新的游戏时,应该调用此方法,初始化出一个新的空棋盘。

❑voidprintBoard(),此方法用于在控制台输出棋盘,各方每一完一颗棋子后,由于棋盘上棋子的状态有改变,所以必须调用此方法重新输入棋盘。

❑voidsetBoard(intposX,intposY,Stringchessman),posX与posY是新下棋子的x与y坐标,,chessman是新下棋子的类型(黑子与白子),每下完一颗棋子后,通过调用此方法把棋子设置到棋盘上。

❑String[][]getBoard(),返回棋盘,返回类型是保存棋盘的二维数组。

当我们需要初始化棋盘的时候,可以直接调用Chessboard的initBoard方法,我们需要考虑该方法需要实现的功能:

初始化棋盘。

由于我们将棋盘看作是一个二维数组,因此initBoard就需要帮我们去创建一个二维数组,创建二维数组可以使用以下代码。

代码清单:

code\gobang\src\org\crazyit\gobang\Chessboard.java

Object[][]array=newObject[size][size];

for(inti=0;i

for(intj=0;j

array[i][j]=newObject();

}

}

以上代码创建一个固定大小(一维与二维大小)的二维数组,再通过嵌套循环为数组中的每一个元素进行赋值。

在游戏中如果我们进行了下棋的操作,可以直接改变这个数组的某一个元素值。

在创建Chessboard类时,我们就需要发挥面向对象的思维,在我们的程序中,所有看到的或者想的事物,我们都可以将其抽象成具体的某个对象,并赋予一定的属性与行为。

在设计对象的过程中,如果有某些事物拿捏不准,不知如何设计属性或者行为,可以将其设计成接口或者抽象类。

Chessboard中提供了一个printBoard的方法用于打印棋盘,在本章中,我们就需要将棋盘数组打印到控制台中,因此该方法可以简单的调用System.out.print去打印相关的字符串。

需要注意的是,由于printBoard方法是没有参数的,因此我们需要为Chessboard提供一个二维数组变量,当调用printBoard方法的时候,将对象内的二维数组打印,我们可以将Chessboard看作一个有状态的Java对象,有状态的Java对象可以理解成一个Java对象保存一些与该对象相关的状态属性,如果该对象没有保存与该对象相关的状态属性,那么我们可以将这个对象看成一个无状态的Java对象。

当外部调用Chessboard的setBoard方法时,就可以将某个值设置到Chessboard中的二维数组里,告诉Chessboard玩家或者“电脑”在某个位置下了怎样的棋子。

1.3.2Chessman类

Chessman类是一个枚举类,此类是构造器私有的,不能直接创建,里面有BLACK与WHITE两个静态属性,代表黑子与白子枚举类,两个表态属性都是Chessman类型的,要获取棋子,则通过这两个属性调用以下的方法获取棋子:

❑StringgetChessman(),返回String类型的棋子实例,“●”或者“○”。

如果我们需要得到棋子的字符串(“●”或者“○”),可以使用以下的代码。

代码清单:

code\gobang\src\org\crazyit\gobang\Chessman.java

Chessman.BLACK.getChessman();

1.3.3GobangGame类

GobangGame类是进行游戏的类,Chessboard依赖于此类,此类控制游戏的开始,重玩与结束,并影响Chessboard类。

主要包含以下构造器与方法:

❑GobangGame(),默认无参数构造器。

❑GobangGame(Chessboardchessboard),有参数构造器,以一个Chessboard实例去初始化这个类。

❑booleanisValid(StringinputStr),此方法验证控制台的输入字符串是否合法,如果合法,返回true,如果不合法,则返回false,此方法抛出Exception异常。

❑voidstart(),开始游戏。

此方法抛出Exception异常。

❑booleanisReplay(Stringchessman),是否重新开始游戏,如果是,返回true,否则返回false,参数chessman代表黑子或白子。

❑int[]computerDo(),计算机随机下棋,由计算机自动设置棋盘,并返回包含新下棋子位置x与y坐标的int[]数组类型。

❑booleanisWon(intposX,intposY,Stringico),判断输赢,参数posX与posY代表新下棋子的x与y坐标,ico代表新下的棋子类型,如果赢了,返回true,否则返回false。

GobangGame是我们五子棋游戏的主体类,游戏里面所有的处理都在该类中实现。

GobangGame中的isValid方法用于验证控制台的输入,玩家主要在控制台输入下棋的坐标,下棋的坐标的字符串形式为:

x,y,我们需要对字符串进行处理得到x和y的值,如果玩家输入的字符串不符合系统要求,则isValid方法返回false,只有当该方法返回true的时候,才会去修改Chessboard的二维数组。

GobangGame中提供了一个start方法,用于游戏的开始,我们需要考虑游戏开始的行为,例如需要初始化棋盘(调用Chessboard的init方法),需要开始从控制台读取玩家的输入信息、打印棋盘,验证控制台输入的信息等,这些功能我们将在下面的章节中加以描述。

当轮到“电脑”下棋的时候,我们需要随机生成电脑的下棋坐标,GobangGame中的computerDo方法用于随机产生坐标。

判断一局游戏是否胜利,可以调用GobangGame的isWon方法,该方法判断游戏是否胜利,是五子棋中最主要的方法,五子棋是否可以相连的所有逻辑,都会在该方法中实现。

isWon方法会在每次下棋后(玩家下棋或者“电脑”下棋)调用。

到此,游戏中的三个对象已经设计完成,这三个对象中已经定义好了各种方法,并在前面章节中详细描述了各个方法的作用,在下面章节中我们将开始对这三个对象所定义的方法进行实现。

当然,如果需要做到更好的程序解耦,我们可以使用一些设计模式,例如将游戏规则写成一个具体的算法,可以使用策略模式,如果需要产生出不同的棋子(将控制台换成其他界面),可以编写棋子工厂等。

但是本章主要目的是展现一个最简单的五子棋,因此本章中并不涉及任何具体的设计模式。

1.4棋盘类实现

在此类中,主要是用一个String[][]类型的二维数组board去保存棋盘,board[i][j]代表棋盘的某个位置(i代表x坐标,j代表y坐标),如果此位置没有棋子,默认值为“十”,如果有棋子,board[i][j]的值为“●”或者“○”。

用一个不可改变的常量BOARD_SIZE来表示棋盘的大小,所以保存这个棋盘的是一个BOARD_SIZE*BOARD_SIZE的二维数组。

图1.3描述了为什么需要使用一个二维数组来代表一个棋盘,如果把棋盘的一列当做一个数组,那么N列的棋盘就是一个二维数组,用数组能很好的存储与表现这个棋盘。

图1.3棋盘与数组的关系

1.4.1初始化棋盘

在1.3节介绍过,此类主要是实现棋盘初始始化、输出、与更新,在这节便用代码一步一步地实现各个功能。

首先我们需要初始化棋盘的实现,看以下代码片段。

代码清单:

code\gobang\src\org\crazyit\gobang\Chessboard.java

publicvoidinitBoard(){

//初始化棋盘数组

board=newString[BOARD_SIZE][BOARD_SIZE];

//把每个元素赋值为“十”,用于控制台输出棋盘

for(inti=0;i

for(intj=0;j

board[i][j]="十";

}

}

}

上面代码中,BOARD_SIZE是代表棋盘的大小,用一个String[][]类型的二维数组来代表棋盘,创建此数组后,通过迭代为为个数组元素的值赋为“十”来初始化棋盘。

创建了棋盘数组后,如果需要定位到棋盘的某个位置,只需要得到棋盘数组的一维值与二维值即可,例如处理玩家下棋动作的时候,可以将数组中具体的某个“十”替换成具体的棋子字符串。

1.4.2输出棋盘

输出棋盘,只需要Chessboard的board属性(二维数组)的每一个值,打印到控制台中。

如果可以做到更好的扩展性,我们可以在二维数组中存放棋子对象,而不是简单的字符串,那么存放在二维数组中的每一个棋子对象,都可以实现某个棋子接口或者继承棋子的抽象类,这样可以更好的做到游戏的扩展性。

当然,我们在本章为了简单起见,只在该二维数组中存放需要打印的字符串,打印时只需要得到具体的某个二维数组的元素,将其打印即可。

代码清单:

code\gobang\src\org\crazyit\gobang\Chessboard.java

publicvoidprintBoard(){

//打印每个数组元素

for(inti=0;i

for(intj=0;j

//打印后不换行

System.out.print(board[i][j]);

}

//每打印完一行数组元素就换行一次

System.out.print("\n");

}

}

棋盘的输出与棋盘的初始化相类似,都是要遍历保存棋盘的数组,只不过是每遍历到一个元素都要输出来,注意到这里的输出方法用的是System.out.print()而不是常用的System.out.println(),这里因为System.out.println()方法是输出后自动换行的,如果使用此方法,便达不到我们需要的效果,棋盘的输出效果如图1.4。

图1.4控制台五子棋的棋盘

打印出来的效果,就好像在控制台中出现了一个棋盘。

1.4.3获取棋盘

在Chessboard中提供了一个getBoard的方法,用于返回本对象的棋盘二维数组,该方法一般在游戏类GobangGame中调用,游戏类得到棋盘的二维数组,可以用于判断棋盘中的某一个位置是否有棋子或者计算游戏是否胜利。

getBoard方法只需要将本对象中的board(二维数组)返回即可,代码如下。

代码清单:

code\gobang\src\org\crazyit\gobang\Chessboard.java

/**

*返回棋盘

*@return返回棋盘

*/

publicString[][]getBoard(){

returnthis.board;

}

到此,棋盘类的几个方法都已经实现,该类的主要功能是创建棋盘、打印棋盘等,实现的过程中涉及了一些Java语言的基本操作,例如嵌套循环、创建二维数组等。

在下面的小节中,我们将去实现游戏的核心部分。

1.5棋子枚举类实现

在某些情况下,一个类的属性是有限而且固定的(在某些情况下),例如本章中的棋子类,它只有两个对象,黑棋和白棋。

这种实例有限而且固定的类,在Java里面称为枚举类,枚举类的关健字用enum而不是class,此类中有两个枚举属性BLACK和WHITE,代表黑子与白子,代码实现如下:

代码清单:

code\gobang\src\org\crazyit\gobang\Chessman.java

publicenumChessman{

BLACK("●"),WHITE("○");

privateStringchessman;

/**

*私有构造器

*/

privateChessman(Stringchessman){

this.chessman=chessman;

}

/**

*@return黑棋或者白棋

*/

publicStringgetChessman(){

returnthis.chessman;

}

}

在上面的代码中,可以看到,枚举类是用enum关键字代替了class关键字,看到此枚举类的构造器的权限修饰符是private,也是表明此类是不可以通过外部创建的,只能在此类的内部创建,这是为了保证此对象只有黑子与白子两种类型。

黑体代码是列出枚举值,实际上就是调用私用构造器创建此对象,等同以下代码:

publicstaticfinalChessmanBLACK=newChessman(“●”);

publicstaticfinalChessmanWHITE=newChessman(“○”);

由于BLACK与WHITE两个属性是静态的,所以要获取黑子或者白子,可以通过以下代码来获得:

Chessman.BLACK.getChessman();

Chessman.WHITE.getChessman();

在控制台中,我们可以使用这种方式来确定棋子的字符串,如果我们需要在swing或者其他界面中展示一个棋子,可能需要为具体的某个棋子保存相应的棋子图片,在本章中,由于棋子只是普通的两个字符串,因此可以直接写成枚举对象即可。

如果你希望你的程能有更好的扩展性,笔者建议可以根据情况建立棋子接口,并提供白棋与黑棋的实现类,我们在棋盘二维数组中存放的只是某个接口,而不是具体的类,这样,提高了程序的可扩展性,在本小节的开头提到:

在某些情况下,一个类中的属性有限并且是固定的。

但是在我们开发的实际情况中(特别是做企业应用),随着业务的不断变化,类的不可变几乎是不可能的。

举个例子,如果需要将本章中的五子棋迁移到swing界面中,那么该棋子枚举类就不得不更改了。

虽然本章是为了做一个较为简单的五子棋,但更多的想向大家展现面向对象的思维。

1.6游戏类实现

本章中的游戏类是GogangGame,在该类中,主要控制游戏的开始,重新开始与结束,验证玩家输入的合法性,判断游戏的输与赢,调用棋盘类来初始化棋盘,打印棋盘,使用棋子类去设置棋盘等。

此类中有四个属性,两个int类型的posX与poxY,用来存储玩家现在输入的x与y坐标(x和y坐标是指玩家输入的数字对应棋盘数组中的一维值与二维值),一个默认值为5的int类型常量WIN_COUNT,游戏胜利需要连接的棋子达到的连子数目,由于是五子棋,因此只需要5个棋子相连,游戏就胜利。

还有一个Chessboard类型的变量chessboard,用来表示棋盘,游戏中就只用到一个棋盘,该对象可以使用初始化棋盘、打印棋盘、获得棋盘(数组)等方法。

1.6.1使用BufferedReader获取键盘输入

BufferedReader是JavaIO流中的一个字符包装流,它必须建立在字符流的基础之上。

该对象可以从输入流中读取文本,但标准输入:

System.in是字节流,所以程序需要使用转换流InputStreamReader将其包装成字符流。

所以程序中用于获取键盘的输入采用以下代码创建。

//获取键盘的输入

BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));

StringinputStr=null;

//br.readLine:

每当键盘输入一行内容按回车键,则输入的内容被br读取到

while((inputStr=br.readLine())!

=null){

/**

*处理键盘输入

*/

}

BufferedReader中有一个readLine()方法,此方法总是读取下一行的输入字符串,如果没有下一行,则返回null。

当得到玩家输入的字符后,我们可以进这些字符进行验证,验证完后,如果字符串符合系统要求,可以在验证处使用continue跳出本次循环。

如果需要读取输入,我们就需要为这些输入作出不同的判断,例如,玩家输入了y(继续游戏),那么我们就需要判断玩家输入了y后程序所需要执行哪些操作,因此,这样会为while循环体中增加许多的if语句,这些if语句会影响程序的可读性,如果需要将这些if语句去掉,我们可以将每个if中的代码抽取出来,作为具体的一个处理类。

这样做不仅减少while循环体中的代码,而且可以使得程序更加清晰,程序的耦合度更低,while循环体中只负责读取玩家输入的字符串,而具体的处理则不必由该方法来执行。

由于本章中的代码与动作相对较少,因此并不涉及如何实现以上所说的处理模式,更深入的可以查看“仿QQ游戏大厅”一章。

1.6.2验证玩家输入字符串的合法性

根据引言中提到的输入约定,玩家在控制台输入的字符串必须是以(x,y)的方式输入,还需要验证输入的字符串是否能转换为数字,是否超越棋盘的边界(小于等于1,大于等于棋盘数组的长度),并且需要判断该位置是否已经存在棋子,具体判断流程如图1.5所示。

图1.5验证流程

首先,x与y必须是一个数字,由以下代码验证。

代码清单:

code\gobang\src\org\crazyit\gobang\GobangGame.java

//将用户输入的字符串以逗号(,)作为分隔,分隔成两个字符串

String[]posStrArr=inputStr.split(",");

try{

posX=Integer.parseInt(posStrArr[0])-1;

posY=Integer.parseInt(posStrArr[1])-1;

}catch(NumberFormatExceptione){

chessboard.printBoard();

Sy

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1