65.9K
CodeProject 正在变化。 阅读更多。
Home

ChessCtrl

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (6投票s)

2024年9月17日

GPL3

15分钟阅读

viewsIcon

2126

downloadIcon

60

使用MFC库在C++中编写的具有完整功能的国际象棋控件。

ChessCtrl 是一个使用MFC库在C++中编写的、功能齐全的国际象棋控件。主要的类是您猜到的 CChessCtrl,它包含了 ChessBoard 类。

ChessBoard 类实现了以下函数:

  • void resetBoard(): 开始新游戏;重置引擎的字段并棋盘上放置相应的棋子。
  • void submitMove(const TCHAR* fromSquare, const TCHAR* toSquare)
  • void getANewBoard()
  • void makeGameInCheck()
  • void makeGameNotInCheck()
  • void beginAGame()
  • void endTheGame()
  • void makeWhiteGoesNext()
  • bool gameCanContinue(wstring sourceFileRank, wstring destFileRank): 检查游戏是否未结束。
  • bool sourceAndDestIsValid(wstring sourceFileRank, wstring destFileRank): 检查给定的源和目标文件的文件和等级表示是否有效(为2个字符的wstring),并且在棋盘范围内。
  • bool withinChessBoard(wstring fileRank): 检查文件是否在 'A'-'H' 范围内,等级是否在 '1'-'8' 范围内。
  • bool sourceIsNotEmpty(wstring sourceFileRank, Board* board): 检查源位置是否非空(即,有棋子可移动)。
  • bool isCurrentPlayerPiece(bool isWhiteTurn, Piece* piece, wstring sourceFileRank): 检查源位置的棋子是否属于当前轮到的一方。
  • bool pieceMoveIsValid(int returnCode, Piece* piece, wstring sourceFileRank, wstring destFileRank): 检查验证棋子移动的返回码是否为零。
  • bool pieceMoveKeepsKingSafe(bool isWhiteTurn, Piece* piece, wstring sourceFileRank, wstring destFileRank, Board* sandboxBoard): 检查在给定棋盘(在ChessBoard中将是一个沙盒)下,给定方的王是否安全,如果不安全,则向用户显示错误并返回 false。
  • void handleInvalidMove(int returnCode, Piece* piece, wstring sourceFileRank, wstring destFileRank): 调用错误处理程序打印错误,传递调用函数提供的信息。
  • bool kingIsSafeFromRivalry(bool isWhiteTurn, Board* board): 如果对方的棋子均无法吃掉给定方的王(即,没有有效的移动到王的所在文件和等级),则返回 true。
  • bool playerHaveValidMove(bool isWhiteTurn, Board* board): 如果给定方在给定棋盘上存在有效的移动,则返回 true。
  • wstring findPlayersKingFileRank(bool isWhiteTurn, Board* board): 迭代并返回给定方的王的所在位置(文件和等级)。
  • Piece* tryMoveAndReturnCaptured(wstring sourceFileRank, wstring destFileRank, Board* board): 在给定棋盘上,执行从源到目标的移动并获取被吃掉的棋子;情况 1(try块)- 目标位置有其他棋子(执行吃子);情况 2(catch块)- 目标位置无棋子(执行移动)。在情况 1 时返回棋子,否则返回 NULL。
  • void confirmMoveOnBoard(wstring sourceFileRank, wstring destFileRank, Board* board): 在给定棋盘上,执行从源到目标的移动;情况 1(try块)- 目标位置有其他棋子(执行吃子);情况 2(catch块)- 目标位置无棋子(执行移动)。
  • void switchPlayers()
  • Board* cloneBoard(Board* board): 深拷贝给定棋盘,包括地图中的所有棋子。
  • void deepCleanBoard(Board* board): 深层清理给定棋盘,释放其中所有棋子的内存以及棋盘本身。
  • bool showMoveAndCheckIfGameCanContinue(Piece* piece, wstring sourceFileRank, Piece* capturedPiece, wstring destFileRank, bool isWhiteTurn, Board* board): 在标准输出上以文本和图形方式进行打印。
  • void ComputerPlayer(): 实现计算机的黑方棋子移动的后退算法(如果启用)。

ChessBoard 类包含以下类:

  • EmptyPiece(继承自 Piece
  • Bishop(继承自 Piece
  • King(继承自 Piece
  • Knight(继承自 Piece
  • Pawn(继承自 Piece
  • Queen(继承自 Piece
  • Rook(继承自 Piece

Piece 类声明了以下虚函数:

  • Piece* clone(): 返回一个具有与自身相同信息的不同对象。
  • int isValidMove(wstring sourceFileRank, wstring destFileRank, map<wstring, Piece*>* board)
  • wstring playerToString(): 返回棋子所属玩家的 wstring 表示。
  • wstring toString(): 返回棋子的 wstring 表示。
  • wstring toGraphics(): 返回棋子的图形表示。
  • int Score(): 返回棋子的分数(用于后退算法执行计算机移动)。

并且它实现了以下函数:

  • void confirmMove(): 当调用此函数时,将 isFirstMove 设置为 false,因为棋子已移动至少一次。
  • bool isWhitePlayer(): 返回此棋子是否属于白方玩家。
  • bool isKing(): 如果棋子是王,则返回 true(由 King 构造函数设置)。
  • bool isFriendly(Piece* that): 如果此棋子和 that 棋子属于同一玩家,则返回 true。
  • bool isSameFile(wstring sourceFileRank, wstring destFileRank): 如果 sourceFileRank 和 destFileRank 在同一文件/等级/对角线上,则返回 true;否则返回 false。
  • bool isSameRank(wstring sourceFileRank, wstring destFileRank): 如果 sourceFileRank 和 destFileRank 在同一文件/等级/对角线上,则返回 true;否则返回 false。
  • bool isSameDiagonal(wstring sourceFileRank, wstring destFileRank): 如果 sourceFileRank 和 destFileRank 在同一文件/等级/对角线上,则返回 true;否则返回 false。
  • bool noVerticalObstruction(wstring sourceFileRank, wstring destFileRank, map<wstring, Piece*>* board): 如果棋盘上的中间等级没有棋子,则返回 true;否则返回 false。
  • bool noHorizontalObstruction(wstring sourceFileRank, wstring destFileRank, map<wstring, Piece*>* board): 当且仅当棋盘上的中间文件没有棋子时,返回 true;否则返回 false。
  • bool noDiagonalObstruction(wstring sourceFileRank, wstring destFileRank, map<wstring, Piece*>* board): 如果棋盘上同一对角线上的中间文件和等级没有棋子,则返回 true;否则返回 false。
  • bool destExistFriendlyPiece(wstring destFileRank, map<wstring, Piece*>* board): 如果棋盘上同一对角线上的中间文件和等级没有棋子,则返回 true;否则返回 false。

国际象棋规则

国际象棋规则(也称为国际象棋法)管理着国际象棋的比赛。国际象棋是一款两人抽象策略棋盘游戏。每位玩家控制六种类型的十六个棋子,在棋盘上进行游戏。每种棋子都有独特的移动方式。游戏的目标是将死对方的王;当王的相位威胁被捕获且无路可逃时,即发生将死。除将死外,游戏还可以以多种方式结束:玩家可以认输,并且有几种情况会导致游戏和棋。

虽然国际象棋的确切起源尚不清楚,但现代规则在中古时期首次成形。规则在 19 世纪初之前一直略有修改,那时它们基本达到了当前的形式。规则在不同地区也略有不同。如今,标准规则由国际棋联(Fédération Internationale des Échecs)制定,国际棋联是国际象棋的国际管理机构。一些国家组织会为自己的目的进行小幅修改。快棋、通讯棋、在线国际象棋和 Chess960 的规则略有不同。

除了棋子的基本移动外,规则还规定了使用的设备、时间控制、玩家的行为和道德、对残疾玩家的住宿以及使用棋谱记录棋步。还提供了处理比赛中可能出现的违规行为的程序。

初始设置

国际象棋在棋盘上进行,棋盘是一个方形棋盘,分为 64 个交替颜色的方格(八乘八)(类似于跳棋棋盘)。无论棋盘的实际颜色如何,颜色较亮的方格称为“浅色”或“白色”,颜色较暗的方格称为“深色”或“黑色”。游戏开始时,棋盘上摆放着十六个“白色”棋子和十六个“黑色”棋子。棋盘的摆放方式是,每个玩家右侧的近角都应是白色方格。水平的行称为横线(ranks),垂直的列称为直线(files)。

每位玩家控制十六个棋子

ChessDemo.png

游戏开始时,棋子按图示摆放:每方一个王、一个后、两个车、两个象、两个马和八个兵。棋子摆放方式如下,每格一个:

  • 车放在最外侧的角落,左右边缘。
  • 马放在车的紧里面。
  • 象放在马的紧里面。
  • 后放在与棋子同色的中心格子上:白后放在白格子上,黑后放在黑格子上。
  • 王占据皇后旁边的空位。
  • 兵放在所有其他棋子的前面一格。

用于记住摆放的流行助记符是“后随己色”和“白在右”。后者指的是将棋盘摆放成使每个玩家右手边最近的方格为白色。

游戏玩法

控制白棋的玩家称为“白方”,控制黑棋的玩家称为“黑方”。白方先走,然后玩家轮流走棋。必须走棋;即使走棋有害,也不能跳过走棋。游戏一直进行,直到王被将死、一方认输或宣布和棋(如下所述)。此外,如果游戏是在时间控制下进行的,超时的一方将输掉游戏,除非他们无法被将死。

官方国际象棋规则不包含确定谁执白棋的程序。相反,这个决定留给特定赛事的规则(例如,瑞士制比赛或循环赛)或在休闲对局中,双方协商一致,这时可以使用一些随机选择的方法,例如抛硬币。一种常见的方法是,一方将一手各一个黑白兵藏在手中;另一方选择一只手打开,并获得展示出来的棋子的颜色。

移动

基本走法

每种国际象棋棋子都有自己独特的移动方式。棋子移动到空方格,除非是吃掉对方的棋子。

除了马的移动和王车易位之外,棋子不能越过其他棋子。当被攻击的敌方棋子取代其位置时,棋子即被吃掉(或捉走)。被吃掉的棋子将被永久移出游戏。王可以被将军,但不能被吃掉(见下文)。

  • 王沿着水平、垂直或对角线移动一格。有一种特殊的王车易位移动,每位玩家每局只允许一次(见下文)。

  • 车沿着水平或垂直方向移动任意数量的空方格。它也可以在王车易位时移动。

  • 象沿着对角线移动任意数量的空方格。(因此,象只能移动到浅色方格或深色方格,不能同时移动到两种颜色。)

  • 后沿着水平、垂直或对角线方向移动任意数量的空方格。

  • 马移动到离当前位置最近的、不在同一横线、直线或对角线上的方格。(这可以被认为是先横向移动两格再纵向移动一格,或者先横向移动一格再纵向移动两格——即呈“L”形。)马不受其他棋子的阻碍;它可以跳到新位置。

  • 兵的走法最为复杂

  • 兵向前直走一格,如果该方格为空。如果兵尚未移动,它还可以选择向前直走两格,前提是这两个方格都为空。兵不能后退。

  • 兵不像其他棋子,其吃子方式与其移动方式不同。兵可以吃掉它前方对角线上的任意一个敌方棋子。除非是进行吃过路兵,否则兵不能移动到这些空方格。

兵还参与吃过路兵升变这两个特殊走法。

王车易位

王车易位包括王向车移动两格,然后将车放在王另一侧紧邻它的位置。只有在满足所有以下条件时,才允许王车易位:

  • 参与王车易位的王和车之前不得移动过;
  • 王和车之间不得有其他棋子;
  • 王当前不得受到攻击,王也不能经过或最终停留在被敌方棋子攻击的方格(尽管车可以受到攻击或经过被攻击的方格);
  • 王车易位必须是如图所示的王翼侧或后翼侧。

未移动过的王和同一方未移动过的车在同一横线上,就被认为拥有王车易位权

吃过路兵

当兵在其初始移动中前进两格,并且回合结束时位于同一横线上相邻的敌方兵旁边时,它可以被敌方兵吃过路兵,就像它只移动了一格一样。这种吃子仅在兵前进后的下一个回合合法。图示了一个例子:如果白兵从 a2 移到 a4,则黑兵在 b4 可以通过吃过路兵吃掉它,从 b4 移到 a3,而 a4 上的白兵则被移出棋盘。

升变

如果一方将兵推进到其第八横线,则该兵将升变(转换)为同色的一名后、车、象或马,由玩家选择(通常选择后)。选择不受先前被吃掉的棋子的限制。因此,理论上,如果一方的所有兵都升变,则该玩家最多可以拥有九个后或十个车、象或马。

Check

当王的相位受到至少一个敌方棋子的攻击时,该王即被将军。一个因移动会使己方王处于被将军状态而无法移动的棋子(它被钉在己方王前面)仍然可以对对方玩家进行将军。

做出会使己方王被将军或留在被将军状态的移动是违法的。摆脱将军的可能方法是:

  • 移动王到它未被将军的方格。
  • 吃掉将军的棋子。
  • 插入一个棋子在王和对方的威胁棋子之间(阻挡将军)。

在非正式比赛中,习惯上会在做出将死对方王的移动时宣布“将军”。然而,在正式比赛中,很少会宣布将军。

游戏结束

将死

如果一方的王被将军,并且该方没有任何合法的移动可以摆脱将军,则该王被称为被将死,游戏结束,该方输棋。

图示展示了一个将死局面。白王受到黑后的威胁;王可以移动的空方格也受到威胁;王不能吃掉后,因为它会因此被车将军。

认输

任何一方都可以在任何时候认输,从而将游戏输给对手。为了表示认输,玩家可以说“我认输”。推倒王也表示认输,但应与意外碰倒王区分开。停止两个计时器不是认输的指示,因为计时器可以被停止以呼叫裁判。有时会提供握手,但这可能被误认为是和棋提议。

根据国际棋联的规则,如果一方认输,则在对方无法通过任何一系列合法棋步将死对方的情况下,该方将输棋,否则则为和棋。

和棋

如果发生以下任何情况,游戏将以和棋结束:

  • 轮到走棋的一方未被将军且无合法移动。这种情况称为逼和。相邻的图示了一个这种局面的例子。
  • 游戏达到死局。
  • 双方在其中一方提出和棋后同意和棋。

此外,根据国际棋联的规则,如果一方时间用尽(见下文),或已认输,但局面是对方无法通过任何一系列合法棋步将死,则游戏为和棋。

国际棋联的比赛规则允许玩家在以下两种情况之一声称和棋:

  • 双方各进行了五十回合的棋步,期间没有发生吃子或兵的升变(这是五十回合规则;
  • 同一局面出现了三次(或出现了两次,并且声称和棋的玩家可以强制出现第三次);这是三次重复规则。

这些规则有助于防止比赛无限期延长。

不再有明确定义永恒将军为和棋的规则。在这种情况下,最终将适用三次重复规则或五十回合规则。更常见的是,玩家会简单地同意和棋。

死局

死局被定义为双方都无法通过任何一系列合法棋步将死对方的王的局面。根据国际象棋规则,一旦棋盘上出现死局,游戏立即终止。

一些基本残局总是死局;例如:

  • 王对王;
  • 王对王和象;
  • 王对王和马。

可能出现阻塞的局面,无论哪一方都无法前进,例如图示局面;这些也是死局。

美国国际象棋联合会(USCF)的规则,对于在不包含延迟或增时的计时制下进行的比赛,允许声称“不足以输”的和棋。例如,如果双方只有王和马,即使不是死局,也只有在双方合作的情况下才能实现将死。

触摸走子规则

触摸走子规则是国际象棋的一项基本原则,旨在确保玩家在精神上经过深思熟虑后再移动棋子,而不是在棋盘上进行物理尝试。根据这项规则,有意移动棋子的玩家,如果合法,则必须移动该棋子。这项规则也适用于吃子:触摸对方棋子的玩家,如果存在合法的吃子机会,则必须吃掉它。对于王车易位和兵的升变,则有特殊的考虑,以反映它们在游戏中的独特性。

触摸棋子以调整其在方格内的物理位置的玩家,必须先通过说J'adoube或“我调整”来提醒对方。游戏开始后,只有轮到走棋的玩家才能触摸棋盘上的棋子。

创建并提交您的拉取请求

ChessCtrl贡献规则中所述,所有拉取请求都需要附带一个 GitHub issue。因此,第一步是创建一个 issue,要求改进(如果功能已存在)或添加(如果功能尚不存在)某个功能;在 issue 中,请务必说明您已准备好功能定义,并将提交一个拉取请求。第二步是使用 GitHub 界面将您的 fork 推送到主存储库,并创建拉取请求。最后一步是等待并根据需要响应开发者的反馈,直到您的 PR 被接受或拒绝。

致谢

这个开源项目使用了以下库:

© . All rights reserved.