OOD中的垄断游戏?
Posted
技术标签:
【中文标题】OOD中的垄断游戏?【英文标题】:Monopoly game in OOD? 【发布时间】:2011-06-02 08:29:50 【问题描述】:我通过 CodingHorror 发现了这篇有趣的博文:My Favorite Interview Question。简而言之,他谈到了设计大富翁游戏的面向对象设计挑战,重点是如何对游戏规则进行建模。例如,“如果玩家拥有波罗的海大道,她可以在其中添加房子吗?”
有趣的是,在帖子底部附近,他写道:
您或许可以为自己节省很多面试时间。而不是所有这些喧嚣,请候选人描述他们何时实际使用了框架之外的策略、访问者和命令模式。)
...这可能意味着您可以使用设计模式来模拟游戏规则(见上文)。有没有人这样做过?使用设计模式设计大富翁游戏?如果有,效果如何?
【问题讨论】:
【参考方案1】:这就是我设计 Monopoly 的方式。我冒昧地假设了一种动态类型的语言,因为这使一切变得更容易。特别是 Ruby。
你有一个简单的 Game
对象,它主要是一个大小为 40 的 Array
的包装器,以及一些方便的方法。 Game
对象还跟踪可用的houses
和hotels
的数量以及两叠机会卡和公益金卡。提供了一些方便的方法,如current_turn
和next_turn!
— 都返回一个Player
对象; next_turn!
增加转弯索引,必要时回绕到 0。
玩家可以登陆的所有位置都必须继承自 Property
的超类。 Property
类定义了一些常见的东西,例如 rent
、owner
、set
、houses
、purchasable?
和 upgradeable?
。 rent
和 owner
属性可能是 nil
。 set
属性返回包含组内所有属性的Array
。 set
属性的大小可能从 1 到 4 不等。houses
属性将酒店表示为 5 个“房屋”。
Game
对象有一个 Array
的 Player
对象,每个对象都有 position
(从 0 到 39 的整数)、money
(没有上限——银行从技术上讲永远不会“耗尽”)钱'),get_out_of_jail_frees
和 in_jail?
(因为位置不足以完成此操作)。 Game
对象也有一个索引来跟踪轮到谁了。
属性特定的规则都被编码在它们各自的子类中。因此,例如,rent
在Railroad
上的实现将是:
def rent
owned_count = self.set.select |rr| rr.owner == self.owner .size
return 25 * 2 ** (owned_count - 1)
end
Chance 和 Community Chest 卡可以简单地使用一堆闭包来实现,这些闭包将游戏和玩家对象作为参数。例如:
# Second place in a beauty contest
COMMUNITY_CHEST_CARDS << lambda do |game, player|
player.money += 10
end
# Advance token to Boardwalk
CHANCE_CARDS << lambda do |game, player|
game.advance_token!(player, 39)
end
# Advance token to nearest railroad, pay double
CHANCE_CARDS << lambda do |game, player|
new_position = [5, 15, 25, 35].detect do |p|
p > player.position
end || 5
game.advance_token!(player, new_position)
# Pay rent again, no-op if unowned
game.properties[new_position].pay_rent!(player)
end
等等。 advance_token!
方法显然可以处理诸如传递 go 之类的事情。
显然,还有更多细节——这是一个相当复杂的游戏,但希望这能给你正确的想法。面试肯定绰绰有余。
更新
可以通过将house_rules
Array
添加到Game
对象来打开或关闭房屋规则。这将允许像这样实现 FreeParking
属性:
class Game
def house_rules
@house_rules ||= []
end
def kitty
# Initialize the kitty to $500.
@kitty ||= 500
end
def kitty=(new_kitty)
@kitty = new_kitty
end
end
class FreeParking < Property
def rent
if self.game.house_rules.include?(:free_parking_kitty)
# Give the player the contents of the kitty, and then reset it to zero.
return -(_, self.game.kitty = self.game.kitty, 0)[0]
else
return 0
end
end
end
【讨论】:
哇!经过深思熟虑和构建。 如果我没看错的话,作者的主要关注点是几乎没有两个人按照相同的规则玩垄断,因为每个人都有不同的家规,他们习惯了。在您的架构中,更改规则集不会需要在许多不同的地方进行大量的小改动吗? 最常见的房屋规则——通过免费停车赚钱——可以通过为FreeParking
属性添加rent
方法的实现并返回一个负数来轻松实现。这是一个地方的一个小变化。您可以轻松添加分支逻辑来打开和关闭房屋规则。
更新了我的答案,提供了有关如何执行此操作的更多信息。
我认为使用 OP 链接中建议的一些模式的目的是避免做你所做的事情,即通过添加另一个属性来修改 Game 对象并显式修改 FreeParking 的rent 方法。基本上,您希望能够在不修改任何这些对象的情况下添加规则(开闭原则)。【参考方案2】:
我认为你在这里走错路了。
...which probably means that you can use design patterns to model the rules of the game (see above).
我认为这只是表明您并不真正了解设计模式是什么。已知的设计模式只是我们在编码时给经常出现的情况命名。在你的日常生活中,你永远不会说“我早上 8 点起床去早上 9 点放置 X,整天编程直到下午 5 点,所以他们在月底之前付钱给我”。你说,“今天我去上班了”。您有想赚钱的问题,并且该问题的反复解决方案将起作用。所以......我们在这里有一个模式!让我们称之为“工作”!
设计模式只是针对常见问题的一组经过研究的解决方案。这些解决方案中的每一个都有一个关联的名称(策略、访问者等)。
回来
...which probably means that you can use design patterns to model the rules of the game
这并不意味着您可以使用设计模式来模拟游戏规则,这意味着无论您在解决方案中做什么,它都可能会落入一些已知的设计模式。与必须从头开始描述所有内容相比,将您的解决方案视为一组相互关联的模式更容易。
【讨论】:
在哲学上是正确的,但实际上并不是那么简单。 DP 的主要挑战是在问题中识别它们并在解决方案中正确应用它们(在现实生活中相同,顺便说一句,当问题稍微不常见时“去工作”)。这个问题可能应该改写为“可以应用哪些已知的设计模式来简化这个问题的解决方案?” 这个问题可能应该改写为“可以应用哪些已知的设计模式来简化这个问题的解决方案?”我同意。只是在 SO 上看到人们对设计模式完全感到困惑是很常见的,就好像它们是目标(而不是达到目的的手段)..【参考方案3】:我从来没有设计过大富翁规则(太简单了,我想),但我曾涉足为其他知名游戏编写引擎以供个人娱乐,并理解所有这一切都是一项学术活动。
我尝试建模(并继续尝试)的两个游戏是D&D 和M:tG。
对于 D&D,重点是非常好的 OO 设计 - 使类和类层次结构有意义。
使用 M:tG,您基本上意识到直接的 OO 范式对于这类事情是不完整的。您最终会与代理、事件代理合作,并创建非常复杂的规则集。
除非您是游戏设计师,否则这一切都毫无意义。不过很好玩。
【讨论】:
以上是关于OOD中的垄断游戏?的主要内容,如果未能解决你的问题,请参考以下文章
域外动态||被欧盟处罚后,Steam又在美国被提起反垄断诉讼