2011-07-06 92 views
2

我刚刚有一个与设计模式有关的小问题。卡片游戏设计

考虑可以容纳Card对象的Player对象。

Player player1; 
Player player2; 
Player dealer; 

玩家可以互相给牌。是否有OO的方式来设计一个处理这个问题的方法?

player1.giveCard(Card, player2); 

玩家1可能会使用其他玩家的方法似乎不正确。有什么想法吗?例如,是否所有玩家都有一个名为getCard的方法?

Player::giveCard(Card card, Player player) { 
player.getCard(card) 

} 
+0

你可以做的一件事是为玩家创建getter和setter对象,并保持玩家类以外的逻辑 –

回答

1

关于面向对象方法的美妙的事情是,有无数种方式来抽象和设计相同的概念。问题是你想选择哪一个。

看来,在这种特定情况下,与你所描述的抽象你关注的是,PLAYER1需要使用player2的方法来完成目标。但是,我想改变您对方法的看法。

方法,一般来说,应想到的,首先,我们与世界的公共接口。另一方面,属性是我们保密并锁在我们的物体/头部/身体等内部的那些私人物品。

这是真的,很多编程语言有只用于内部使用私有和保护方法,但其实只是清理代码,以便我们的公共方法并不数百行的。

为了您的卡牌游戏,玩家可以得到一个卡通过任何其他对象,所以我会定义公共方法Player.giveCard(卡)。这是简单的部分,其他答案已经提到了这一点。

但问题变成了,这个方法里面会发生什么? 另外,该卡如何从原来的手中移除?

这里,我们可以做几件事情,而这个名单是不完整:

  1. 玩家只需与其他玩家互动。

在这种情况下,player1选择将card_589给予player2。所以,player1调用方法player2.giveCard(card_589)。在现实世界中,这将由玩家1身体上持有卡2以供玩家2采用。如果玩家2接受该卡,则玩家1不再拥有该卡,并且必须将其从他的手中移除。如果玩家2不接受它,则玩家1不会松开该卡,并将其放回他的手中。

为了建立这个模型,我们将制定一个简单的规则:giveCard方法返回一个布尔结果来指示player2是否接受卡片....在player1调用player2.giveCard()之后,他没有说明player2是否需要该卡,因为这是由player2决定的,在这种情况下。

我们的代码可能看起来像这样的地方里面PLAYER1的功能:

//begin pseudocode to give card to player identified by player2 
//let self refer to player1's own methods 
Player{ 
public giveCardToPlayer(player2, card_id){ 
    card = self.removeCardFromHand(card_id); 
    cardTaken = player2.giveCard(card); 
    if(cardTaken === false){ 
     self.addCardToHand(card); 
    } 
} 
//in the game management system, or elsewhere in player1's code, you then write 
player1.giveCardToPlayer(player2, card_587); 
//or, if in another method "player1.play()", for example: 
//self.giveCardToPlayer(player2, card_587) 
// 
//end pseudocode 

这是最简单的解决方案。这里,player1在player2的决策中没有看到card1是否被占用。玩家1选择在他交出卡之前从他自己的手中取出卡,因此卡不是同时在两个地方。如果玩家2没有拿到该卡,玩家1将其放回他的套牌中,但是否则什么都不做,因为该卡现在与玩家2。

就个人而言,这是抽象模型和我最喜欢的最简单的方法。

  • 玩家可以通过交互的一些中介
  • 这是我最喜欢的场景,当我们正在建模一个游戏,有某种延迟,例如在计算机网络仿真,或者通过邮件模拟一个国际象棋。玩家1将卡片邮寄给玩家2,但玩家2可能会或可能不会收到卡片。在这个游戏中,我们假设你有一张桌子,就像一张桌子一样,任何玩家都可以在自己和另一个玩家之间放置一张牌,这样只有其他玩家才能到达该牌。

    对于这种情况,我们将创建一个名为Table的新对象,虽然我们可以选择多种方式来抽象地将卡放置在桌子上,但我会选择这种方法作为公共可用的界面动作:

    Table.placeCardForUser(card, userId, myId, securityToken) : bool 
    Table.countCardsOnTableToUserFromUser(userId, myId, securityToken) : int 
    Table.pickUpCardToUser(userId, myId, securityToken) : Card[0..*] 
    Table.pickUpCardsToMe(myId, securityToken) : Card[0..*] 
    

    这会带来安全问题,因为我告诉,只有用户id可以拿起卡表,只有身份识别码可以验证和检索卡,所以表格对象需要一些方法来验证我(“当前对象”)有权访问由“userId”和“myId”标识的表上的位置,但也有很多解决方案。

    //begin psuedocode for current example 
    //we are in player1's function body 
    card = self.removeCardFromHand(card_587); 
    player2_id = self.identifyPlayerToReceive(card); 
    table.placeCardForUser(card, player2_id, myId, securityToken); 
    //end current action 
    
    //at next opportunity to act, check to see 
    //if card was taken 
    cardCount = table.countCardsOnTableToUserFromUser(userId, myId, securityToken); 
    if(cardCount > 1){ 
    //player2 has not taken card or other cards that have accumulated 
        pickUpCards = self.decideToPickUpCardsToPlayer(player2_id); 
        if(pickUpCards === true){ 
         cards = table.pickUpCardToUser(player2_id, myId, securityToken); 
         foreach(cards as card){ 
          self.addToHand(card); 
         } 
        } 
    } 
    //now check to see if anyone has given me cards between last round and this round 
    cards = table.pickUpCardsToMe(myId, securityToken); 
    foreach(cards as card){ 
        //let us assume that player1 takes all cards given to him 
        self.addToHand(card); 
    } 
    

    可以做出这种变化。你可以想象一下player1和player2之间的隧道。玩家1通过认识到他目前没有办法将牌给予玩家2并且因此创建隧道来建立隧道。他将一个隧道的副本给予player2,持有“另一端”,然后player2保留隧道的副本。就像桌子一样,这条隧道现在是一个可以让物品来回传递给玩家2的地方,但是因为只有玩家1和玩家2有通往隧道的链接或指针,只有这两个玩家可以将物品放入隧道或带走它们,因此,我们有一个不需要太多安全性的中介。我们可以创建隧道将所有球员与所有其他球员联系起来,这仍然是中间设计的变体。

  • 的自我意识的卡
  • 有时候,我们需要的是更容易的代码,而不是像现实设计。如果Player对象的代码忘记从他的手中删除卡对象,会发生什么情况?现在,因为对象通常是通过引用传递的,所以player2和player1每个都有对该卡片的引用,并且游戏模拟认为同一张卡片有两个副本!

    在这种情况下,我们可以设计卡片自我感知,并让卡片进入玩家的手中。

    对于这个抽象,我将显卡型号为这样:

    //begin pseudocode 
    Card{ 
        private owner; 
        //this is a private link to the object in which the card lies 
        //we will allow any object to be the owner of the card, as long 
        //as the object implements the "CardOwner" interface. 
    
        public putInto(newOwner){ 
        //whoever takes the card must specify a newOwner, which will 
        //implement the "CardHolder" interface. 
          success = newOwner.addCard(self); 
          if(success){ 
           self.owner.removeCard(self); 
           self.owner = newOwner; 
          } 
        } 
    } 
    

    然后,我们可以定义界面如下:

    //begin psuedocode 
    iCardHolder{ 
        public removeCard(card) : bool 
        public addCard(card) : bool 
    } 
    

    在这种情况下,我们从“闭门造车自己“通过让卡本身执行操作的能力。但是,这在有用的地方是在大型项目中,你不能相信其他程序员要记住卡片如何正确处理的细节。

    通过让卡控制指向谁的卡,我们可以确保在任何时候只有一张卡的副本存在,不管是谁在使用它。现在

    ,PLAYER1的代码可能是这样的:

    //give card to player2 
    card = self.chooseCard(); 
    player2.giveCard(card); 
    
    //put card on the floor 
    card = self.chooseCard(); 
    floor.giveCard(card); 
    
    //put card on the table 
    card = self.chooseCard(); 
    table.giveCard(card); 
    

    而且在每个对象,我们可以自由地改变我们收到的卡和我们保持它的方式。

    //player2 - is a simple CardHolder 
    public function giveCard(card){ 
        myHand = self; 
        card.putInto(myHand); 
    } 
    
    //the dealer is a cheat and does not implement CardHolder, 
    //but he has three locations that can act as CardHoldes 
    //they are: 
    // dealer.sleave, dealer.hand, and dealer.pocket 
    public function giveCard(card){ 
        location = self.chooseCardOwner([ sleeve, hand, pocket ]); 
        card.putInto(location); 
    } 
    
    //the floor has random piles that are accumulating 
    public function giveCard(card){ 
        pile = self.chooseRandomPile(); 
        card.putInto(pile); 
    } 
    

    这个选项是奇怪,但它给我们带来了很大的灵活性。在上面的例子中,Dealer和Floor甚至不是iCardHolder接口的实现者,但是它们持有对实现该接口的对象的引用,所以他们仍然可以获取该卡。

    在使用iCardHolder(与其他人完全不同)的每个实现中,代码非常简单,因为我们卸载了对卡片位置的操作并将此责任放在卡片本身上,并且所有卡片都关心关于与它交互的对象,同意一个合同的种类,并承诺实施一个removeCard方法和一个addCard方法。作为安全保障,卡片将当前所有者的副本保留在自己的记忆中,以便如果其中一个卡片持有者出现错误,卡片本身就会为其当前所有者提供答案。

    长话短说

    还有就是你的游戏模型中没有一个正确的方式。这完全是关于个人偏好,以及你希望系统如何运作。作为一名程序员,这是一件美丽的事情。作为进行代码设计的人员,您可以设置程序运行方式,以及什么是良好的对象交互以及什么是不良对象交互。

    0

    你需要知道该卡来自哪个玩家?

    此外,我会假设一个名为CardGame的对象将成为所有Player对象的持有者,并将对玩家进行所有调用,使得一个Player对象不会改变另一个Player对象的状态,但CardGame对象完成所有这些。

    因此,CardGame对象中,你会做出这样的呼叫:

    player1.giveCard(卡); player2.receiveCard(Card);

    +1

    感谢任务和cabanaboy。 CardGame对象包含Player和Card对象是有意义的,并且有一个像transferCard(Player1,Player2,Card) – Brian

    0

    我要说的是,一个球员有一个手和Hand.addCard(卡)和Hand.removeCard(卡)是方法在这里实现。

    游戏将处理从一名玩家中移除一张牌并将其送给下一位(通过那些手牌),因为游戏知道所有玩家对象,但玩家对象不一定需要彼此了解。

    +0

    'player2.getHand()。addCard(player1.getHand()。removeCard(card))的方法。 ;' –