Java小游戏-中国象棋

摘 要

随着互联网的发展,人们的娱乐生活变得多种多样。许多从前的,线下的娱乐设备,在电脑中也可进行。中国象棋起源于中国,因其入门相对围棋来说较为简单,故拥有庞大的玩家群体。

对现实游戏在计算机里的复刻,为人们生活里的游玩提供便利,同时,也可考验制作者的制作水瓶,可谓一举两得。信息时代的到来,对于各个行业的要求也提出了新的标准,因此人们的娱乐也同样需要提高效率。

本文使用JAVA语言,实现了一个基于MySQL数据库的中国象棋游戏。除了象棋最基本的功能——下棋和悔棋,本文还能记录下棋者名称,并记录胜者。值得一提的是,本文能记录对战时每一步的走子,并实现复盘功能。本游戏使用大杂烩设计界面,所有的按键都放在一起,棋盘放在左边,简单明了,便于操作,在一定程度上提高了下棋的效率。

关键词  JAVA  Mysql  中国象棋

第一章 概述

1.1 引言 

中国象棋系统是针对中国象棋玩家游玩而开发的一个游玩程序。中国象棋系统主要是提供中国象棋基本的游玩功能——下棋,悔棋,并进行复盘和记录。现在越来越多的中国象棋玩家,因为不能随身携带棋盘而失去了可以随时下棋的机会,为了不给它们带来这种困扰而设计程序。选择和作为题目的主要原因是因为不想匆匆忙忙的进行课设,所有提前选择了,而对于象棋来说,只要建立坐标,所有的都会变得很简单,比较适合我懒人的性质。从技术上讲,我的中国象棋程序是由JAVA编写的,并结合了MySQL数据库,并实现了复盘功能,对于老师的要求是轻易达到的,并结合了这个学期所学的知识。还有就是用到了许多从未接触过的技术领域,比如对棋盘进行绘画,使界面出现棋盘。

通过该系统,将我的JAVA知识和MySQL数据库知识结合成了一个有机的整体,在下次的使用中会更加熟练,增强了我的自信心和竞争力。

1.2 系统目标

本次设计的中国象棋系统功能齐全,包括下棋,悔棋,记录选手,复盘。

第二章 中国象棋系统需求分析

2.1 系统功能需求

2.1.1 棋盘设计

在JAVA界面设计出按钮,棋盘,等等布局。

2.1.2 走棋规则

重中之重,限制棋子的走棋。

2.1.3 悔棋设计

游玩中可能会点错,需返回上一步。

2.1.4 记录选手

记录选手的名称。一个小功能。

2.1.5 实现复盘

重现对局。

2.2系统的性能要求

因服务器资源有限,故以控制用户数量的手段来保证服务器的稳定。Mysql数据库引擎提供完整的 XML 支持。它还具有构成最大的 Web 站点的数据存储组件所需的可伸缩性、可用性和安全功能。数据库引擎充分保护数据完整性,同时将管理上千并发修改数据库的用户的开销减到最小。因此当网络数据量增大时,系统也可以稳定的运行。

数据库安全方面主要是利用Mysql,自带的各种管理工具,实现对关键数据的保护。

2.3系统配置

2.3.1软件配置

服务器端:安装Java虚拟机,数据库软件Mysql

开发环境:eclipes

开发语言:Java

数据库: Mysql5.0

2.3.2硬件配置

服务器端:Centos6.5,有网络接口卡(NIC),内存应在4GB以上,硬盘在160GB以上。

电脑配置:CPU: Core i5 2.30GHz 内存:DDR3 8GB 硬盘:500GB

操作系统:Microsoft Windows10专业版

客户端:Core i5以上配置的PC机,有网络接口卡(NIC),内存应在4GB以上,硬盘在500GB以上。

电脑配置:CPU: Core i5 2.30GHz 内存:DDR3 8GB 硬盘:500GB

操作系统:Microsoft Windows 7 专业版

2.3.3网络配置

网络:服务器和客户端应有网络连通。配置TCP/IP协议。

2.4系统的未来可能提出的要求

2.5可行性分析

2.5.1 社会可行性

综上所述,此系统开发目标已明确,在技术和经济方面都是都可行。所依此系统的开发是完全可行的。

第三章 中国象棋系统总体设计

3.1 功能设计

系统所实现的功能强弱是衡量一个软件好坏的最直接也是最根本的标准。经过对系统的可行性分析、需求分析、数据分析以及数据库设计后,结合调研的情况,本系统分为走棋功能,悔棋功能,记录功能,复盘功能。

3.2 系统功能设计

3.2.1 走棋功能

点击开始游戏,才能继续进行棋盘上的走棋功能。顺序为红方先走。

3.2.2 悔棋功能

     点击悔棋,可以返回上一步下棋,并转换下棋方。

3.2.3 记录功能

     在数据库服务器上创建名为nn的数据库,共2张表,有一张名为match11,该表记录对局者的名称,当出现胜者时,在下一条记录记录赢家。

3.3 复盘功能

在数据库服务器上创建名为nn的数据库,共2张表,有一张名为replay001,该表记录对局时间,对局顺序,前一步横坐标,前一步纵坐标,前一步坐标信息,后一步横坐标,后一步纵坐标,后一步坐标信息。下面介绍这张数据表。

在replay001中,有8个字段,其中,分别是beforechess0,beforechess1,beforechess2,nowchess0,nowchess1,location,Date,number,分别对应上段中的记录。如下图所示:

beforechess0

beforechess1

beforechess2

nowchess0

nowchess1

location

Date

number

表3.1  replay001的字段

     在这些字段中,beforechess0,beforechess1,beforechess2,nowchess0,nowchess1,location,Date均以char型为字符,仅number以int型为字符。如下a图所示:

类型

长度

小数点

不是null

beforechess0

char

11

0

beforechess1

char

11

0

beforechess2

char

11

0

nowchess0

char

11

0

nowchess1

char

11

0

location

char

11

0

Date

char

255

0

number

int

11

0

表3.2  replay001的表设计

最后就是记录走棋时的数据

第四章 中国象棋详细设计

4.1 开发工具的选用及其介绍

4.2 棋盘设计

首先,先想象对棋盘的布局,我这里是建立一个JFrame类,让棋盘布局为BorderLayout,将主体的棋盘,棋子都放到西边,东边放按钮等等操作键。由于Boderlayout的每个方位只能放一个组件,所以我们又设计了一个JPanel的类,里面放各种按钮等等,然后把这个JPanel类放到东边。

通过提前规划,我们大致确定了需要建立的按钮等等,其中有开始游戏,悔棋,重新开始,记录,开始复盘,上一步,下一步。其中开始游戏,悔棋,重新开始的作用就像它们的字意一样,就是操控下棋时的开始或者悔棋,而记录,是记录了下棋者的名称,并且在他们分出胜负后,记录胜者,开始复盘和上一步,下一步则是连在一起的,在开始复盘时,能让系统获得复盘时的信息,而上一步或者下一步,则可以让这些信息体现在棋盘上。总之,将功能分为了3个模块:下棋前、下棋时、下棋后。

4.3 走棋功能

对中国象棋中所有棋子的走棋规则进行了分析,并得出结论。在代码中模拟其走棋规则,然后进行绘制。操作方法就是,点击棋子即可。但在走子之前,必须得先打开总开关(开始游戏),不然对棋子是无法进行操作的。值得一提的是,对于对将的吃法,在该程序还没进行设计。总共有7个种类的棋子,且分红黑两边,我们一一讲解,为了便于获取坐标,我们事先设计了beforechess数组和nowchess数组,其中beforechess[0]代表落子前的行位置,beforechess[1]代表落子前的列位置,beforechess[2]代表棋的代号;nowchess[0]代表落子后的行位置,nowchess[1]代表落子后的列位置,nowchess[2]代表棋的代号,并且设置flag,令flag等于1时,棋子才能走动。

对于黑将,由于将不能走出田字格,且一次只能走一格的性质,我们得到将的行列后,把将的nowchess[0]控制在0,1,2,nowchess[1]控制在3,4,5。此时有2中情况,第一种是竖走走,即nowchess[1]-beforechess[1]的绝对值等于1,而横坐标之差为0;第二种则是横走,即nowchess[0]-beforechess[0]的绝对值等于1,而竖坐标之差为0。我们通过if语句,在只有这两个情况时,让flag等于1,即将可以走动。

对于红帅,由于帅不能走出田字格,且一次只能走一格的性质,我们得到帅的行列后,把帅的nowchess[0]控制在7,8,9,nowchess[1]控制在3,4,5。此时有2中情况,第一种是竖走走,即nowchess[1]-beforechess[1]的绝对值等于1,而横坐标之差为0;第二种则是横走,即nowchess[0]-beforechess[0]的绝对值等于1,而竖坐标之差为0。我们通过if语句,在只有这两个情况时,让flag等于1,即帅可以走动。

对于黑士,由于士不能走出田字格,且只能斜走的性质,我们得到黑士的行列后,把黑士的nowchess[0]控制在0,1,2,nowchess[1]控制在3,4,5。之后,我们要判断黑士是否走棋符合规则,对黑士的走棋规则做了分析后,我们发现,其nowchess[1]-beforechess[1]的绝对值和nowchess[0]-beforechess[0]的绝对值必须都是1,于是,通过if语句,只有满足上述条件,才让flag等于1,即黑士可以走动。

对于红士,由于士不能走出田字格,且只能斜走的性质,我们得到红士的行列后,把红士的nowchess[0]控制在7,8,9,nowchess[1]控制在3,4,5。之后,我们要判断红士是否走棋符合规则,对红士的走棋规则做了分析后,我们发现,其nowchess[1]-beforechess[1]的绝对值和nowchess[0]-beforechess[0]的绝对值必须都是1,于是,通过if语句,只有满足上述条件,才让flag等于1,即红士可以走动。

对于黑卒,因为卒在过河前不能左右移动,且卒不能后退,我们得到卒的行列后,需判断卒是否过河。在过河前,卒的beforechess[0]在3或者4,在过河后,卒的beforechess[0]大于等于5。在if判断是否过河后,我们要开始判断卒的走法是否符合规则了。在过河前,卒只能前进,且一次只能前进一格,所以nowchess[1]-beforechess[1]的值等于1,而nowchess[0]-beforechess[0]等于0;在过河后,卒可以左右移动,所以分两种情况:前进和左右移动。前进时,与过河前一样,nowchess[1]-beforechess[1]

的值等于1,而nowchess[0]-beforechess[0]等于0;左右移动时,nowchess[1]-beforeche

ss[1]的值等于0,而nowchess[0]-beforechess[0]的绝对值等于1。由if判断后令flag等于1,即黑卒可以走动。

对于红兵,因为兵在过河前不能左右移动,且兵不能后退,我们得到兵的行列后,需判断兵是否过河。在过河前,兵的beforechess[0]在5或者6,在过河后,卒的beforechess[0]小于等于5。在if判断是否过河后,我们要开始判断兵的走法是否符合规则了。在过河前,兵只能前进,且一次只能前进一格,所以nowchess[1]-beforechess[1]的值等于-1,而nowchess[0]-beforechess[0]等于0;在过河后,兵可以左右移动,所以分两种情况:前进和左右移动。前进时,与过河前一样,nowchess[1]-beforechess[1]

的值等于-1,而nowchess[0]-beforechess[0]等于0;左右移动时,nowchess[1]-beforeche

ss[1]的值等于0,而nowchess[0]-beforechess[0]的绝对值等于1。由if判断后令flag等于1,即红兵可以走动。

对于一些可以长距离移动的棋子,比如炮或者车,在移动的路上可能会遇到阻碍,所以我们要设计一个方法findchessnumb()方法,来判断中间有几个子。这个findchessnumb(),以4个int值为输入量,分别代表beforechess[1]、nowchess[1]、beforechess[0]、nowchess[0],然后判断是横移还是竖移。横移时,即beforechess[0]等于nowchess[0],通过运算得出横移了几个格子,然后通过for语句,从beforechess[1]+1开始(排除自己),到nowchess[1]之间的location有几个不等于0,即中间隔了几个棋子。竖移时,即beforechess[1]等于nowchess[1],通过运算得出竖移了几个格子,然后通过for语句,从beforechess[0]+1开始(排除自己),到nowchess[0]之间的location有几个不等于0,即中间隔了几个棋子。

对于黑炮,因为炮只能隔子吃子,在移动时,炮只能上下或者左右横移,所以在移动炮时,要判断炮的落脚点是否有子,以此来判断炮时移动还是吃。对于吃,很简单,只需判断炮的nowchess[2]是否大于10(因为红色方的代号均大于10,空的话为0),如果大于10,则为吃,要判断findchessnumb()的返回值是否为1,不然无法进行。如果nowchess[2]为0,则正常移动,要判断findchessnumb()的返回值是否为0,否则遇到阻碍无法进行。

对于红炮,因为炮只能隔子吃子,在移动时,炮只能上下或者左右横移,所以在移动炮时,要判断炮的落脚点是否有子,以此来判断炮时移动还是吃。对于吃,很简单,只需判断炮的nowchess[2]是否在1到10之间(因为黑色方的代号均在1到10,空的话为0),如果在1到10之间,则为吃,要判断findchessnumb()的返回值是否为1,不然无法进行。如果nowchess[2]为0,则正常移动,要判断findchessnumb()的返回值是否为0,否则遇到阻碍无法进行。

对于车,因为其相对于炮来说,是直上直下的,在吃上也没有这么讲究,所以只用判断它的findchessnumb()是否为0,即可操作下去。前提是得横移或者竖移,而不是斜移。

对于象,它的移动稍微复杂,要判断象脚是否被阻挡,才可走下去。而象是只能斜走2格的,即Math.max(nowchess[1],beforechess[1])-Math.min(nowchess[1], beforechess[1])==2并且Math.max(nowchess[0],beforechess[0])-Math.min(nowchess[0], beforechess[0])==2,所以在if之后,还需判断其是否被挡象脚,即判断location[(nowchess[0]+beforechess[0])/2][(nowchess[1]+beforechess[1])/2]==0。最后,由于象是不能过河的,所以当是黑象时,其nowchess[0]小于等于4,当是红象时,其nowchess[0]大于等于5。

对于马,它的功能更复杂了。经过思考得出,每匹马有四个马脚,而每匹马可以走8个位置,所以在落子前,我们得知道落子后的位置是否被阻挡了马脚。我将马的走法分为了竖走和横走两种,此时马脚也分为了竖马脚和横马脚。落子是竖马脚时,马的beforechess[1]-nowchess[1]的绝对值为1,而只有beforechess[0]和nowchess[0]来判断是哪个马脚。如果是上马脚,则beforechess[0]-nowchess[0]等于2,如果是下马脚,则为-2。在横走时,也是同理。然后就是判断马脚是否被挡住了,直接判断此时马脚的location,判断是否为0,即可知道是否被挡马脚。

4.4 悔棋功能

设计了一个数组record[9999][6],在每次走棋后记录棋的位置,在悔棋时使用该数组进行一系列操作来返回上一次的步骤。其中,record[][0]记录beforechess[0],record[][1]记录beforechess[1],record[][2]记录beforechess[2],record[][3]记录nowchess

[0],record[][4]记录nowchess[1],record[][5]记录nowchess[2]。而record[i][]中的i,则记录第几步。

在记录完之后,我们开始设计悔棋的方法regret()。因为悔棋即是返回上一步,所以我们只用得到上一步时,整个棋盘各个坐标的信息,然后进行重新绘制即可。我们知道,此时与上一步的差别,即是在刚刚下棋的这里,在最新的record中,所以我们将此时最新的record初始化,然后让步数减一,再进行绘制,就可以返回上一步。最后要注意,交换走子权。

4.5 记录棋手

这里连接了MySQL数据库,即在每次对战时,棋手写入自己的名称,并点击记录,此时MySQL将记录棋手的名称,在对局结束后(分出胜负),数据库将记录胜者的名称。

我设计了2个JTextField,一个记录红色方的棋手名称,另一个记录黑色方的棋手名称。在Listener类中,我们通过setJTextField(),把Listener中的JTextField和Chess中的JTextField连接,目的是为了获取Chess中的JTextField的信息。运用getText()方法即可获取信息。

在得到JTextField的信息后,我们要把它记录到数据库。连接数据库的过程不必多说,现在讨论如何记录。经过学习我们知道,往数据表中添加,需要语句:INSERT INTO 表名(字段1,字段2….) VALUES 添加内容。于是我们建立一个String listname,让listname = "('"+ter.getText()+"','"+teb.getText()+"')";再建立一个Statement stmt,让stmt执行executeUpdate()方法即可,即stmt.executeUpdate(sqlStr)。

4.6 实现复盘

复盘是一个较为复杂的功能,对于每次的下棋记录,我们需要一个独立的,不重复的编号,这里我选择了以时间为编号。但是,又要保证时间Date在下一局之前都不能发生变动,所以要求时间的设置的一局中只能设置一次。我这里做了个dateflag来进行判断,即每次开始时,令dateflag等于1,当dateflag=1时,获取当前的时间并记录到nowdate中,然后令dateflag等于0,因为控制dateflag变换的语句是在开始游戏或重新开始中实现的,所以在下一局之前,dateflag都不会发生变化,这保证了这一局中的nowdate一直是一个值。

在实现复盘前,我们要得到数据,所以就有录入数据。因为在实现悔棋时,我们已经建立了一个数组record来记录每一步的信息,所以我们直接把record记录到数据库中即可。和记录选手名称一样,需要语句:INSERT INTO 表名(字段1,字段2….) VALUES 添加内容。

listname = "('"+s1+"','"+s2+"','"+s3+"','"+s4+"','"+s5+"','"+s6+"','"+nowdate+"','"+pedom

eter+"')";

System.out.println(nowdate);

String sqlStr = "INSERT INTO replay001(beforechess0,beforechess1,beforechess2,nowchess0,nowchess1,location,Date,number) VALUES" +listname;

这里pedometer是步数,在下一步解释。然后执行stmt.executeUpdate(sqlStr),这里的s1到s6分别是record[][0]到record[][5]化为String形式的结果。

值得注意的是,由于悔棋时在录入后的进行的,所以悔棋会影响录入的真实情况,所以我们要将在悔棋的同时,把最新的一条记录给删除。为了删除这一步,我们得知道这一步的步是多少步,但是,犹豫我是将所有的对局信息都放在一个表中,步数难免会有所重复,所以删除时,可能会将别的对局的信息给删除,这时,第二特征就尤为特征,这里我选择Date作为我的第二特征,因为Date在不同对局是不同的。然后我们使用语句sqlStr="delete from replay001 where Date='"+nowdate+"' and number="+pedometer,这里pedometer是减1后的,所以刚好对应于需要删除的记录。再执行stmt.executeUpdate(sqlStr),即可删除。

在实现录入数据后,我们即可开始进行复盘。首先,我们得选择复盘何时的对局,这时,就得运用Date的唯一性了。我们建立一个JComboBox,在设计界面时,连接数据库,把所有不同的Date全部添入JComboBox中。这里我做了个数组record[],将所有读取出来的Date记录到record中,如果record[i]不等于record[i-1],则说明是不同的记录,于是将record添加到JComboBox中去。

我在界面放置了开始复盘按钮,是为了在选择完对局后,开始在程序中录入该局的数据库信息。为此,我们需要一个与record[][]一模一样的二维数组,我命名为replaycord[][],把数据库中,beforechess0记录到replaycord[][0]中,beforechess1记录到replaycord[][1]中,beforechess2记录到replaycord[][2]中,nowchess0记录到replaycord[][3]中,nowchess1记录到replaycord[][4]中,location记录到replaycord[][5]中,此时,我们已经记录完数据了只剩使用这些数据了。

在设计界面时,我放置了两个按钮:上一步、下一步。现在,我们要实现它们。在实现下一步,我们知道,下棋实际上是把落子位置棋子的信息用落下的棋子的信息覆盖,于是,我们只用遵循这个规则就行,把location[nowchess[0]][nowchess[1]]用beforechess[2]覆盖,即location[replaycord[zyh][3]][replaycord[zyh][4]]=replaycord[zyh]

[2],然后把前一步的信息用0覆盖,即location[replaycord[zyh][0]][replaycord[zyh][1]] = 0,最后进行重新绘制即可。而上一步的原理,和悔棋无差,只不过,在复盘中不需要交换落子权。即location[replaycord[zyh-1][0]][replaycord[zyh-1][1]]=replaycord[zyh-1][2]和location[replaycord[zyh-1][3]][replaycord[zyh-1][4]] = replaycord

[zyh-1][5]。然后再进行重绘。

程序源码

https://download.csdn.net/download/m0_54570435/87715014

 

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
写一个Java象棋小游戏可以分为以下几个步骤: 1. 定义棋盘:创建一个二维数组来表示棋盘,每个元素代表一个棋子的位置。 2. 定义棋子:创建一个ChessPiece类来表示棋子,包括棋子的类型(如车、马、象等)和位置。 3. 初始化棋盘:将所有的棋子按照规则放置在初始位置上。 4. 实现移动规则:为每个棋子定义移动规则,根据用户输入的起始位置和目标位置判断是否符合规则。 5. 实现游戏逻辑:根据玩家的输入进行移动,并判断游戏是否结束。 下面是一个简单的示例代码,演示如何实现一个基本的Java象棋小游戏: ```java public class ChessGame { private ChessPiece[][] board; public ChessGame() { // 初始化棋盘 board = new ChessPiece[8][8]; // 初始化棋子 // TODO: 根据规则放置棋子 } public void movePiece(int startX, int startY, int targetX, int targetY) { // 判断起始位置是否有棋子 ChessPiece piece = board[startX][startY]; if (piece == null) { System.out.println("起始位置没有棋子!"); return; } // 判断目标位置是否符合移动规则 if (!isValidMove(piece, startX, startY, targetX, targetY)) { System.out.println("非法移动!"); return; } // 移动棋子 board[targetX][targetY] = piece; board[startX][startY] = null; // TODO: 判断游戏是否结束 } private boolean isValidMove(ChessPiece piece, int startX, int startY, int targetX, int targetY) { // TODO: 根据棋子类型判断移动规则是否合法 return true; } // TODO: 实现其他方法 public static void main(String[] args) { ChessGame game = new ChessGame(); game.movePiece(1, 0, 2, 2); // TODO: 进行其他操作 } } ``` 请注意,这只是一个简单的示例,你可以根据自己的需求和规则来扩展和完善代码。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X-MTing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值