— Nim example from chapter 10 of Programming in Haskell,
— , Cambridge University Press, 2016.
import Data.Char
— Game utilities
next :: Int -> Int
next 1 = 2
next 2 = 1
type Board = [Int]
initial :: Board
initial = [5,4,3,2,1]
finished :: Board -> Bool
finished = all (== 0)
valid :: Board -> Int -> Int -> Bool
valid board row num = board !! (row-1) >= num
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
-- IO utilities
putRow :: Int -> Int -> IO ()
putRow row num = do putStr (show row)
putStr “: ”
putStrLn (concat (replicate num “* “))
putBoard :: Board -> IO ()
putBoard [a,b,c,d,e] = do putRow 1 a
putRow 2 b
putRow 3 c
putRow 4 d
putRow 5 e
getDigit :: String -> IO Int
getDigit prompt = do putStr prompt
x <- getChar
newline
if isDigit x then
return (digitToInt x)
else
do putStrLn "ERROR: Invalid digit"
getDigit prompt
newline :: IO ()
newline = putChar '\n'
-- Game of nim
play :: Board -> Int -> IO ()
play board player =
do newline
putBoard board
if finished board then
do newline
putStr “Player ”
putStr (show (next player))
putStrLn ” wins!!”
else
do newline
putStr “Player ”
putStrLn (show player)
row <- getDigit "Enter a row number: "
num <- getDigit "Stars to remove : "
if valid board row num then
play (move board row num) (next player)
else
do newline
putStrLn "ERROR: Invalid move"
play board player
nim :: IO ()
nim = play initial 1