Я пытаюсь написать двух игроков в Haskell, например, шашки. Я предполагаю наличие типов GameState
, Move
и функцию result :: GameState -> Move -> GameState
, которая определяет правила игры. Я хочу иметь как человеческих, так и автоматизированных игроков, и я решил, что сделаю это, имея класс:
class Player p m | p -> m where
selectMove :: p -> GameState -> m Move
где идея заключалась бы в том, что m может быть Identity для базового игрока AI, IO для человека, состояния для ИИ, который поддерживает состояние через ходы и т.д. Вопрос заключается в том, как перейти от этого к общему игровому циклу. Я полагаю, что могу определить что-то вроде:
Player p1 m1, Player p2 m2 => moveList :: p1 -> p2 -> GameState -> m1 m2 [Move]
монадическая функция, которая принимает игроков и начальное состояние и возвращает ленивый список ходов. Но затем поверх этого пусть скажу, что мне нужен текстовый интерфейс, который, скажем, позволяет сначала выбрать каждого игрока из списка возможностей, а затем заставляет игру играть. Поэтому мне нужно:
playGame :: IO ()
Я не вижу, как определить playGame, заданный moveList, в общем виде. Или мой общий подход не прав?
EDIT: размышляя об этом, я даже не вижу, как определить moveList выше. Например, если игрок 1 был человеком, поэтому IO и игрок 2 были ИО с состоянием, поэтому State, первый ход игрока 1 имел бы тип IO Move
. Затем игроку 2 нужно было бы получить состояние типа IO GameState
и произвести перемещение типа State IO Move
, а следующий игрок 1 следующего типа будет иметь тип IO State IO Move
? Это не выглядит правильно.