Дизайн абстракции интерфейса

В настоящее время я пытаюсь написать небольшую игровую программу (Skat) в качестве хобби-проекта. Skat - это игра-хитрость, в которой два игрока играют против одного игрока. существуют разные типы плееров (локальный плеер, сетевой плеер, компьютер и т. д.), я хотел абстрагировать интерфейс для плеера.

Моя основная идея - использовать класс типов Player , который определяет всевозможные вещи, которые игрок должен делать и знать (разыгрывая карту, получать уведомления о том, кто выиграл уловку и т. д.). Затем вся игра выполняется функцией playSkat :: (Player a, Player b, Player c) => a -> b -> c -> IO () где a , b и c могут быть разными типами игроков. Затем игрок может отреагировать определенным в реализации способом. Локальный игрок получит какое-то сообщение на своем терминале, сетевой игрок может послать некоторую информацию по сети, а компьютерный игрок может вычислить новую стратегию.

Потому что игрок может захотеть выполнить некоторый ввод-вывод и определенно захотеть иметь какой-то государства, чтобы отслеживать личные вещи, он должен жить в какой-то Монаде. Итак, я подумал об определении класса Player следующим образом:

class Player p where
  playCard :: [Card] -> p -> IO (Card,p)
  notifyFoo :: Event -> p -> IO p
  ...

Этот шаблон, похоже, очень похож на преобразователь состояний, но я не уверен, как с этим справиться. Если бы я написал это как дополнительную монаду-преобразователь поверх ввода-вывода, у меня в конце концов было бы три разных монады. Как мне хорошо написать эту абстракцию?

Чтобы пояснить, что мне нужно, вот как должен выглядеть обычный поток управления:
При розыгрыше трюка первый игрок разыгрывает карту, затем второй и, наконец, третий. Для этого логика должна трижды выполнить функцию playCard для каждого игрока. После этого логика решает, какой игрок выиграет взятку, и отправляет информацию о том, кто выиграл, всем игрокам.

7
задан fuz 24 April 2011 в 15:32
поделиться