You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('') and can be up to 35 characters long.


#lang racket
; util
(define (spliton lst x) ; like splitOn in haskell. couldn't find this in the std lib.. (foldr (λ (element next)
(if (equal? element x)
(cons empty next)
(cons (cons element (first next)) (rest next))))
(list empty) lst))
(define (mapmap f lst) ; why tf can't i do (compose map map) (map (λ (x) (map (λ (y) (f y)) x)) lst))
(define (mapmapmap f lst) ; (map . map . map) (map (λ (x) (mapmap f x)) lst))
(define (transpose xss)
(apply map list xss))
(define (all? f list)
(not (findf (λ (x) (not (f x))) list)))
; IO and setup
(define lines
(file>lines "day4.txt"))
(define numbers ; grab first line of file, split into a list on , (map string>number (stringsplit (first lines) ",")))
(define boards
(let* ([strlists (spliton (drop lines 2) "")] ; split on empty lines [splitup (mapmap stringsplit strlists)] ; convert '("1 2 3") to '("1" "2" "3") [numlists (mapmapmap string>number splitup)]) ; convert '("1" "2" "3") to '(1 2 3) (mapmapmap (λ (x) (cons x #f)) numlists))); change each cell to (<number>, <picked>)
; part 1
(define (markboard board number) ; mark up a board with #t or #f based on the number (mapmap (λ (cell)
(match cell
[(cons num on) (cons num (or on (= num number)))]))
board))
(define (markboards boards number) ; mark all boards based on the number (map (λ (board) (markboard board number)) boards))
(define (allwinners? lst) ; check if all pairs in the list are #t (all? cdr lst))
(define (iswinner? board) ; check if any row or column in the board is a winner (let ([cols (transpose board)])
(or
(findf allwinners? board)
(findf allwinners? cols))))
(define (markalluntilwin boards numbers)
(foldl (λ (number acc)
(match acc
([cons boards lastnumber]
(if (findf iswinner? boards) ; if we have any winners (cons boards lastnumber) ; just return the boards (cons (markboards boards number) number))))) ; otherwise keep marking (cons boards 0) numbers))
(define (sumunmarked board)
(let* ([cells (apply append board)] ; flatten it [unmarked (filter (λ (x) (not (cdr x))) cells)] ; filter out marked cells [nums (map car unmarked)])
(foldl + 0 nums)))
(define part1
(let* ([markedup (markalluntilwin boards numbers)] ; get (the final board state . last number) [markedboards (car markedup)] ; car out the boards [lastnumber (cdr markedup)] ; cdr out the last number [winningboard (findf iswinner? markedboards)] ; find the winning board [unmarkedsum (sumunmarked winningboard)]) ; sum up the unmarked cells (* unmarkedsum lastnumber)))
part1
; part 2
(define (markalluntilone boards numbers)
(foldl (λ (number acc)
(match acc
([cons boards lastnumber]
(if (= (length boards) 1) ; if we have only have 1 board left (cons boards lastnumber) ; just return it (let ([filteredboards (filter (λ (x) (not (iswinner? x))) boards)]) ; otherwise filter out the winners (cons (markboards filteredboards number) number)))))) ; and then keep marking (cons boards 0) numbers))
(define part2
(let* ([markedup (markalluntilone boards numbers)] ; get (the final board state . last number) [markedboards (car markedup)] ; car out the boards [lastnumber (cdr markedup)] ; cdr out the last number [winningboard (findf iswinner? markedboards)] ; find the winning board [unmarkedsum (sumunmarked winningboard)]) ; sum up the unmarked cells (* unmarkedsum lastnumber)))
part2
