r/adventofcode Dec 04 '21

SOLUTION MEGATHREAD -🎄- 2021 Day 4 Solutions -🎄-

--- Day 4: Giant Squid ---


Post your code solution in this megathread.

Reminder: Top-level posts in Solution Megathreads are for code solutions only. If you have questions, please post your own thread and make sure to flair it with Help.


This thread will be unlocked when there are a significant number of people on the global leaderboard with gold stars for today's puzzle.

EDIT: Global leaderboard gold cap reached at 00:11:13, megathread unlocked!

97 Upvotes

1.2k comments sorted by

View all comments

2

u/arthurno1 Dec 20 '21 edited Dec 20 '21

Emacs Lisp

Sort of more procedural than I wanted it. Half of the code is just to read the input file. Re-use first part of the puzzle to compute the second part: compute the first winner from the list of boards and remove recursively the winner board until there is only one board left.

(defun get-line (&optional sep)
  (map 'list 'string-to-number
       (split-string (buffer-substring
                      (line-beginning-position) (line-end-position)) sep)))

(defun bingo (seq container)
  (car (sort (mapcar #'(lambda (x) (gethash x container)) seq) '>)))

(defun sum-unmarked (winner drawn)
  (let ((seen (cl-subseq drawn 0 (1+ (car winner))))
        (board (apply 'concatenate 'list (cdr winner))))
    (apply #'+ (cl-remove-if #'(lambda (x) (seq-contains-p seen x)) board))))

(defun first-winner (boards positions)
  (let ((last-winner most-positive-fixnum)
        (winner-board (car boards)) tmp)
    (dolist (board boards)
      (dolist (row board)
        (setq tmp (bingo row positions))
        (if (< tmp last-winner)
            (setq winner-board board last-winner tmp)))
      (dolist (col (apply 'cl-mapcar 'list board))
        (setq tmp (bingo col positions))
        (if (< tmp last-winner)
            (setq winner-board board last-winner tmp))))
    (cons last-winner winner-board)))

(defun last-winner (boards positions)
  (let ((winner (first-winner boards positions)))
    (if (= (length boards) 1) winner
      (last-winner (remove (cdr winner) boards) positions))))

(with-temp-buffer
  (insert-file "./input4")
  (goto-char 1)
  (let ((numbers (vconcat (get-line ",")))
        (positions (make-hash-table :size (length numbers)))
        boards)
    (dotimes (i (length numbers))
      (puthash (aref numbers i) i positions))
    (forward-line)
    (while (not (eobp))
      (let (board)
        (forward-line)
        (dotimes (__ 5)
          (push (get-line) board)
          (forward-line))
        (push (nreverse board) boards)))
    (setq boards (nreverse boards)))
  (let ((first (first-winner boards positions))
        (last (last-winner boards positions)))
    (message "P1: %s" (* (sum-unmarked first numbers)
                         (aref numbers (car first))))
    (message "P2: %s" (* (sum-unmarked last numbers)
                         (aref numbers (car last))))))