Выбрать главу

Теперь определим функцию 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 |

+----+----+----+----+