The current functions to calculate game wins are quite difficult to read and harder to debug and understand.
This function returns a list of lists and should be refactored to make the win state clearer
boardToWinnableCells : CellBoard -> List (List Cell)
boardToWinnableCells board =
let
isCellEmpty { cellstate } =
cellstate == EmptyCell
in
[ [ board.a1, board.a2, board.a3, board.a4 ] -- column A
, [ board.b1, board.b2, board.b3, board.b4 ] -- column B
, [ board.c1, board.c2, board.c3, board.c4 ] -- column C
, [ board.d1, board.d2, board.d3, board.d4 ] -- column D
, [ board.a1, board.b1, board.c1, board.d1 ] -- row 1
, [ board.a2, board.b2, board.c2, board.d2 ] -- row 2
, [ board.a3, board.b3, board.c3, board.d3 ] -- row 3
, [ board.a4, board.b4, board.c4, board.d4 ] -- row 4
, [ board.a1, board.b2, board.c3, board.d4 ] -- back slash diagonal
, [ board.a4, board.b3, board.c2, board.d1 ] -- forward slash diagonal
]
|> List.filter (List.all isCellEmpty)
This function actually calculates the wins but that's not clear from the types or the logic
matchingDimensions : List Gamepiece -> Bool
matchingDimensions gamepieces =
gamepieces
-- convert from list of game pieces to sets of strings
|> List.map (gamepieceToList >> Set.fromList)
-- { "Circle", "Filled", "Colour1, ""Large"}
-- interset the sets to make one set of common values
|> Liste.foldl1 Set.intersect
-- convert from Maybe set to set
|> Maybe.withDefault Set.empty
-- return True is set isn't empty, false if it is
|> not
<< Set.isEmpty
This top level function puts the other two together but that gets lost in all the transformations. Again, very hard to follow logic.
isWin : CellBoard -> Bool
isWin board =
board
-- turn a board to list of lists of game winning cells
|> boardToWinnableCells
-- strip cell names
|> List.map (List.map (\{ cellstate } -> cellstate))
-- convert cells to gamepieces and filter out cells that dont have gamepieces in them
|> List.map (List.map cellstateToMaybe)
|> List.map (List.filterMap identity)
-- filter out those that aren't filled in
|> List.filter (\x -> List.length x >= 4)
-- turn to list of booleans on if cells have matches
|> List.map matchingDimensions
-- filter out false values
|> List.filter identity
-- if any values remain, return bool
|> not
<< List.isEmpty
Let's use types to clear up the logic slightly.