aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOscar Najera <hi@oscarnajera.com>2023-12-29 20:59:07 +0100
committerOscar Najera <hi@oscarnajera.com>2023-12-29 20:59:07 +0100
commitde2cfb93f12cf2b6e6b7575540c3061f210fb4e6 (patch)
treeb7fd59d70ac61e675d7ddec448e7eb7bf810f0f5
parentb13d1071a270c8ba655800cca26a76f9d6735e6e (diff)
downloadscratch-de2cfb93f12cf2b6e6b7575540c3061f210fb4e6.tar.gz
scratch-de2cfb93f12cf2b6e6b7575540c3061f210fb4e6.tar.bz2
scratch-de2cfb93f12cf2b6e6b7575540c3061f210fb4e6.zip
refactor
-rw-r--r--AoC2023/day20/solver.lisp71
1 files changed, 37 insertions, 34 deletions
diff --git a/AoC2023/day20/solver.lisp b/AoC2023/day20/solver.lisp
index d57af9a..21b0bed 100644
--- a/AoC2023/day20/solver.lisp
+++ b/AoC2023/day20/solver.lisp
@@ -3,34 +3,38 @@
(:use :cl :fiveam :alexandria))
(in-package :day20)
-(defstruct module
+(defstruct (module (:constructor mk-module
+ (type outputs
+ &aux (state (if (eq type 'conjunction)
+ (make-hash-table) 'off)))))
type state outputs)
+(defun prepare-board (board)
+ "Records into every conjunction which are its inputs."
+ (maphash (lambda (name value)
+ (with-slots (type state outputs) value
+ (dolist (out outputs)
+ (when (arrows:some->
+ (gethash out board)
+ (module-type)
+ (eq 'conjunction))
+ (setf (gethash name (module-state (gethash out board))) 'low)))))
+ board))
+
(defun parse-input (lines)
(let ((board (make-hash-table)))
- (dolist (instruction lines board)
+ (dolist (instruction lines)
(destructuring-bind (module outputs) (str:split " -> " instruction)
(let ((outputs (mapcar #'read-from-string (str:split ", " outputs)))
- (name (if (string-equal "broadcaster" module) 'broadcaster (read-from-string (subseq module 1))))
+ (name (if (string-equal "broadcaster" module) 'broadcaster
+ (read-from-string (subseq module 1))))
(type (ecase (elt module 0)
(#\b 'broadcaster)
(#\& 'conjunction)
(#\% 'flip-flop))))
- (setf (gethash name board) (make-module :type type
- :state (if (eq type 'conjunction) (make-hash-table) 'off)
- :outputs outputs)))))))
-
-(defun prepare-board (board)
- (maphash (lambda (name value)
- (with-slots (type state outputs) value
- (dolist (out outputs)
- (when (arrows:some->
- (gethash out board)
- (slot-value 'type)
- (eq 'conjunction))
- (setf (gethash name (slot-value (gethash out board) 'state)) 'low)))))
- board)
- board)
+ (setf (gethash name board) (mk-module type outputs)))))
+ (prepare-board board)
+ board))
(defun toggle (state)
(ecase state
@@ -61,7 +65,7 @@
signals))
(test parts
- (let ((board (prepare-board (parse-input (uiop:read-file-lines "eg-i1")))))
+ (let ((board (parse-input (uiop:read-file-lines "eg-i1"))))
(is (equal
'((BROADCASTER A LOW) (BROADCASTER B LOW) (BROADCASTER C LOW))
(propagate board '((button broadcaster low)))))
@@ -74,7 +78,7 @@
(is (null (propagate board '((c blank low)))))))
(defun solver1 (lines)
- (let ((board (prepare-board (parse-input lines))))
+ (let ((board (parse-input lines)))
(labels ((rec (signals n-high n-low)
(if (null signals)
(list n-high n-low)
@@ -91,7 +95,8 @@
(apply #'lcm (mapcar #'cdr cycles)))
(defun solver2 ()
- (let* ((board (prepare-board (parse-input (uiop:read-file-lines "input"))))
+ (let* ((board (parse-input (uiop:read-file-lines "input")))
+ (start '((button broadcaster low)))
;; feed is a single conjunction that gives to rx by inspecting input
;; feed has 4 inputs, it needs them all to be on high before it outputs
;; a low for rx
@@ -100,28 +105,26 @@
;; their cycle.
(feed (loop for name being the hash-key of board
using (hash-value module)
- when (member 'rx (slot-value module 'outputs))
+ when (member 'rx (module-outputs module))
return name))
- (cycles (loop for name being the hash-key of board
- using (hash-value module)
- when (member feed (slot-value module 'outputs))
- collect (cons name 0)))
- (presses 1)
- (start '((button broadcaster low))))
+ cycles)
+
+ (maphash (lambda (name module)
+ (when (member feed (module-outputs module))
+ (push (cons name nil) cycles)))
+ board)
(loop named outer
for signals = (propagate board start) then (propagate board (or signals start))
- when (null signals)
- do (incf presses)
- ;; until (< 4000 presses)
+ count (null signals) into presses
+ ;; until (< 4000 presses)
do
(loop for (from to pulse) in signals do
(when (and (eq to feed) (eq pulse 'high))
- (setf (cdr (assoc from cycles)) presses))
- (when (every (compose #'positive-fixnum-p #'cdr) cycles)
+ (setf (cdr (assoc from cycles)) (1+ presses)))
+ (when (every (compose #'numberp #'cdr) cycles)
(return-from outer (common-cycle cycles)))))))
-
(test solutions
(is (= 32000000 (solver1 (uiop:read-file-lines "eg-i1"))))
(is (= 11687500 (solver1 (uiop:read-file-lines "eg-i2"))))