75 lines
3.4 KiB
Plaintext
75 lines
3.4 KiB
Plaintext
(function :GameState readState [file]
|
|
(let [lines (filter (Util.readLines file))
|
|
:Map<Int,Array<Board>> boardsByNumber (new Map)]
|
|
(objectWith
|
|
[
|
|
numbersToCall (map (.split (lines.shift) ",") Std.parseInt)
|
|
boards (for group (groups lines 5)
|
|
(let [numbers (map (apply concat (for line group (filter (line.split " ")))) Std.parseInt)
|
|
board (object
|
|
uncalled (for line (groups numbers 5) (for number line (Some number)))
|
|
called (for y (range 5) (for x (range 5) None))
|
|
won false)]
|
|
(doFor number numbers
|
|
(unless (boardsByNumber.exists number) (dictSet boardsByNumber number []))
|
|
(.push (dictGet boardsByNumber number) board))
|
|
board))
|
|
]
|
|
boardsByNumber)))
|
|
|
|
// Return true if the board wins as a result of the given number being called
|
|
(function :Bool stepBoard [:Board board numberCalled]
|
|
(doFor [y row] (enumerate board.uncalled)
|
|
(doFor [x square] (enumerate row)
|
|
(whenLet [(when (= numberCalled number) (Some number)) square]
|
|
(setNth row x None)
|
|
(setNth (nth board.called y) x (Some number)))))
|
|
(boardWon board))
|
|
|
|
(function :Bool boardWon [:Board board]
|
|
(let [:Array<Array<Option<Int>>> linesOfFive
|
|
(cast (concat
|
|
board.called
|
|
(for x (range 5) (for row board.called (nth row x)))))]
|
|
(doFor line linesOfFive
|
|
(let [&mut won true]
|
|
(doFor square line
|
|
(case square
|
|
(None (set won false) (break))
|
|
(otherwise)))
|
|
(when won (return true))))
|
|
(return false)))
|
|
|
|
// Return the winning score(s) when a board(s) win
|
|
(function :Null<Array<Int>> stepState [:GameState state]
|
|
// Keep returning the last score if there are no more numbers to call
|
|
(let [numberCalled (state.numbersToCall.shift)
|
|
winningScores []]
|
|
(when (state.boardsByNumber.exists numberCalled)
|
|
(doFor board (dictGet state.boardsByNumber numberCalled)
|
|
(unless board.won
|
|
(when (stepBoard board numberCalled)
|
|
(set board.won true)
|
|
(winningScores.push (boardScore board numberCalled))))))
|
|
winningScores))
|
|
|
|
(function :Int boardScore [:Board board numberCalled]
|
|
(* numberCalled (apply + (for row board.uncalled (apply + (for square row (case square ((Some v) v) (otherwise 0))))))))
|
|
|
|
(function winningScore [file]
|
|
(let [state (readState file)]
|
|
(loop
|
|
// Assume that for potential solutions to the AOC problem, only one board wins at a time.
|
|
(whenLet [[score] (stepState state)]
|
|
(return score))))
|
|
(throw ""))
|
|
|
|
(function lastWinningScore [file]
|
|
(let [state (readState file)
|
|
&mut finishedBoards 0]
|
|
(loop
|
|
(whenLet [winningScores (stepState state)]
|
|
(+= finishedBoards winningScores.length)
|
|
(when (= finishedBoards state.boards.length)
|
|
(return (first winningScores))))))
|
|
(throw "")) |