Advent of Code '23 - Day 4

Table of Contents

Today was easier. I managed to complete the first part in about 20 minutes, which could have been shorter if I'd discovered that empty record at the end of my dataset sooner. The second part took a bit longer, but that was mainly due to the longer runtime of this script… I don't think this method is the best way to address this issue but I'm drawing a blank on how to solve it properly.

Input

Example

Card 1: 41 48 83 86 17 | 83 86  6 31 17  9 48 53
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
Card 3:  1 21 53 59 44 | 69 82 63 72 16 21 14  1
Card 4: 41 92 73 84 69 | 59 84 76 51 58  5 54 83
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11

Part 1

(defun aoc23/score-card (card)
  (let ((score 0))
    (dolist (i (seq-intersection (alist-get :winning-numbers card)
                                 (alist-get :my-numbers card)))
      (if (= score 0)
          (setq score 1)
        (setq score (* score 2))))
    score))

(defun aoc23/string-to-model (string)
  (let* ((parts (string-split string ":"))\
         (game (car parts))
         (numbers (cadr parts))
         (parts (string-split numbers "|"))
         (winning-numbers (car parts))
         (my-numbers (cadr parts))
         (winning-numbers (mapcar 'string-to-number (string-split winning-numbers)))
         (my-numbers (mapcar 'string-to-number (string-split my-numbers))))
    `(,game
      (:winning-numbers . ,winning-numbers)
      (:my-numbers . ,my-numbers))))

;(aoc23/string-to-model "Card 1: 41 48 83 86 17 | 83 86  6 31 17  9 48 53")

(apply '+ 
       (mapcar 'aoc23/score-card
               (mapcar 'aoc23/string-to-model
                       (seq-filter (lambda (s) (< 0 (length s)))
                                   (string-split input "\n")))))

Part 2

(defun aoc23/score-card (card)
  (length (seq-intersection (alist-get :winning-numbers card)
                            (alist-get :my-numbers card))))

(defun aoc23/parse-card-id (string)
  (string-to-number (cadr (string-split string))))

(defun aoc23/string-to-model (string)
  (let* ((parts (string-split string ":"))\
         (game (car parts))
         (numbers (cadr parts))
         (parts (string-split numbers "|"))
         (winning-numbers (car parts))
         (my-numbers (cadr parts))
         (winning-numbers (mapcar 'string-to-number (string-split winning-numbers)))
         (my-numbers (mapcar 'string-to-number (string-split my-numbers))))
    `(,game
      (:winning-numbers . ,winning-numbers)
      (:my-numbers . ,my-numbers))))


(let ((cards (mapcar 'aoc23/string-to-model (seq-filter (lambda (s) (< 0 (length s)))
                                                        (string-split input "\n"))))
      (bonus  '())
      (current 1)
      (counter 0))
  ;; set rounds per card on 1 for each card
  (dolist (card cards)
    (setf (alist-get (aoc23/parse-card-id (car card)) bonus) 1))

  ;; walk cards
  (dolist (card cards)
    (let ((score (aoc23/score-card card)))
      (dotimes (s (alist-get current bonus))
        (setq counter (1+ counter))
        (dotimes (i score)
          (let ((bonus-index (+ current i 1)))
          (setf (alist-get bonus-index bonus) (1+ (alist-get bonus-index bonus)))))))
    (setq current (1+ current)))
  counter)



;;
;;  (dolist (card cards)
;;    (dotimes (i (alist-get (car card) bonus))
;;      (dotimes (c (aoc23/score-card card))
;;        (let ((game (format "Card %d" (+ current c 1))))
;;          (setf (alist-get game bonus) (+ 1 (alist-get game bonus))))))
;;    (setq current (1+ current))))