中国象棋游戏算法

5.主要算法和实现

5.1核心算法

5.1.1绘制棋盘

 算法伪码

    输入:棋子点2维数组,炮、兵、卒位置坐标。

输出:显示棋盘。

初始化棋子点坐标;

绘制10条横线;//for循环

绘制9条纵线;//for循环

绘制2个九宫格;//2*2共5条斜线;

绘制楚河汉界;//2个字符串;

绘制炮、兵、卒的位置标记;

//中间的6个兵和5个炮,标记需要画8条短直线;其它5个兵、卒都画

5条短直线。

画竖线标记;

// 红方从右到左画中文简体汉字一到九,黑方从右到左画阿拉伯数字1到9。

   程序代码

 Graphics2D g2 = (Graphics2D) g;

// 兵、卒、炮标记笔画

BasicStroke bsFlag = new BasicStroke(2);

// 楚河汉界、棋盘边框笔画

BasicStroke bsLine = new BasicStroke(2);

// 棋盘线笔画

BasicStroke bs1 = new BasicStroke(1);

//绘制直线

drawLines(g2, bsLine, bs1);

//绘制九宫格

drawJiuGongLines(g2, bs1);

//绘制楚河漢界

drawChuheHanjieString(g2);

//绘制炮和兵标记

drawPaoBingFlag(g2, bsFlag);

// 如果有棋子移动,画出2个提示框,每个提示框由8条线组成

drawMoveFlag(g2);

drawWillMoveFlag(g2);  

 5.1.2绘制棋子

      算法伪码

          使用图片标签;

          

      程序代码

public class ChessPiece extends JLabel {

setIcon(PieceUtil.getImageIcon("hongju.png"));

 5.1.3记录棋谱

     算法伪码

第1字是棋子的名称。如“马”或“车”。

第2字是棋子所在纵线的数码。

第3字表示棋子移动的方向:横走用“平”,向前走用“进”或“上”,向后走用“退”或“下”。

第4字是棋子进退的格数,或者到达纵线的数码。

举例 

“炮二平五”,表示红炮从纵线二平移到纵线五。

“马8进7”,表示黑马从纵线8向前走到纵线7。

“车2退3”,表示黑车沿纵线2向后移动3格

当一方有2个以上名称相同的棋子位于同一纵线时,需要用“前”或“后”来加以区别。例如,“前马退六”(表示前面的红马退到直线六)、“后炮平5”(表示后面的黑炮平移到直线5)

   程序代码

int startX = (int) pStart.getX();

int startY = (int) pStart.getY();

int endX = (int) pEnd.getX();

int endY = (int) pEnd.getY();

5.1.4游戏规则  

5.1.4.1棋子移动

算法伪码

输入:移动棋子的起点和终点坐标,棋子点2维数组

输出:棋子能否移动;

移动棋子需要考虑的共同问题

 起点和终点的位置的坐标是否越界

 起点和终点位置的棋子,是否是同一方的;

 棋子移动后,己方是否会被将军

    棋子移动后,将帅是否会对脸

   移动棋子需要考虑的特殊问题

  將(帥)、仕(士)是否走出九宫;

  象是否过河,象眼是否被堵;

馬是否别腿;

炮要翻山吃子;

兵过河前只能前进,过河后可以前进或左右移动;

車的移动规则

     如果起点和终点横坐标相同,2点之间的竖线上没有其它的棋子。

  否则,如果起点和终点纵坐标相同,2点之间的横线上没有其它的棋子。

馬的移动规则:

 水平方向移动2步,垂直方向移动1步;

 水平方向移动1步,垂直方向移动2步。

炮的移动规则

如果起点和终点横坐标相同,2点之间的竖线上没有其它的棋子,或者有且只有1个棋子。

    否则,如果起点和终点纵坐标相同,2点之间的横线上没有其它的棋子或者有且只有1个棋子。

象的移动规则

  起点和终点的横坐标和纵坐标之差都是2.

仕的移动规则

  起点和终点的横坐标和纵坐标之差都是1.

帥的移动规则

  起点和终点的横坐标差1或纵坐标差1.

兵的移动规则

  起点和终点的纵坐标差1;横坐标差1。

public static boolean allRule(ChessPiece piece, int startX,

int startY, int endX, int endY, ChessPoint[][]

chessPoints) {

// 重用車、馬、炮的移动规则

if (category == PieceCategory.JU || category ==

PieceCategory.MA

|| category == PieceCategory.PAO) {

return jmpRule(category, startX, startY, endX,

endY, chessPoints);

}

// 基本打谱、高级打谱共用的帥、仕、兵、相的移动规则

if (category.equals(PieceCategory.SHUAI)

|| category.equals

(PieceCategory.HONGSHI)

|| category.equals(PieceCategory.BING)

|| category.equals

(PieceCategory.HONGXIANG)

|| category.equals(PieceCategory.JIANG)

|| category.equals(PieceCategory.HEISHI)

|| category.equals(PieceCategory.ZU)

|| (category.equals

(PieceCategory.HEIXIANG))) {

return ssxbRule(piece, startX, startY, endX,

endY, chessPoints);

}

5.1.4.2将帅是否对脸检测算法

获得將帥的坐标;

如果移动的棋子是將或帥

將移动,终点和帥之间是否没有棋子。

帥移动,终点和將之间是否没有棋子。

否则,

將和帥之间是否有且只有一个棋子,此棋子是正在移动的棋子。

5.1.4.3己方是否被将军算法

获取己方將帥的位置;

获取对方車馬炮兵的位置;(車馬炮可能有2个,兵可能有5个)

如果車将军,返回true;

    否则,如果馬将军,返回true;

否则,如果炮将军,返回true;

否则,如果兵将军,则返回true。

注:判断一个棋子是否将军,只需要判断一个棋子移动到將的位置,是否符合游戏规则就可以了。

返回false;

   程序代码

public static boolean isDuiLian(ChessPiece piece, int endX, int endY,

ChessPoint[][] chessPoints) ;

 5.2.5走棋算法

       算法伪码

棋手通过鼠标点击来走棋。先单击要走的棋子,然后在目的位置上再单击一次,就实现一步走棋。正规比赛中,棋手拿起棋子,就必须走该棋子,除非该棋子没有合理走法。在这里,没有必要严格执行这条规则。棋手单击本方棋子之后,又再次单击本方另一个棋子,则说明放弃原有的选择,新的棋子为即将走的棋子。

    为了在棋盘上有明显的视觉效果,棋手每次选中己方棋子都要突出显示,发出声音并让棋子闪烁。棋子移动后,移动的起点和终点也突出显示。

如果,第一次点击本方棋子

保存棋子的起点坐标,选中棋子闪烁。

//点击棋盘和对方棋子忽略不计

否则,

点击本方棋子,则更新选中的棋子,更新起点坐标。

点击对方棋子,吃子是否合法,合法则移动。

点击棋盘,移动是否合法,合法则移动。

   程序代码

public void mousePressed(MouseEvent e) ;

5.1.6 棋子闪烁

      算法伪码

算法用途:红方或黑方选中棋子时,选中的棋子应该闪烁,提示用户。

算法描述:

用一个ChessPiece类型的变量 winkPiece保存需要闪烁的棋子,用一个boolean类型的变量needWink标志棋子是否需要闪烁,然后新增一个线程,控制棋子的闪烁。

   程序代码

while (true) {

try {

if (needWink) {//棋子需要闪烁

winkPiece.setVisible(false);//隐藏棋子

Thread.sleep(600);

winkPiece.setVisible(true);//显示棋子

Thread.sleep(600);

} else {//棋子不需要闪烁,则

Thread.sleep(500);

}

} catch (InterruptedException ex) {

break;//退出线程

} catch (Exception e) {

e.printStackTrace();

}

 5.1.7 保存和读取棋谱

算法伪码

     棋谱格式:

  对象格式,二进制流,使用Java序列化机制;

  文本格式,文本字符串,使用文字表示的棋谱

   程序代码

GameRecord gameRecord = owner.getGameRecord();

gameRecord.setDesc(desc);

ArrayList<String> paths = owner.getSavePaths();

boolean flag = ManualUtil.saveManual(paths.get(0) + name

+ EXTENSION_NAME, paths.get(1) + name + ".txt", gameRecord);

5.1.8 逆向解析棋谱

算法伪码

  棋谱生成的逆向解析过程

    解析第一个字

    解析第二个字

    解析第三个字

    解析第四个字

   程序代码

private void movePieceByManual(String manual);

5.2网络通信

   5.2.1 通信协议

public static enum MsgType {

GAME_EXIT, GAME_PAUSE,

GAME_CONTINUE, PIECE_MOVING,

GAME_UNDO, GAME_BACK_YES,

 GAME_BACK_NO, PLAYER_GIVEIN,

 ROOM_MESSAGE, GAME_MESSAGE,

 GROUP_MESSAGE, PLAYER_CREATE_GAME, PLAYER_JOIN_CREATED_GAME, PLAYER_EXIT_CREATED_GAME,  CREATOR_START_CREATED_GAME, PLAYER_LIST, CREATOR_LIST, ADD_PLAYER, SUB_PLAYER, ADD_CREATOR, SUB_CREATOR, PLAYER_LOGIN, CREATOR_AND_MEMBER, CHANGE_ROLE, CHANGE_GAME_STATUS, BYE_BYE

};

房间内的消息

编号

类型

名字

描述

消息内容

001

PLAYER_LOGIN

玩家登录

玩家使用用户名和密码登录到服务器

用户名、密码

002

ROOM_MESSAGE

房间聊天消息

玩家在房间内发表消息

用户ID、消息内容

003

PLAYER_CREATE_GAME

创建游戏

创建一个游戏

用户ID、玩家组ID

004

PLAYER_JOIN_CREATED_GAME

加入游戏

加入一个游戏

用户ID、玩家组ID

005

BYE_BYE

退出房间

退出房间

彻底退出游戏

小组内的消息

编号

类型

名字

描述

消息内容

101

PLAYER_LIST

所有玩家的列表

玩家列表

所有玩家的列表

102

CREATOR_LIST

创建者列表

创建者列表

创建者的列表

103

ADD_PLAYER

增加一个玩家

新增加了一个玩家

玩家ID、新增玩家的信息

105

SUB_PLAYER

减少一个玩家

减少了一个玩家

玩家ID、退出玩家的ID

105

ADD_CREATOR

增加创建者

增加了一个创建者

创建者信息

106

SUB_CREATOR

减少创建者

减少了一个创建者

创建者ID

107

CREATOR_AND_MEMBER

创建者和玩家列表

创建者和该组玩家的列表

该组所有玩家的信息

108

CHANGE_ROLE

改变角色

玩家改变角色

玩家ID、新的角色

109

CHANGE_GAME_STATUS

改变游戏状态

更新游戏的状态

玩家ID、游戏状态

110

GROUP_MESSAGE

组内消息

小组内的消息

玩家组ID、消息详情

111

CREATOR_EXIT_CREATED_GAME

退出游戏

小组内有人退出了游戏

退出游戏的人的ID

112

PLAYER_EXIT_CREATED_GAME

加入者退出某个创建者创建的游戏

加入者退出某个创建者创建的游戏

创建者ID,加入者ID

游戏进行过程中的消息

类型

名字

描述

消息内容

201

GAME_EXIT

玩家退出游戏

观察者、红方、黑方退出了刚刚或正在进行的一场游戏

玩家的ID、玩家的角色

202

CREATOR_START_CREATED_GAME

创建者开始游戏

创建游戏的人开始了游戏

创建者开始游戏

203

GAME_PAUSE

暂停游戏

玩家暂停了游戏

暂停游戏

205

GAME_CONTINU

继续游戏

玩家继续了游戏

205

GAME_UNDO

请求悔棋

玩家请求悔棋

206

GAME_BACK_YES

同意悔棋

玩家同意了对手的悔棋请求

207

GAME_BACK_NO

拒绝悔棋

玩家拒绝了对手的悔棋请求

208

PLAYER_GIVEIN

认输

对方认输

209

PIECE_MOVING

棋子移动

对方移动棋子

210

GAME_QIUHE

求和

玩家求和

211

GAME_MESSAGE

比赛中聊天消息

游戏进行过程中,玩家发表聊天信息

5.2.2消息处理过程

     5.2.2.1房间内消息

PLAYER_LOGIN:客户端发送登录所需的信息,服务器端验证,验证通过则向其它所有玩家发送新玩家的信息。

ROOM_MESSAGE:客户端发送聊天信息到服务器,服务器转发该消息给所有人。

PLAYER_CREATE_GAME:客户端发送创建游戏的消息,服务器端转发该消息给所有人。

PLAYER_JOIN_CREATED_GAME:客户端发送加入游戏的消息到服务器,服务器转发该消息给所有人。

BYE_BYE:玩家彻底退出游戏,服务器转发该消息给所有人,所有玩家删除该玩家的信息。

     5.2.2.2小组内消息

PLAYER_LIST:服务器发送玩家列表消息给某个组的所有人。

CREATOR_LIST:服务器发送创建者列表给所有人。更新创建者列表。

ADD_PLAYER:服务器发送增加玩家消息给此玩家之外的所有人,接收消息的客户端更新玩家列表。

SUB_PLAYER:服务器发送减少玩家消息给此玩家之外的所有人,接收消息的客户端更新玩家列表。

ADD_CREATOR:服务器发送增加创建者消息给此玩家之外的所有人,接收消息的客户端更新创建者列表。

SUB_CREATOR:服务器发送减少创建者消息给此玩家之外的所有人,接收消息的客户端更新创建者列表。

CREATOR_AND_MEMBER:服务器发送创建者和成员列表消息消息给此玩家之外的所有人,接收消息的客户端更新玩家列表。

CHANGE_ROLE:服务器发送改变角色消息给此玩家之外的所有人,接收消息的客户端更新该玩家的角色信息。

CHANGE_GAME_STATUS:更改游戏状态。

GROUP_MESSAGE:玩家组的聊天消息。

CREATOR_EXIT_CREATED_GAME:创建者退出创建的游戏。所有玩家都将退出该组,玩家组被删除。

PLAYER_EXIT_CREATED_GAME:加入游戏的人退出创建者创建的游戏,其它玩家收到消息后,更新成员列表。

CREATOR_START_CREATED_GAME:创建者开始游戏。其它玩家都开始游戏。

5.2.2.3 玩家游戏消息

GAME_EXIT:玩家退出正在进行的比赛。

GAME_PAUSE:玩家暂停游戏。

GAME_CONTINU:玩家继续游戏。

GAME_UNDO:玩家请求悔棋。

GAME_BACK_YES:对方同意悔棋。

GAME_BACK_NO:对方拒绝悔棋。

PLAYER_GIVEIN:玩家认输。

PIECE_MOVING:棋子移动消息。

GAME_QIUHE:玩家求和。

GAME_MESSAGE:玩家组内的聊天。

     

   5.2.3 Socket实现

     

       Java.net.ServerSocket

// 打开端口号PORT,使客户能够连接上

ServerSocket serverSocket = new ServerSocket

(NetworkConstants.PORT);

String time = ChessUtil.getTime();

msgArea.append(SERVER_NAME + ":开始监听用户请求

--" + time + "\n");

// 不间断地监听用户请求

while (true) {

// 等待客户进程发出连接请求

Socket playerSocket = serverSocket.accept();

ObjectOutputStream oos = new ObjectOutputStream(playerSocket.getOutputStream());

ObjectInputStream ois = new

ObjectInputStream(playerSocket.getInputStream());

  Java.net.Socket

/** 从服务器接收消息 */

private void receiveInfoFromServer() throws Exception {

MsgPacket serverPacket = new MsgPacket();

if (fromServer != null) {

serverPacket = (MsgPacket) fromServer.readObject();

}

5.3人工智能

       5.3.1 局面表示

            使用2维数组,

// 棋子点,共90个,横9*纵10

public ChessPoint chessPoints[][];

       5.3.2 走法表示

class ManualItem {

private PieceId eatedPieceId;// 被吃棋子的ID,悔棋时使用

private MoveStep moveStep;// 从哪移动到哪

       5.3.3 生成走法

先找出本方棋子,然后分别生成每个棋子的走法。每个棋子的走法,根据中国象棋的游戏规则来生成。

方法一:程序简单,但效率不高。

        使用2个for循环,从所有位置中找出可走位置,来生成走法。

方法二:程序复杂,效率高。

        针对每个棋子的特点,只选择可走位置,来生成走法。

       5.3.4  局面评估

        参考因素:棋子的价值、位置、灵活性等。

        5.3.5 搜索算法

         5.3.5.1 深度优先

算法伪码

输入:树根结点root

输出:无

如果结点root非空

   访问结点root

   从左到右,依次深度优先搜索结点root的每一个子结点。

否则,直接返回

      5.3.5.2 广度优先

算法伪码

输入:树根节点root

输出:无

1如果结点root为空

直接返回

2.否则

3.将结点root放入队列

5.如果队列不为空

5.队首结点出队,赋给root

6.访问该结点

7.将root的子结点进队

8.返回第5步。

   程序代码

  5.3.6人机博弈流程

初始化棋盘:显示棋盘,棋子按棋局开始位置摆放好。

棋手行棋:  棋手思考走法,并且鼠标在界面上走出一步棋。

合理性判断:对棋手走出的每一步棋,进行合理性判断,是否符合游戏规则。

棋手思考不周全,下棋时手误,或者鼠标点的位置有误差,都可能导致走棋不符合规则。对棋手下棋进行合理性判断是非常必要的。为了简化程序,并不判断是否有长将、长捉、长杀等情况。

棋局结束判断:当一方无棋可走,或者被吃掉將,棋局就结束了。程序必须判断棋局是否结束。为了降低程序难度,不考虑不变作和。

  5.4其它算法

      5.4.1 棋谱的自动演示

          For循环

      5.4.2 音乐的播放与停止

标记播放状态,根据状态来决定是播放、停止还是暂停。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
国际象棋马象残局算法是指在国际象棋中,针对马和象这两个棋子的残局问题而设计的算法。马象残局算法旨在找出在只剩下马和象这两个棋子的情况下,实现胜利或者防守的最佳走法。 在马象残局算法中,可以使用一些基本的搜索和判断技巧。例如,可以使用置换表技术和走法顺序优化技巧来提高搜索效率和减少搜索空间。此外,还可以利用计算机博弈基本智能算法来进行决策,克服搜索不稳定性的问题。 一种常见的方法是建立开局库和残局库。开局库是指存储了各种开局局势和相应最佳走法的数据库,可以在残局开始时进行参考。而残局库则是存储了各种马象残局的数据库,可以在残局时提供参考走法。这些库可以帮助计算机在残局中做出更明智的决策。 此外,训练神经网络也是一种常见的方法。通过使用来自真实比赛和不常见的棋局的数据,可以让计算机学习和改善自身的判断能力。通过自我学习,计算机可以逐渐提高下棋的技巧和决策能力。 总之,国际象棋马象残局算法是通过使用搜索技巧、博弈算法、开局库、残局库和训练神经网络等方法,来解决在只剩下马和象这两个棋子的情况下的最佳走法问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [电脑象棋循序渐进及国际象棋程序设计](https://download.csdn.net/download/intmov/1283072)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [一台会判断的计算机:自学72小时就能成国际象棋大师](https://blog.csdn.net/weixin_28730549/article/details/118412038)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

等天晴i

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

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

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

打赏作者

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

抵扣说明:

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

余额充值