Reputation: 316
I'm creating a game called nim using haskell. To summarize the game short: By calling nim followed by a number up to to 9 I create the board for the game:
>> nim 3
1 *
2 * *
3 * * *
1 2 3
This is working as it should. The game goes as follows: You can remove any number of stars fro any row, but you have to remove at least 1 star. You cannot remove stars from row 1 and 2 in the same turn. Person to remove last star wins.
Okay, so the game plays as it should, but a problem occurs when I'm printing the board after each turn.
Let's say I have the board above, and give input to remove 1 1 (remove 1 star from row 1)
This is what I get:
0
2 * *
3 * * *
1 2 3
The 0 should still be 1.
These are my functions responsible for printing the board
putRow
takes in the row number and the number of stars. These two arguments are the same but I had no luck with changing the function to only accept 1.
putBoard
takes in the list that represents the board for the game. putBoard [1,2,3] creates the board from the game above. I runs putStr in the first element and then recursively calls putRow in the remainder of the list.
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 []
is going to be replaced later to create column numbers under the board, but thats for later. For now its just a string that only works with game with boardsize 3.
This is the function that handles moves when row and number of stars is specified
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
Upvotes: 3
Views: 935
Reputation: 80744
Your function putRow
takes two arguments: the row number row
, and the number of stars in that row num
.
When you call that function from putBoard
, you're passing the same x
for both row
and num
putRow x x
So it's no wonder that the number printed to the left matches the number of stars!
What you need to do is pass x
(which is the number of stars) for num
, but pass the actual index of the row for row
:
putRow idx x
But where to get the idx
? Well, let's see: the first time you call putBoard
, idx
would be 1
. And then every time you call putBoard
recursively - that would be printing the next row, so idx
should get incremented by one. Let's write that down:
putBoard :: Int -> Board -> IO ()
putBoard idx (x:xs) = putRow idx x >> putBoard (idx+1) xs
putBoard idx [] = putStr " 1 2 3"
But now whoever calls putBoard
has to provide the initial 1
:
putBoard 1 board
That's a bit inconvenient, so you can wrap that up in an inner function like this:
putBoard :: Board -> IO ()
putBoard = go 1
where
go idx (x:xs) = putRow idx x >> go (idx+1) xs
go idx [] = putStr " 1 2 3"
Upvotes: 4