Теперь определим функцию shuffle1. Мы делаем ход в текущей позиции, который мы выбрали случай-
ным образом из списка доступных ходов. Выбором случайного элемента из списка, будет заниматься функция
randomElem, а функция nextMoves будет возвращать список доступных ходов для данного положения:
shuffle1 :: Game -> IO Game
shuffle1 g = flip move g <$> (randomElem $ nextMoves g)
randomElem :: [a] -> IO a
randomElem = un
nextMoves :: Game -> [Move]
nextMoves = un
Нам осталось определить всего две функции, и всё готово для игры. Определим выбор случайного эле-
мента из списка:
import System.Random
...
randomElem :: [a] -> IO a
randomElem xs = (xs !! ) <$> randomRIO (0, length xs - 1)
Мы генерируем случайное число в диапазоне индексов списка и затем извлекаем элемент. Теперь функ-
ция определения ходов в текущем положении:
nextMoves g = filter (within . moveEmptyTo . orient) allMoves
where moveEmptyTo v = shift v (emtyField g)
allMoves = [Up, Down, Left, Right]
Мы выполняем схожие операции с теми, что были в функции move. Мы фильтруем из списка всех ходов
те, что выводят пустую фишку за пределы доски.
212 | Глава 13: Поиграем
Отображение положения
Я немного поторопился, нам осталась ещё одна функция. Это отображение позиции. Я не буду подробно
останавливаться на теле функции, скажу лишь то, что она составляет строку так как это показано в коммен-
тарии к функции.
--
+----+----+----+----+
--
|
1 |
2 |
3 |
4 |
--
+----+----+----+----+
--
|
5 |
6 |
7 |
8 |
--
+----+----+----+----+
--
|
9 | 10 | 11 | 12 |
--
+----+----+----+----+
--
| 13 | 14 | 15 |
|
--
+----+----+----+----+
--
instance Show Game where
show (Game _ board) = ”\n” ++ space ++ line ++
(foldr (\a b -> a ++ space ++ line ++ b) ”\n” $ map column [0 .. 3])
where post id = showLabel $ board ! id
showLabel n
= cell $ show $ case n of
15 -> 0
n
-> n+1
cell ”0”
= ”
”
cell [x]
= ’ ’:’ ’: x :’ ’:[]
cell [a,b] = ’ ’: a : b :’ ’:[]
line = ”+----+----+----+----+\n”
nums = ((space ++ ”|”) ++ ) . foldr (\a b -> a ++ ”|” ++ b) ”\n” .
map post
column i = nums $ map (\x -> (i, x)) [0 .. 3]
space = ”\t”
Теперь мы можем загрузить модуль Loop в интерпретатор и набрать play. Немного отвлечёмся и поигра-
ем.
Prelude> :l Loop
[1 of 2] Compiling Game
( Game. hs, interpreted )
[2 of 2] Compiling Loop
( Loop. hs, interpreted )
Ok, modules loaded: Loop, Game.
*Loop> play
Привет! Это игра пятнашки
+----+----+----+----+
|
1 |
2 |
3 |
4 |
+----+----+----+----+
|
5 |
6 |
7 |
8 |
+----+----+----+----+
|
9 | 10 | 11 | 12 |
+----+----+----+----+
| 13 | 14 | 15 |
|
+----+----+----+----+
Возможные ходы пустой клетки:
left
или l
-- налево
right
или r
-- направо
up
или u
-- вверх
down
или d
-- вниз
Другие действия:
new int
или n int -- начать новую игру, int - целое число,
указывающее на сложность
quit
или q
-- выход из игры
Начнём новую игру?
Укажите сложность (положительное целое число):
5
+----+----+----+----+
|
1 |
2 |
3 |
4 |
+----+----+----+----+
|
5 |
6 |
7 |
8 |
+----+----+----+----+
Пятнашки | 213
|
9 |
| 10 | 11 |
+----+----+----+----+
| 13 | 14 | 15 | 12 |
+----+----+----+----+
Ваш ход:
r
+----+----+----+----+
|
1 |
2 |
3 |
4 |
+----+----+----+----+