Я пытаюсь реализовать карточную игру Jass в Haskell и хотел бы сделать состояние игры как можно более явным или избегать невозможных состояний с типами.
В стандартном варианте участвуют четыре игрока. Игроки друг против друга образуют команду. В игре раунды играются до тех пор, пока одна команда не наберет целевой счет. В начале каждого раунда каждый игрок получает по 9 карт, один игрок выбирает козырь и ведет первый трюк. В фокусе каждый игрок должен разыграть одну карту. Карты сравниваются относительно главной масти и козыря, и игрок с самой высокой картой выигрывает. Очки трюков добавляются к счету команды победителя. Победитель также ведет на следующий трюк. В раунде играются трюки, пока у каждого игрока не осталось карт. Существует более подробное объяснение википедии и немецкое объяснение jassa.at .
Моя модель данных для игрока выглядит примерно так
data Player = Player
{ playerID :: PlayerID
, name :: String
, cards :: Set Card
, sendMessage :: Message -> IO ()
, receiveAction :: IO Action
}
таким образом, я могу просто использовать различные функции отправки и получения, например, для командной строки или сетевых игроков.
- Я хотел бы представить игру как конечный автомат с чистой функцией обновления, однако в большинстве штатов допустимо только одно действие только от одного игрока, и поэтому я думаю, что в функции обновления большая часть просто обрабатывает недопустимые входные данные.
Я не знаю, что будет лучший способ представить эти части игрового состояния.
Игроки.
- Моей первой идеей было использовать простой список и каждый раз вращать этот список, чтобы текущий игрок всегда был главой. Это легко сделать, но я также думаю, что легко что-то сделать go неправильно, например, что если список пуст, или есть только один игрок и так далее ...
- Использовать массив для игроки и использовать индекс для текущего игрока. Преимущество в том, что для перехода к следующему игроку мне просто нужно увеличить индекс. Где-то я должен использовать мод для циклического массива, но это не проблема. Я также попробовал это с XDataKinds, чтобы размер массива соответствовал уровню типа, и поэтому функция nextPlayer может управлять модом. Это также имеет то преимущество, что для команд я могу использовать только четные и нечетные индексы игроков. Но при этом я должен хранить дополнительную карту из playerID или индексировать карты игроков. Так что теперь массив и карта могут выйти из-под контроля c.
Трюк
Я не уверен, должен ли я хранить список сыгранных карт и кто играл их или просто запись с лидерством, наивысшей картой, победителем и достоинством сыгранных карт и отслеживание всех сыгранных карт в монаде писателя.
Раунды и хитрости
Это примерно одинаково для обоих, если я сохраню список со всеми сыгранными раундами и трюками или только текущий раунд и трюк и сохраню сумму очков из предыдущих раундов / трюков