Nim в Haskell: рекурсивная функция для создания доски - PullRequest
3 голосов
/ 30 октября 2019

Я создаю игру под названием nim, используя haskell. Подводя итог короткой игре: позвонив nim с последующим номером до 9, я создаю игровое поле для игры:

>> nim 3
1 *
2 * *
3 * * *
  1 2 3

Это работает так, как должно. Игра идет следующим образом: Вы можете удалить любое количество звезд из любой строки, но вы должны удалить как минимум 1 звезду. Вы не можете удалить звезды из ряда 1 и 2 в один и тот же ход. Человек, чтобы удалить последнюю звезду, побеждает.

Хорошо, так что игра играет должным образом, но возникает проблема, когда я печатаю доску после каждого хода.

Допустим, у меня есть доска выше, и выдается ввод для удаления1 1 (убрать 1 звезду из строки 1)

Вот что я получаю:

0 
2 * *
3 * * *
  1 2 3

0 все равно должно быть 1.

Это мои функции, отвечающие запечать доски putRow принимает номер строки и количество звездочек. Эти два аргумента совпадают, но мне не повезло с изменением функции, чтобы принимать только 1.

putBoard берет в списке, который представляет доску для игры. putBoard [1,2,3] создает доску из игры выше. Я запускаю putStr в первом элементе, а затем рекурсивно вызываю putRow в оставшейся части списка.

putRow :: Int -> Int -> IO ()
putRow row num = do putStr (show row)
                    putStr " "
                    putStrLn (concat (replicate num "* "))

putBoard :: Board -> IO ()
putBoard (x:xs) =    putRow x x >> putBoard xs
putBoard [] = putStr " 1 2 3"

putBoard [] будет заменен позже, чтобы создать номера столбцов под доской, но это будет позже. На данный момент это просто строка, которая работает только с игрой с размером доски 3.

Это функция, которая обрабатывает движения, когда задан ряд и количество звездочек

move :: Board -> Int -> Int -> Board
move board row num = [update r n | (r, n) <- zip [1..] board]
   where update r n = if r == row then (n - num) else n

1 Ответ

4 голосов
/ 30 октября 2019

Ваша функция putRow принимает два аргумента: номер строки row и количество звезд в этой строке num.

Когда вы вызываете эту функцию из putBoard, выпрохождение одного и того же x для row и num

putRow x x

Так что неудивительно, что число, напечатанное слева, соответствует количеству звезд!

Что вам нужнодля этого нужно передать x (то есть количество звезд) для num, но передать фактический индекс строки для row:

putRow idx x

Но где взять idx? Что ж, давайте посмотрим: в первый раз, когда вы позвоните putBoard, idx будет 1. И затем каждый раз, когда вы вызываете putBoard рекурсивно - это будет печать следующей строки, поэтому idx должно увеличиваться на единицу. Давайте запишем это:

putBoard :: Int -> Board -> IO ()
putBoard idx (x:xs) = putRow idx x >> putBoard (idx+1) xs
putBoard idx [] = putStr " 1 2 3"

Но теперь тот, кто звонит putBoard, должен предоставить начальную 1:

putBoard 1 board

Это немного неудобно, так что вы можете обернуть этово внутренней функции, как это:

putBoard :: Board -> IO ()
putBoard = go 1
  where
    go idx (x:xs) = putRow idx x >> go (idx+1) xs
    go idx [] = putStr " 1 2 3"
...