From de2cfb93f12cf2b6e6b7575540c3061f210fb4e6 Mon Sep 17 00:00:00 2001 From: Oscar Najera Date: Fri, 29 Dec 2023 20:59:07 +0100 Subject: refactor --- AoC2023/day20/solver.lisp | 71 ++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 34 deletions(-) (limited to 'AoC2023/day20/solver.lisp') 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")))) -- cgit v1.2.3