Вот как бы я разработал монополию. Я взял на себя смелость использовать язык с динамической типизацией, так как это делает все проще. Руби конкретно.
У вас есть простой Game
объект, который в основном является оберткой размером Array
размера 40, плюс несколько удобных методов. Объект 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
Карты Шанс и Сундук сообщества могут быть просто реализованы с помощью множества замыканий, которые принимают игру и объект игрока в качестве параметров. Например:
# 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!
, очевидно, обрабатывает такие вещи, как пассы.
Очевидно, есть еще детали - это довольно сложная игра, но, надеюсь, это даст вам правильное представление. Это было бы более чем достаточно для собеседования.
Обновление
Домашние правила можно включить или отключить, добавив 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