Читаем Учебник по Haskell полностью

нам не удастся, мы напомним пользователю как с нами общаться (remindMoves) и попросим сходить вновь:

askForMove :: IO Query

askForMove = showAsk >>

getLine >>= maybe askAgain return . parseQuery

where askAgain = wrongMove >> askForMove

parseQuery :: String -> Maybe Query

parseQuery = un

wrongMove :: IO ()

wrongMove = putStrLn ”Не могу распознать ход.” >> remindMoves

showAsk :: IO ()

showAsk = un

remindMoves :: IO ()

remindMoves = un

Механизм распознавания похож на случай с распознаванием числа. Значение завёрнуто в тип Maybe. И в

самом деле функция определена лишь частично, ведь не все строки кодируют то, что нам нужно.

Функции parseQuery и remindMoves тесно связаны. В первой мы распознаём ввод пользователя, а во вто-

рой напоминаем пользователю как мы закодировали его запросы. Тут стоит остановиться и серьёзно поду-

мать. Как закодировать значения типа Query, чтобы пользователю было удобно набирать их? Но давайте

отвлечёмся от этой задачи, она слишком серьёзная. Оставим её на потом, а пока проверим не ушли ли мы

слишком далеко, возможно наша программа потеряла смысл. Проверим типы!

*Loop> :r

[1 of 2] Compiling Game

( Game. hs, interpreted )

[2 of 2] Compiling Loop

( Loop. hs, interpreted )

Ok, modules loaded: Game, Loop.

Пятнашки | 207

Приведём код в порядок

Нам осталось дописать функции распознавания запросов и несколько маленьких функций с фразами и

модуль Loop будет готов. Но перед тем как сделать это давайте упорядочим функции. Видно, что у нас выде-

лилось несколько задач по типу общения с пользователем. У нас есть задачи, в которых мы что-то показываем

пользователю, меняем состояние экрана и есть задачи, в которых мы просим от пользователя какие-то дан-

ные, ожидаем запросы функцией getLine. Также в самом верху выражения программы у нас расположены

функции, которые координируют действия остальных, это третья группа. Сгруппируем функции по этому

принципу.

Основные функции

play :: IO ()

play = greetings >> setup >>= gameLoop

gameLoop :: Game -> IO ()

gameLoop game

| isGameOver game

= showResults game >> setup >>= gameLoop

| otherwise

= showGame game >> askForMove >>= reactOnMove game

setup :: IO Game

setup = putStrLn ”Начнём новую игру?” >>

putStrLn ”Укажите сложность (положительное целое число): ” >>

getLine >>= maybe setup shuffle . readInt

Запросы от пользователя (getLine)

reactOnMove :: Game -> Query -> IO ()

reactOnMove game query = case query of

Quit

-> quit

NewGame n

-> gameLoop =<< shuffle n

Play

m

-> gameLoop $ move m game

askForMove :: IO Query

askForMove = showAsk >>

getLine >>= maybe askAgain return . parseQuery

where askAgain = wrongMove >> askForMove

parseQuery :: String -> Maybe Query

parseQuery = un

readInt :: String -> Maybe Int

readInt = un

Ответы пользователю (putStrLn)

greetings :: IO ()

greetings = un

showResults :: Game -> IO ()

showResults g = showGame g >> putStrLn ”Игра окончена.”

showGame :: Game -> IO ()

showGame = putStrLn . show

showAsk :: IO ()

showAsk = un

quit :: IO ()

quit = putStrLn ”До встречи.” >> return ()

По этим функциям видно, что нам немного осталось. Теперь вернёмся к запросам пользователя.

Формат запросов

Можно вывести с помощью deriving экземпляр класса Read для типа Query и читать их функцией read.

Но это плохая идея, потому что пользователь нашей программы может и не знать Haskell. Лучше введём

сокращённые имена для всех значений. Например такие:

208 | Глава 13: Поиграем

left

-- Play Left

right

-- Play Rigth

up

-- Play Up

down

-- Play Down

quit

-- Quit

new n

-- NewGame n

Можно обратить внимание на то, что все команды начинаются с разных букв. Воспользуемся этим и дадим

пользователю возможность набирать команды одной буквой. Это приводит на с к таким определениям для

функций разбора значения и напоминания ходов:

parseQuery :: String -> Maybe Query

parseQuery x = case x of

”up”

-> Just $ Play Up

”u”

-> Just $ Play Up

”down”

-> Just $ Play Down

”d”

-> Just $ Play Down

”left”

-> Just $ Play Left

”l”

-> Just $ Play Left

”right” -> Just $ Play Right

”r”

-> Just $ Play Right

”quit”

-> Just $ Quit

”q”

-> Just $ Quit

’n’:’e’:’w’:’ ’:n

-> Just . NewGame =<< readInt n

’n’:’ ’:n

-> Just . NewGame =<< readInt n

_

-> Nothing

remindMoves :: IO ()

remindMoves = mapM_ putStrLn talk

where talk = [

”Возможные ходы пустой клетки:”,

left

или l

-- налево”,

right

или r

-- направо”,

up

или u

-- вверх”,

down

или d

-- вниз”,

”Другие действия:”,

new int

или n int -- начать новую игру, int - целое число,”,

”указывающее на сложность”,

quit

или q

-- выход из игры”]

Проверим работоспособность:

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных