5
\$\begingroup\$

Recently I started to learn Haskell. I did this by making exercises on the Internet. The problem of making these exercises is that I never know if I solved it the correct way. I currently wrote a function which I think looks really ugly, but I don't know how to improve it. I hope that someone could give me some tips to improve it.

In this exercice I need to make a tic-tac-toe-game. Wikipedia

The question of the function I wrote is as follows:

Write a function moves :: Player -> Board -> [Board] that, given the current player and the current state of the board, returns all possible moves that player can make expressed as a list of resulting boards. (For now, you should continue making moves, even if one of the players has already won.)

I wrote the following code:

data Field = X | O | B
    deriving (Eq, Ord)

instance Show Field where
    show X = "X|" :: String
    show O = "O|" :: String
    show B = " |" :: String

symbol :: Player -> Field
symbol P1 = X
symbol P2 = O

type Row   = (Field, Field, Field)
type Board = (Row, Row, Row)

I only want to improve this function: (Because the above code is part of bigger code)

moves :: Player -> Board -> [Board]
moves p ((a,b,c),(d,e,f), (g,h,i)) = (moves' a (((symbol p),b,c), (d,e,f), (g,h,i))) ++
                                     (moves' b ((a,(symbol p),c), (d,e,f), (g,h,i))) ++
                                     (moves' c ((a,b,(symbol p)), (d,e,f), (g,h,i))) ++
                                     (moves' d ((a,b,c), ((symbol p),e,f), (g,h,i))) ++
                                     (moves' e ((a,b,c), (d,(symbol p),f), (g,h,i))) ++
                                     (moves' f ((a,b,c), (d,e,(symbol p)), (g,h,i))) ++
                                     (moves' g ((a,b,c), (d,e,f), ((symbol p),h,i))) ++
                                     (moves' h ((a,b,c), (d,e,f), (g,(symbol p),i))) ++
                                     (moves' i ((a,b,c), (d,e,f), (g,h,(symbol p))))

moves' :: Field -> Board -> [Board]
moves' c m = if c == B then [m] else []

Is there a way to improve my code?

\$\endgroup\$
2
\$\begingroup\$

Your function suffer from the retained structure (tuples of tuples). Tuples were not thought to be searched in or to be examined using recursion.

By converting it to a List on the fly, you may work with recursion and all the functions working on Lists (map, fold, etc.).

Here’s an example:

import Data.Maybe (catMaybes)

boardToList :: Board -> [Field]
boardToList ((a,b,c), (d,e,f), (g,h,i)) = [a,b,c,d,e,f,g,h,i]

ListToBoard :: [Field] -> Board
ListToBoard [a,b,c,d,e,f,g,h,i] = ((a,b,c), (d,e,f), (g,h,i))
ListToBoard _ = undefined

moves :: Player -> Board -> [Board]
moves player board = map ListToBoard $ catMaybes [boardSet i | i <- [0..8]]
    where (new, lboard) = (symbol player, boardToList board)
          boardSet i = case splitAt i lboard of
                            (start, B:end) -> Just (start ++ [new] ++ end)
                            _              -> Nothing
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.