C++/OpenGL国际象棋游戏程序设计建议



我正在制作一款用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,它接受一个Move并检查移动是否有效。

一个抽象类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

关于国际象棋的AI部分:

为了获得国际象棋AI或任何类型的回合制游戏AI,你需要计算游戏在一个给定回合中的"值"(这很重要)(也就是说,你给每一块分配一个值,并将玩家1和玩家2的值相加,然后你做score=玩家1score-玩家2score,所以负值对玩家2有利,正值对玩家1有利,这只是一个基本的例子,不是很有效,但这是解释游戏的"价值"是)。

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

有了它,你将能够构建一个决策树,其中你将把游戏的当前状态作为根节点。树的下一个"级别"将代表从当前状态(依此类推)可以达到的每一种可能状态。重要的是要注意,若你们考虑玩家1在树的级别上的可能移动,你们会考虑玩家下一个级别上的两个可能移动。

接下来要做的是:

假设玩家1要移动,他会在树上观察直到深度5(对于一场国际象棋游戏,你永远不会在整棵树上观察)。因此,他将选择一个为他优化的移动,这意味着:在每个级别上,他都会考虑自己的最佳移动或玩家2的最佳移动(因此他将处理最坏的情况),因此他将移动树的下一级别中值最高的节点。

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

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

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

因此,基本上,您将根据更深节点的值进行回归,以找到节点的值。

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

希望它对有一点帮助

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

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

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

我建议你阅读:

  1. 国际象棋程序WIKI
  2. TalkChess电脑象棋论坛
  3. 研究一个开源的计算机象棋引擎,比如Stockfish、Crafty或Fruit

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

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

对于像国际象棋这样的东西,存在着许多有效而优雅的国际象棋游戏状态表示。我想说MVC(模型、视图、控制器)设计模式在国际象棋游戏中运行得很好。

希望这会有一些意义,如果没有,我建议你多读一些MVC。

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

视图是所有与演示文稿相关的代码所在的位置。OpenGL在这里所做的一切,以及"调试"例程,它可能(例如)将棋盘的ASCII表示打印到控制台。

控制器可能具有一些与用户接口以处理输入的功能。控制器是操作模型("将E5移动到D3":控制器中的一个函数可能会调用model.moveKnight('D3'))和视图("在光荣的3D中绘制板":控制器可能会调用类似于openGLView.draw(model)的操作)的代码部分

MVC帮助实现的主要目标之一是执行不同任务的代码部分的独立性。如果你的人工智能发生了一些变化,导致渲染算法出现问题,这将是一个令人沮丧和困难的境地。一个经验丰富的程序员会竭尽全力确保这种情况不会发生。

在这一点上,你可能想知道你的人工智能代码在哪里合适。好吧,这真的取决于你。运用你最好的判断力。它可能是控制器的一部分。就我个人而言,我希望它是一个完整的另一个控制器(chessAIController)来实现AI算法,但将所有这些都包含在主控制器中同样容易。

关键是,实际上如何组织代码并不重要,只要它是以某种逻辑方式完成的。MVC之所以如此广泛,是因为这三个组件通常存在于大多数软件中,并且通常将它们分开是有意义的。注意,他们实际上并没有真正分开。。。控制器经常直接操纵视图和模型。诸如不允许视图操作任何内容之类的限制有助于代码保持清晰易懂。

当你在编程项目中没有结构或组织时,几乎不可能避免拥有庞大的例程来完成所有的事情,因为代码中实际上只有一个地方可以用来构建功能。这必然会产生大量错综复杂的意大利面条代码,无论多么高级的语言都无法将您从中拯救出来。这创建的代码非常糟糕,因为没有人能理解它,甚至你在编写它的两周后也无法理解它。

相关内容

  • 没有找到相关文章

最新更新