solved day8 and improved submitting answers
This commit is contained in:
parent
f5b144ce21
commit
f7bda050dd
5 changed files with 234 additions and 32 deletions
2
aoc.asd
2
aoc.asd
|
@ -31,6 +31,7 @@
|
||||||
(:file "2024/day05")
|
(:file "2024/day05")
|
||||||
(:file "2024/day06")
|
(:file "2024/day06")
|
||||||
(:file "2024/day07")
|
(:file "2024/day07")
|
||||||
|
(:file "2024/day08")
|
||||||
)))
|
)))
|
||||||
:description "Advent of Code challenges and solutions."
|
:description "Advent of Code challenges and solutions."
|
||||||
:long-description "Solutions for the AOC challenges."
|
:long-description "Solutions for the AOC challenges."
|
||||||
|
@ -54,6 +55,7 @@
|
||||||
(:file "2024/day05-test")
|
(:file "2024/day05-test")
|
||||||
(:file "2024/day06-test")
|
(:file "2024/day06-test")
|
||||||
(:file "2024/day07-test")
|
(:file "2024/day07-test")
|
||||||
|
(:file "2024/day08-test")
|
||||||
)))
|
)))
|
||||||
:description "Test system for aoc"
|
:description "Test system for aoc"
|
||||||
:perform (test-op (op c) (symbol-call :parachute :test :aoc/tests)))
|
:perform (test-op (op c) (symbol-call :parachute :test :aoc/tests)))
|
||||||
|
|
|
@ -51,19 +51,21 @@
|
||||||
|
|
||||||
|
|
||||||
(defun mul-branch (equation)
|
(defun mul-branch (equation)
|
||||||
|
"returns simplified equation after applying the * operator or nil if not possible"
|
||||||
(let ((r (equation-result equation))
|
(let ((r (equation-result equation))
|
||||||
(os (equation-operands equation)))
|
(os (equation-operands equation)))
|
||||||
(if (= (gcd r (first os)) (first os))
|
(and (= (gcd r (first os)) (first os))
|
||||||
(make-equation :result (/ r (first os)) :operands (cdr os))
|
(make-equation :result (/ r (first os)) :operands (cdr os)))))
|
||||||
nil)))
|
|
||||||
|
|
||||||
(defun plus-branch (equation)
|
(defun plus-branch (equation)
|
||||||
|
"returns simplified equation after applying the + operator or nil if not possible"
|
||||||
(let ((r (equation-result equation))
|
(let ((r (equation-result equation))
|
||||||
(os (equation-operands equation)))
|
(os (equation-operands equation)))
|
||||||
(if (>= r(first os))
|
(and (>= r(first os))
|
||||||
(make-equation :result (- r (first os)) :operands (cdr os)))))
|
(make-equation :result (- r (first os)) :operands (cdr os)))))
|
||||||
|
|
||||||
(defun solvedp (equation)
|
(defun solvedp (equation)
|
||||||
|
"returns true if equation has been solved"
|
||||||
(let ((r (equation-result equation))
|
(let ((r (equation-result equation))
|
||||||
(os (equation-operands equation)))
|
(os (equation-operands equation)))
|
||||||
(and
|
(and
|
||||||
|
@ -71,6 +73,7 @@
|
||||||
(= r (first os)))))
|
(= r (first os)))))
|
||||||
|
|
||||||
(defun valid-equation (equation)
|
(defun valid-equation (equation)
|
||||||
|
"recursively determine if the equation is valid"
|
||||||
(if (equation-operands equation)
|
(if (equation-operands equation)
|
||||||
(let ((mb (mul-branch equation))
|
(let ((mb (mul-branch equation))
|
||||||
(pb (plus-branch equation)))
|
(pb (plus-branch equation)))
|
||||||
|
@ -80,7 +83,6 @@
|
||||||
(and pb (valid-equation pb))))
|
(and pb (valid-equation pb))))
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
|
|
||||||
(defun sum-valid-eqs (eqs)
|
(defun sum-valid-eqs (eqs)
|
||||||
(loop
|
(loop
|
||||||
for eq in eqs
|
for eq in eqs
|
||||||
|
|
165
src/2024/day08.lisp
Normal file
165
src/2024/day08.lisp
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
(defpackage :aoc/2024/08
|
||||||
|
(:use :cl :aoc :alexandria :trivia :lla)
|
||||||
|
(:export
|
||||||
|
#:sample-data
|
||||||
|
#:sample-data2
|
||||||
|
#:part1
|
||||||
|
#:part2
|
||||||
|
))
|
||||||
|
|
||||||
|
(in-package :aoc/2024/08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;; a frequency node represents a location on the map
|
||||||
|
;; associated to a frequence, like an antenna or antinode
|
||||||
|
(defstruct frequency-node frequency position)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defun parse-line (line)
|
||||||
|
"return an equation with the result and the operands in reverse order as in the text"
|
||||||
|
(loop
|
||||||
|
for x from 0 to (1- (length line))
|
||||||
|
for c = (aref line x)
|
||||||
|
if (not (or (eq c #\.) (eq c #\#)))
|
||||||
|
collect (list x c)))
|
||||||
|
|
||||||
|
(defstruct antenna-map bounds antennas)
|
||||||
|
|
||||||
|
(defun parse-input (lines)
|
||||||
|
(make-antenna-map
|
||||||
|
:bounds
|
||||||
|
(vector (length (first lines)) (length lines))
|
||||||
|
:antennas
|
||||||
|
(loop for y from 0 to (1- (length lines))
|
||||||
|
for line in lines
|
||||||
|
append (mapcar (lambda (a)
|
||||||
|
(make-frequency-node
|
||||||
|
:position (vector (first a) y)
|
||||||
|
:frequency (second a)))
|
||||||
|
(parse-line line)))))
|
||||||
|
|
||||||
|
(defparameter input-text (test-input 2024 8))
|
||||||
|
(defparameter input-data (parse-input input-text))
|
||||||
|
|
||||||
|
(defparameter sample-text (aoc:split-lines "............
|
||||||
|
........0...
|
||||||
|
.....0......
|
||||||
|
.......0....
|
||||||
|
....0.......
|
||||||
|
......A.....
|
||||||
|
............
|
||||||
|
............
|
||||||
|
........A...
|
||||||
|
.........A..
|
||||||
|
............
|
||||||
|
............"))
|
||||||
|
|
||||||
|
(defparameter sample-data
|
||||||
|
(parse-input sample-text))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defun antinode (ant1 ant2)
|
||||||
|
(and
|
||||||
|
(eq (frequency-node-frequency ant1) (frequency-node-frequency ant2))
|
||||||
|
(make-frequency-node
|
||||||
|
:frequency (frequency-node-frequency ant1)
|
||||||
|
:position (aops:each
|
||||||
|
(lambda (a b) (- (* 2 b) a))
|
||||||
|
(frequency-node-position ant1)
|
||||||
|
(frequency-node-position ant2)
|
||||||
|
))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun group-by-frequency (fnodes)
|
||||||
|
(let ((groups (make-hash-table :test #'eq)))
|
||||||
|
(loop for n in fnodes
|
||||||
|
do (push n (gethash (frequency-node-frequency n) groups)))
|
||||||
|
groups))
|
||||||
|
|
||||||
|
(defun fnode-in-boundsp (map fnode)
|
||||||
|
(loop for x across (frequency-node-position fnode)
|
||||||
|
for bound across (antenna-map-bounds map)
|
||||||
|
always (< -1 x bound))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun antennas-antinodes (antennas)
|
||||||
|
(loop for a1 in antennas
|
||||||
|
append (loop for a2 in antennas
|
||||||
|
if (not (eq a1 a2))
|
||||||
|
collect (antinode a1 a2))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun count-antinodes (map)
|
||||||
|
(let ((antennas-by-f (group-by-frequency (antenna-map-antennas map)))
|
||||||
|
(antinode-map (make-hash-table :test #'equalp))
|
||||||
|
)
|
||||||
|
(loop
|
||||||
|
for antennas being the hash-values of antennas-by-f
|
||||||
|
do (loop for n in (antennas-antinodes antennas)
|
||||||
|
if (and n (fnode-in-boundsp map n))
|
||||||
|
do (incf (gethash (frequency-node-position n) antinode-map 0))))
|
||||||
|
(length (hash-table-keys antinode-map)))
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
(defparameter sample-data2 (parse-input (aoc:split-lines "T....#....
|
||||||
|
...T......
|
||||||
|
.T....#...
|
||||||
|
.........#
|
||||||
|
..#.......
|
||||||
|
..........
|
||||||
|
...#......
|
||||||
|
..........
|
||||||
|
....#.....
|
||||||
|
..........
|
||||||
|
")))
|
||||||
|
|
||||||
|
(defun resonant-nodes (map ant1 ant2)
|
||||||
|
(unless
|
||||||
|
(or (equalp ant1 ant2)
|
||||||
|
(not (equal
|
||||||
|
(frequency-node-frequency ant1)
|
||||||
|
(frequency-node-frequency ant2))))
|
||||||
|
(loop for i from 1
|
||||||
|
for fn = (make-frequency-node
|
||||||
|
:frequency (frequency-node-frequency ant1)
|
||||||
|
:position (aops:each
|
||||||
|
(lambda (a b) (+ a (* i (- b a))))
|
||||||
|
(frequency-node-position ant1)
|
||||||
|
(frequency-node-position ant2)))
|
||||||
|
while (fnode-in-boundsp map fn)
|
||||||
|
collect fn)))
|
||||||
|
|
||||||
|
(defun antennas-resonant-nodes (map antennas)
|
||||||
|
(loop for a1 in antennas
|
||||||
|
append (loop for a2 in antennas
|
||||||
|
append (resonant-nodes map a1 a2))))
|
||||||
|
|
||||||
|
(defun count-resonant-nodes (map)
|
||||||
|
(let ((antennas-by-f (group-by-frequency (antenna-map-antennas map)))
|
||||||
|
(resonant-node-map (make-hash-table :test #'equalp))
|
||||||
|
)
|
||||||
|
(loop
|
||||||
|
for antennas being the hash-values of antennas-by-f
|
||||||
|
do (loop for n in (antennas-resonant-nodes map antennas)
|
||||||
|
if (fnode-in-boundsp map n)
|
||||||
|
do (incf (gethash (frequency-node-position n) resonant-node-map 0))))
|
||||||
|
(length (hash-table-keys resonant-node-map)))
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun part1 (data)
|
||||||
|
(format nil "~A" (count-antinodes data)))
|
||||||
|
|
||||||
|
(defun part2 (data)
|
||||||
|
(format nil "~A" (count-resonant-nodes data)))
|
||||||
|
|
||||||
|
(defun solve-day ()
|
||||||
|
(format t "part1: ~A~%" (part1 input-data))
|
||||||
|
(format t "part2: ~A~%" (part2 input-data)))
|
|
@ -8,26 +8,13 @@
|
||||||
#:clear-data-cache))
|
#:clear-data-cache))
|
||||||
|
|
||||||
(in-package :aoc)
|
(in-package :aoc)
|
||||||
|
|
||||||
(defun load-ql-dependencies ()
|
(defun load-ql-dependencies ()
|
||||||
())
|
())
|
||||||
|
|
||||||
|
(defparameter *aoc-url* "https://adventofcode.com")
|
||||||
(defvar *aoc-url* "https://adventofcode.com")
|
|
||||||
|
|
||||||
|
|
||||||
(defvar *cookie-jar*
|
(defparameter *cookie-jar*
|
||||||
(cl-cookie:make-cookie-jar
|
|
||||||
:cookies (list
|
|
||||||
(cl-cookie:make-cookie
|
|
||||||
:name "session"
|
|
||||||
:value (uiop:getenv "AOC_SESSION")
|
|
||||||
:origin-host "adventofcode.com"
|
|
||||||
:path "/"
|
|
||||||
:domain ".adventofcode.com"
|
|
||||||
:secure-p t))))
|
|
||||||
|
|
||||||
(setf *cookie-jar*
|
|
||||||
(cl-cookie:make-cookie-jar
|
(cl-cookie:make-cookie-jar
|
||||||
:cookies (list
|
:cookies (list
|
||||||
(cl-cookie:make-cookie
|
(cl-cookie:make-cookie
|
||||||
|
@ -42,24 +29,28 @@
|
||||||
(defun split-lines (s)
|
(defun split-lines (s)
|
||||||
(cl-ppcre:split "\\n" s))
|
(cl-ppcre:split "\\n" s))
|
||||||
|
|
||||||
|
|
||||||
(defun fetch-input-data (year day)
|
(defun fetch-input-data (year day)
|
||||||
(let ((url (format nil "~A/~D/day/~D/input" *aoc-url* year day)))
|
(let ((url (format nil "~A/~D/day/~D/input" *aoc-url* year day)))
|
||||||
(multiple-value-bind
|
(multiple-value-bind
|
||||||
(body)
|
(body)
|
||||||
(dex:get url :cookie-jar *cookie-jar* :verbose t)
|
(dex:get url :cookie-jar *cookie-jar*)
|
||||||
(split-lines body))))
|
(split-lines body))))
|
||||||
|
|
||||||
|
(defun print-articles (body)
|
||||||
|
(let* ((dom (plump:parse body))
|
||||||
|
(articles (plump:get-elements-by-tag-name dom "article")))
|
||||||
|
(loop for article in articles
|
||||||
|
do (format t "~A~%~%" (plump:render-text article)))))
|
||||||
|
|
||||||
(defun submit-answer (year day level answer)
|
(defun submit-answer (year day level answer)
|
||||||
(let ((url (format nil "~A/~D/day/~D/answer" *aoc-url* year day)))
|
(let ((url (format nil "~A/~D/day/~D/answer" *aoc-url* year day)))
|
||||||
(multiple-value-bind
|
(multiple-value-bind
|
||||||
(body)
|
(body)
|
||||||
(dex:post url :cookie-jar *cookie-jar* :verbose t
|
(dex:post url :cookie-jar *cookie-jar*
|
||||||
:content `(("level" . ,level)
|
:content `(("level" . ,level)
|
||||||
("answer" . ,answer)
|
("answer" . ,answer)
|
||||||
("submit" . "[Submit]")))
|
("submit" . "[Submit]")))
|
||||||
body)))
|
(print-articles body))))
|
||||||
|
|
||||||
(defun submit-part1 (year day answer)
|
(defun submit-part1 (year day answer)
|
||||||
(submit-answer year day "1" answer))
|
(submit-answer year day "1" answer))
|
||||||
|
@ -67,6 +58,18 @@
|
||||||
(defun submit-part2 (year day answer)
|
(defun submit-part2 (year day answer)
|
||||||
(submit-answer year day "2" answer))
|
(submit-answer year day "2" answer))
|
||||||
|
|
||||||
|
(defun show-articles (path)
|
||||||
|
(let ((url (format nil "~A/~A" *aoc-url* path)))
|
||||||
|
(multiple-value-bind
|
||||||
|
(body)
|
||||||
|
(dex:get url :cookie-jar *cookie-jar*)
|
||||||
|
(print-articles body))))
|
||||||
|
|
||||||
|
(defun private-leaderboard (year id)
|
||||||
|
(let ((path (format nil "~D/leaderboard/private/view/~D" year id)))
|
||||||
|
(show-articles path)))
|
||||||
|
|
||||||
|
|
||||||
(defvar *input-data-cache* (make-hash-table))
|
(defvar *input-data-cache* (make-hash-table))
|
||||||
|
|
||||||
(defun clear-data-cache ()
|
(defun clear-data-cache ()
|
||||||
|
|
30
tests/2024/day08-test.lisp
Normal file
30
tests/2024/day08-test.lisp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
(defpackage :aoc/2024/08/tests
|
||||||
|
(:use :cl :aoc :aoc/tests :aoc/2024/tests :parachute :aoc/2024/08))
|
||||||
|
|
||||||
|
(in-package :aoc/2024/08/tests)
|
||||||
|
|
||||||
|
(define-test suite-2024-08
|
||||||
|
;:parent suite-2024
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(define-test+run test-part1
|
||||||
|
:parent suite-2024-08
|
||||||
|
(true (equalp '( '()) (part1 sample-data))))
|
||||||
|
|
||||||
|
(define-test+run test-part2
|
||||||
|
:parent suite-2024-08
|
||||||
|
(true
|
||||||
|
(equalp "34" (part2 sample-data)))
|
||||||
|
(true
|
||||||
|
(equalp "9" (part2 sample-data2))))
|
||||||
|
|
||||||
|
|
||||||
|
(define-test test-parse-line
|
||||||
|
:parent suite-2024-08
|
||||||
|
(is equalp '() (parse-line (first sample-data)))
|
||||||
|
(is equalp '((8 #\0)) (parse-line (second sample-data)))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue