2

我正在制作一个用 OpenGL 渲染的国际象棋游戏。

我不是在找人来告诉我所有的答案,我想自己弄清楚代码,但我真正需要的是指出正确的概念。在这一点上,我不知道从哪里开始。这是我发现的:

一个枚举,TurnState,具有以下值:

  • playerOneTurn
  • playerTwoTurn
  • Stopped

一个枚举,GameState,具有以下值:

  • playerOneCheck
  • playerTwoCheck
  • playerOnecCheckMate
  • PlayerTwoCheckMate
  • InitializingGame
  • Tie
  • NormalPlay

一个抽象类 ,Player和一个子类 , Computer

具有以下字段的类ChessGame

Player p1, p2
TurnState turnState
GameState gameState 

具有以下字段的类Move

*Piece
Location origin
Location destination

具有以下字段的类Location

row
col
*ChessBoard 

一个类, ChessBoard, 有一个方法, isValid, 它接受 aMove并检查移动是否有效。

具有以下方法的抽象类ChessPieces

GetValue()      // returns an int value of the piece (for scoring)
GetPosition()   // returns the current position of a piece
getIsSelected() // returns a boolean, true if selected, false if unselected
move()          // moves the piece in a way dependent upon what piece 

以及以下子类:

  • Pawn
  • Rook
  • Queen
  • King
  • Knight
4

3 回答 3

3

至于国际象棋的AI部分:

要获得国际象棋 AI 或任何类型的回合制游戏 AI,您需要计算给定回合中游戏的“价值”(这很重要)(即,您为每个棋子分配一个值并将玩家 1 和player2 然后你做 score = player1score - player2score,所以负值将有利于玩家 2 和正值,玩家 1,这只是一个基本的例子,不是一个非常有效的例子,但它是解释什么是“价值”的最基本的方式游戏将是)。

在您可以计算之后,您需要能够计算给定棋盘特定配置的玩家的每一个可能的移动。

有了它,您将能够构建一个决策树,其中您将拥有游戏的当前状态作为根节点。树的下一个“级别”将代表您可以从当前状态(等等)到达的每个可能的状态。重要的是要注意,如果您考虑玩家 1 可能在树的级别上移动,您将在下一个考虑玩家两个可能的移动。

接下来要做的是:

假设玩家 1 将要移动,他将在树中查看直到深度 5(对于国际象棋游戏,您永远不会查看整个树)。所以他会选择一个会为他优化的动作,这意味着:在每个级别他都会考虑他的最佳动作或玩家2的最佳动作(所以他会在最坏的情况下工作),所以他会移动树的下一级中的最高值节点。

要计算节点的值,请执行以下操作: 注意:考虑到根节点的深度为 0,对于 player1,每个奇数深度节点都需要为 maxValue,而对于 player2,每个偶数深度节点都需要为 minValue。

您将树扩展到您定义的最大深度,对于 maxDepth 中的节点,您只需计算板的值(我在答案开头提到过),对于上层节点,您将执行以下操作:

偶数节点的值:所有子节点之间的 minValue 奇数节点的值:所有子节点之间的 maxValue

所以基本上你会根据更深节点的值进行回归以找到节点的值。

嗯,这就是基本的想法,你可以从中研究一些其他的东西,如果你想你可以PM我,我已经在这种搜索上做了一些工作,我只是在这里描述了最基本的想法,以获得有效的代码你需要很多优化技术。

希望它有所帮助

于 2012-09-12T02:46:30.340 回答
1

首先:将两者分开:AI 和 GUI/OpenGL。在国际象棋中,将 GUI 和 AI(计算机国际象棋术语中的“引擎”)放在两个不同的进程中并使用预定义的协议进行通信是很正常的。两个最流行的协议是 UCI 和 WinBoard。

对于国际象棋引擎部分,您基本上需要三件事:

  1. 董事会/职位代表
  2. 叶节点评估函数
  3. 一种搜索算法

我建议你阅读:

  1. 国际象棋编程维基
  2. TalkChess 计算机国际象棋论坛
  3. 学习开源计算机国际象棋引擎,例如 Stockfish、Crafty 或 Fruit。
于 2012-09-12T12:24:44.950 回答
0

这可能不会直接回答您的问题(实际上您的问题是什么?),但您提到您想要指向正确概念的指针。

oysteijo 是对的,其中一个非常重要的概念是将程序的各个部分相互分离。

对于象棋之类的东西,存在许多有效而优雅的国际象棋游戏状态表示。我想说 MVC(模型、视图、控制器)设计模式非常适合国际象棋游戏。

希望这会有意义,如果不是,我建议您多阅读 MVC。

您的模型将主要涉及存储游戏状态表示的数据结构,这就是棋盘。一件作品只能出现在 64 个地点中的一个上,并且作品的类型、数量以及每个作品的作用都有限制。模型将负责处理这些东西。为模型提供用于确定任何给定动作的合法性的逻辑(即,不一定涉及任何给定游戏实例的状态的游戏属性)也是有意义的。

视图是所有与演示相关的代码所在的位置。所有的 OpenGL 都在这里,一个“调试”例程可能(例如)将棋盘的 ASCII 表示打印到控制台。

控制器可能具有与用户交互以处理输入的一些功能。控制器是操作模型(“将 E5 移动到 D3”:控制器中的一个函数可能会调用model.moveKnight('D3'))和视图(“以光彩的 3D 画板”:控制器可能会执行类似调用的操作openGLView.draw(model))的代码部分

MVC 帮助实现的主要目标之一是执行不同任务的代码部分的独立性。如果您的 AI 中的某些更改导致渲染算法出现问题,那将是一个令人沮丧和困难的位置。经验丰富的程序员会竭尽全力确保不会发生这种情况。

此时您可能想知道您的 AI 代码在哪里适合。好吧,这真的取决于你。用你最好的判断。它可能是控制器的一部分。就我个人而言,我希望它是一个chessAIController实现 AI 算法的完整的另一个控制器(

关键是,你实际上如何组织代码并不重要,只要它以某种合乎逻辑的方式完成即可。MVC 如此普遍的原因是这三个组件通常存在于大多数软件中,并且通常将它们分开是有意义的。请注意,它们实际上并没有真正分开......控制器通常直接操作视图和模型。诸如不允许视图操作任何东西的限制有助于代码保持干净和可理解。

当您在一个编程项目中没有结构或组织时,几乎不可能避免使用庞大的例程来完成所有事情,因为代码中实际上只有一个地方可以构建功能。这总是会产生一堆乱七八糟的意大利面条代码,无论多么高级,任何语言都无法拯救你。这会创建很糟糕的代码,因为没有其他人可以理解它,甚至在编写后两周内你也无法理解它。

于 2012-09-12T23:18:33.540 回答