有什么模型棋盘游戏的模式吗?[英] Any patterns for modelling board games?

本文是小编为大家收集整理的关于有什么模型棋盘游戏的模式吗?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

为了娱乐,我试图将儿子最喜欢的棋盘游戏之一作为一件软件写.最终,我希望在其顶部构建WPF UI,但是现在我正在构建对游戏及其规则进行建模的机器.

当我这样做时,我一直看到我认为许多棋盘游戏常见的问题,也许其他人已经比我更好地解决了问题.

(请注意,AI玩游戏,以及有关高性能的模式对我来说并不有趣.)

到目前为止我的模式是:

  • 代表游戏框中实体的几种不变的类型,例如骰子,棋子,卡片,板,董事会上的空间,金钱等.

  • 每个玩家的对象,其中包含玩家资源(例如钱,得分),他们的姓名等.

  • 一个代表游戏状态的对象:玩家,转弯的对象,董事会上的Peices的布局等等.

  • 管理转弯序列的状态机.例如,许多游戏都有一个小的游戏,每个玩家都可以在这里看看谁去.那是开始状态.当玩家轮到比赛开始时,首先他们滚动,然后移动,然后他们必须在适当的位置跳舞,然后其他玩家猜测他们是什么品种,然后他们会收到积分.

我可以利用一些先前的艺术吗?

编辑:我最近意识到的一件事是,游戏状态可以分为两类:

  • 游戏文物状态. "我有$ 10"或"我的左手在蓝色上".

  • 游戏序列状态. "我两次滚动了双打;下一个让我入狱".状态机在这里可能很有意义.

编辑:我在这里真正寻找的是实现基于多人转弯的游戏(如国际象棋,拼字游戏或垄断)的最佳方法.我敢肯定,我可以通过开始完成工作来创建这样的游戏,但是,就像其他设计模式一样,如果没有仔细的研究,可能有一些方法可以使事情变得更加顺利.这就是我所希望的.

推荐答案

看来,这是我刚刚注意到的一个2个月的线程,但是到底是什么.我以前已经为商业,网络棋盘游戏设计并开发了游戏框架.我们有一个非常愉快的经验.

您的游戏可能处于(接近)无限数量的状态,因为诸如A拥有多少钱玩家,Bone Money B的含量,等等等...因此,我很漂亮确保您想远离国家机器.

我们框架背后的想法是将游戏状态表示为结构,其中所有数据字段共同提供了完整的游戏状态(即:如果您想将游戏保存到磁盘,则将该结构写出)./p>

我们使用命令模式表示玩家可以做出的所有有效的游戏动作.这将是一个示例动作:

class RollDice : public Action
{
  public:
  RollDice(int player);

  virtual void Apply(GameState& gameState) const; // Apply the action to the gamestate, modifying the gamestate
  virtual bool IsLegal(const GameState& gameState) const; // Returns true if this is a legal action
};

因此,您会看到要确定移动是否有效,您可以构建该操作,然后调用其Islegal功能,以通过当前的游戏状态.如果它是有效的,并且播放器确认操作,则可以调用应用功能实际修改游戏状态.通过确保您的游戏代码只能通过创建和提交法律措施来修改游戏状态(换句话说,操作::应用方法家族是唯一直接修改游戏状态的方法),然后确保您的游戏状态永远不会无效.此外,通过使用命令模式,您可以使玩家的所需移动序列化并通过网络发送以在其他玩家的游戏状态下执行.

最终有一个系统的系统,结果证明了一个相当优雅的解决方案.有时行动将有两个或更多阶段.例如,玩家可以登陆垄断地位,现在必须做出新的决定.玩家滚动骰子时,以及决定购买房地产之前的游戏状态如何?我们通过以我们游戏状态的"行动上下文"成员为特色来管理这样的情况.操作上下文通常是无效的,表明该游戏目前不处于任何特殊状态.当玩家滚动骰子并将骰子滚动动作应用于游戏状态时,它将意识到玩家已经降落在一个无拥有的属性上,并且可以创建一个新的" playerDecideCideTopurchaseproperty"动作上下文,其中包含玩家的索引我们正在等待一个决定.到Rolldice Action完成时,我们的游戏状态表示目前正在等待指定的玩家决定是否购买房地产.现在,所有其他动作的Islegal方法都可以轻松返回false,除了" buyproperty"和" passpropertypurchaseopportunity"动作,只有在游戏状态具有" playerDecideTopCurchaseproperty"动作上下文时才合法.

.

通过使用动作上下文,在棋盘游戏的终身生活中,游戏状态结构并不能完全代表游戏中游戏中发生的事情.这是您棋盘游戏系统的非常理想的属性.当您仅通过检查一个结构来找到有关游戏中发生的一切的所有内容时,编写代码会更容易.

此外,它可以很好地扩展到网络环境,客户可以通过网络将其操作提交到主机计算机,该动作可以将动作应用于主机的"官方"游戏状态,然后回应该操作的所有操作其他客户将其应用于其重复的游戏状态.

我希望这简洁明了.

其他推荐答案

游戏引擎的基本结构使用状态模式.您的游戏盒的项目为 singletons 各种班级.每个状态的结构都可以使用策略模式模板方法.

a Factory 用于创建插入玩家的玩家,另一个玩家,另一个玩家,另一个玩家,辛格尔顿. GUI将通过使用观察者模式与此互动,并通过使用一个人进行交互使用命令模式创建的几个命令对象.观察者和命令的使用可以在被动视图中,但只是关于任何MVP/MVC模式,都可以根据您的喜好使用.保存游戏时,您需要抓取 Memento 它的当前状态

我建议您查看此 stite ,看看您是否抓住您是否抓住您,他们是否抓住您作为起点.同样,您的游戏板的核心将成为州立机器.大多数游戏将由两个州预/设置和实际游戏代表.但是,如果您正在建模的游戏具有多种不同的游戏模式,则可以拥有更多的状态.状态不必是顺序的,例如战争轴和战斗有一个玩家可以用来解决战斗的战机.因此,赛前有三个州,主板,战板,游戏在主板和战斗局之间不断切换.当然,转弯序列也可以由状态机表示.

其他推荐答案

我刚刚完成了使用多态性的设计和实施基于州的游戏.

使用称为GamePhase的基本抽象类,该类具有一个重要的方法

abstract public GamePhase turn();

这是什么意思是每个GamePhase对象保持游戏的当前状态,呼叫turn()查看其当前状态并返回下一个GamePhase.

每个混凝土GamePhase具有构造函数,可容纳整个游戏状态.每个turn()方法都有其中的游戏规则.尽管这将规则传播到围绕规则,但它使相关的规则保持在一起.每个turn()的最终结果只是创建下一个GamePhase并以完整的状态传递到下一个阶段.

这允许turn()非常灵活.根据您的游戏,给定状态可以分支到许多不同类型的阶段.这形成了所有游戏阶段的图.

在最高级别的驾驶代码非常简单:

GamePhase state = ...initial phase
while(true) {
    // read the state, do some ui work
    state = state.turn();
}

这非常有用,因为我现在可以轻松地创建游戏的任何状态/阶段

现在要回答您的问题的第二部分,这在多人游戏中如何起作用?在需要用户输入的某些GamePhase中,给定当前状态/阶段,turn()的调用会询问当前Strategy. Strategy只是所有可能的决策Player可以做出的接口.此设置还允许使用AI!

实现Strategy

安德鲁·托普(Andrew Top)说:

您的游戏可能会处于(接近)无限数量的状态,因为诸如A拥有多少钱玩家,Bone Money B的含量,等等.因此,我很确定您想要远离国家机器.

我认为该陈述非常误导,虽然确实有很多游戏状态,但只有几个游戏阶段.为了处理他的示例,这就是我混凝土GamePhases.

的构造函数的整数参数

垄断

一些GamePhase s的示例是:

  • gamestarts
  • PlayerRolls
  • PlayerlandsonProperty(freeparking,gotojail,go等)
  • 玩家贸易
  • PlayerPurchasesProperty
  • 玩家购买
  • PlayerPurchaseshotels
  • PlayerPaysrent
  • PlayerBankRupts
  • (所有机会和社区胸卡)

基地中的某些状态GamePhase是:

  • 球员名单
  • 当前的球员(转弯)
  • 玩家的钱/财产
  • 物业上的房屋/酒店
  • 玩家位置

然后,一些阶段会根据需要记录自己的状态,例如,PlayerRolls会记录玩家连续双打的次数.一旦我们离开PlayerRolls阶段,我们就不再关心连续的卷.

许多阶段可以重复使用并链接在一起.例如,GamePhase CommunityChestAdvanceToGo将使用当前状态创建下一个阶段PlayerLandsOnGo并将其返回.在PlayerLandsOnGo的构造函数中,当前的玩家将被移动到,他们的钱将增加$200.

本文地址:https://www.itbaoku.cn/post/627713.html

问题描述

For fun, I'm trying to write one of my son's favorite board games as a piece of software. Eventually I expect to build a WPF UI on top of it, but right now I'm building the machine that models the games and its rules.

As I do this, I keep seeing problems that I think are common to many board games, and perhaps others have already solved them better than I will.

(Note that AI to play the game, and patterns around high performance are not interesting to me.)

So far my patterns are:

  • Several immutable types representing entities in the game box, e.g. dice, checkers, cards, a board, spaces on the board, money, etc.

  • An object for each player, which contains the players resources (e.g. money, score), their name, etc.

  • An object that represents the state of the game: the players, who's turn it is, the layout of the peices on the board, etc.

  • A state machine that manages the turn sequence. For example, many games have a small pre-game where each player rolls to see who goes first; that's the start state. When a player's turn starts, first they roll, then they move, then they have to dance in place, then other players guess what breed of chicken they are, then they receive points.

Is there some prior art I can take advantage of?

EDIT: One thing I realized recently is that game state can be split in to two categories:

  • Game artifact state. "I have $10" or "my left hand is on blue".

  • Game sequence state. "I have rolled doubles twice; the next one puts me in jail". A state machine may make sense here.

EDIT: What I'm really looking for here is the best way to implement multiplayer turn-based games like Chess or Scrabble or Monopoly. I'm sure I could create such a game by just working through it start to finish, but, like other Design Patterns, there are probably some ways to make things go much more smoothly that aren't obvious without careful study. That's what I'm hoping for.

推荐答案

it seems this is a 2 month old thread that I've just noticed now, but what the heck. I've designed and developed the gameplay framework for a commercial, networked board game before. We had a very pleasant experience working with it.

Your game can probably be in a (close to) infinite amount of states because of the permutations of things like how much money player A has, how much money player B has, and etc... Therefore, I'm pretty sure you want to stay away from state machines.

The idea behind our framework was to represent the game state as structure with all the data fields that together, provide the complete game state (ie: if you wanted to save the game to disk, you write that structure out).

We used the Command Pattern to represent all of the valid game actions a player could make. Here would be an example action:

class RollDice : public Action
{
  public:
  RollDice(int player);

  virtual void Apply(GameState& gameState) const; // Apply the action to the gamestate, modifying the gamestate
  virtual bool IsLegal(const GameState& gameState) const; // Returns true if this is a legal action
};

So you see that to decide whether a move is valid, you can construct that action and then call its IsLegal function, passing in the current game state. If it is valid, and the player confirms the action, you can call the Apply function to actually modify the game state. By ensuring that your gameplay code can only modify the game state by creating and submitting legal Actions (so in other words, the Action::Apply family of methods are the only thing that directly modifies the game state), then you ensure that your game state will never be invalid. Furthermore, by using the command pattern, you make it possible to serialize your player's desired moves and send them over a network to be executed on other player's game states.

There ended up being one gotcha with this system that turned out to have a fairly elegant solution. Sometimes actions would have two or more phases. For example, the player may land on a property in Monopoly and must now make a new decision. What is the game state between when the player rolled the dice, and before they decide to purchase a property or not? We managed situations like this by featuring an "Action Context" member of our game state. The action context would normally be null, indicating that the game is not currently in any special state. When the player rolls the dice and the dice rolling action is applied to the game state, it will realize that the player has landed on an un-owned property, and can create a new "PlayerDecideToPurchaseProperty" action context that contains the index of the player we are waiting for a decision from. By the time the RollDice action has completed, our game state represents that it is currently waiting for the specified player to decide whether to buy a property is not. It is now easy for all other actions' IsLegal method to return false, except for the "BuyProperty" and "PassPropertyPurchaseOpportunity" actions, which are only legal when the game state has the "PlayerDecideToPurchaseProperty" action context.

Through the use of action contexts, there is never a single point in the life-time of the board game where the game state structure does not completely represent EXACTLY what is happening in the game at that point in time. This is a very desirable property of your board game system. It will it much easier for you to write code when you can find everything you ever want to know about what's happening in the game by examining only one structure.

Furthermore, it extends very nicely to networked environments, where clients can submit their actions over a network to a host machine, which can apply the action to the host's "official" game state, and then echo that action back to all the other clients to have them apply it to their replicated game states.

I hope this was concise and helpful.

其他推荐答案

The basic structure of your game engine uses the State Pattern. The items of your game box are singletons of various classes. The structure of each state may use Strategy Pattern or the Template Method.

A Factory is used to create the players which are inserted into a list of players, another singleton. The GUI will keep watch on the Game Engine by using the Observer pattern and interact with this by using one of several Command object created using the Command Pattern. The use of Observer and Command can be used with in the context of a Passive View But just about any MVP/MVC pattern could be used depending on your preferences. When you save the game you need to grab a memento of it's current state

I recommending looking over some of the patterns on this site and see if any of them grab you as a starting point. Again the heart of your game board is going to be a state machine. Most games will represented by two states pre-game/setup and the actual game. But you can had more states if the game you are modelling has several distinct modes of play. States don't have to be sequential for example the wargame Axis & Battles has a battle board the players can use to resolve battles. So there are three states pre-game, main board, battle board with the game continually switching between the main board and battle board. Of course the turn sequence can also be represented by a state machine.

其他推荐答案

I just finished designing and implementing a state based game using polymorphism.

Using a base abstract class called GamePhase that has one important method

abstract public GamePhase turn();

What this means is every GamePhase object holds the current state of the game, and a call to turn() looks at its current state and returns the next GamePhase.

Each concrete GamePhase has constructors that hold the entire game state. Each turn() method has a little bit of the game rules inside them. While this spreads the rules around, it keeps related rules close together. The end result of each turn() is just creating the next GamePhase and passing in the full state into the next phase.

This allows turn() to be very flexible. Depending on your game a given state can branch to many different types of phases. This forms a graph of all game phases.

At the highest level the code to drive it is very simple:

GamePhase state = ...initial phase
while(true) {
    // read the state, do some ui work
    state = state.turn();
}

This is extremely useful as I can now easily create any state/phase of the game for testing

Now to answer the second part of your question, how does this work in multiplayer? Within certain GamePhases that require user input, a call from turn() would ask the current Player their Strategy given the current state/phase. Strategy is just a interface of all the possible decisions a Player can make. This setup also allows Strategy to be implemented with AI!

Also Andrew Top said:

Your game can probably be in a (close to) infinite amount of states because of the permutations of things like how much money player A has, how much money player B has, and etc... Therefore, I'm pretty sure you want to stay away from state machines.

I think that statement is very misleading, while it is true that there are a lot of different game states, there are only a few game phases. To handle his example, all it would be is an integer parameter to the constructors of my concrete GamePhases.

Monopoly

Example of some GamePhases would be:

  • GameStarts
  • PlayerRolls
  • PlayerLandsOnProperty (FreeParking, GoToJail, Go, etc)
  • PlayerTrades
  • PlayerPurchasesProperty
  • PlayerPurchasesHouses
  • PlayerPurchasesHotels
  • PlayerPaysRent
  • PlayerBankrupts
  • (All Chance and Community Chest cards)

And some states in the base GamePhase are:

  • List of Players
  • Current Player (who's turn)
  • Player's Money/Property
  • Houses/Hotels on Properties
  • Player Position

And then some phases would record their own state as needed, for example PlayerRolls would record the number of times a player has roll consecutive doubles. Once we leave the PlayerRolls phase, we don't care about consecutive rolls anymore.

A lot of phases can be reused and linked together. For example the GamePhase CommunityChestAdvanceToGo would create the next phase PlayerLandsOnGo with the current state and return it. In the constructor of PlayerLandsOnGo the current player would be moved to Go and their money would be incremented by $200.