52700.fb2
gameLoop :: Game -> IO ()
gameLoop game
| isGameOver game
= showResults game >> setup >>= gameLoop
| otherwise
= showGame game >> askForMove >>= reactOnMove game
showResults :: Game -> IO ()
showResults = un
showGame :: Game -> IO ()
showGame = un
Пятнашки | 205
askForMove :: IO Query
askForMove = un
reactOnMove :: Game -> Query -> IO ()
reactOnMove = un
-- в модуль Game
isGameOver :: Game -> Bool
isGameOver = un
Как определить закончилась игра или нет это скорее дело модуля Game. Все остальные функции принадле-
жат модулю Loop. Функция askForMove возвращает реплику пользователя и тут же направляет её в функцию
reactOnMove. Функции showGame и showResults ничего не возвращают, они только меняют состояния экрана.
После того как игра закончится мы предложим игроку начать новую.
Обратите внимание на то, как даже не дав определение функции, мы всё же очерчиваем её смысл в
объявлении типа. Так посмотрев на функцию askForMove и сопоставив тип с именем, мы можем понять, что
эта функция предназначена для запроса значения типа Query, для запроса реплики пользователя. А по типу
функции showGame мы можем понять, что она проводит какой-то побочный эффект, судя по имени что-то
показывает, из типа видно что показывает значение типа Game или текущую позицию.
Отображение позиции
Определим функции отображения результата и позиции. Когда игра закончится мы покажем итоговое
положение и объявим результат.
showResults :: Game -> IO ()
showResults g = showGame g >> putStrLn ”Игра окончена.”
Теперь определим функцию showGame. Если тип Game является экземпляром класса Show, то определение
окажется совсем простым:
-- в модуль Loop
showGame :: Game -> IO ()
showGame = putStrLn . show
-- в модуль Game
instance Show Game where
show = un
Реакция на реплики пользователя
Теперь нужно определить функции askForMove и reactOnMove. Первая функция требует установить про-
токол реплик пользователя, в каком виде он будет набирать значения типа Query. Нам пока лень об этом
думать и мы перейдём к функции reactOnMove. Вспомним её тип:
reactOnMove :: Game -> Query -> IO ()
Функция принимает текущее положение и запрос пользователя. И ничего не возвращает, она продолжает
игру. В любом случае в этой функции будет сопоставление с образцом по запросам пользователя так что
можно написать:
reactOnMove :: Game -> Query -> IO ()