Files
kiss-vscode/projects/aoc/src/year2021/day4.kiss

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 ""))