Advent of Code '23 - day 7

Table of Contents

Appearantly I missed the rule about the lowest card. Fun puzzle nonetheless.

Input

Example

32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483

Part 1

(defun aoc23/char-to-card (c)
  (string-search (char-to-string c) "23456789TJQKA"))

(defun aoc23/string-to-hand (string)
  (let* ((segs (string-split string " "))
         (cards (car segs))
         (cards (mapcar 'aoc23/char-to-card cards))
         (bid (string-to-number (cadr segs))))
    `((:cards . ,cards)
      (:bid . ,bid))))

(defun aoc23/make-set-score (cards)
  (let* ((map (make-hash-table))
         (out 0))
    (dolist (card cards)
      (let ((c (gethash card map 0)))
        (setq c (1+ c))
        (puthash card c map)))

    (let ((scores (sort (hash-table-values map) '>)))
      (dolist (v scores)
        (setq out (+ (* 10 out)
                     v)))
      (dotimes (i (- 5 (length scores)))
        (setq out (* 10 out))))
    out
  ))

(defun aoc23/compare-hands (a b)
  (let ((aa a)
        (bb b))
    (while (and (car aa)
                (car bb)
                (= (car aa) (car bb)))
      (setq aa (cdr aa))
      (setq bb (cdr bb)))
    (> (car aa) (car bb))))

(defun aoc23/sort-hands (a b)
  (let* ((ca (cdr (assoc :cards a)))
         (cb (cdr (assoc :cards b)))
         (sca (aoc23/make-set-score ca))
         (scb (aoc23/make-set-score cb)))
    (let ((x (if (= sca scb)
                 (aoc23/compare-hands ca cb)
               (> sca scb))))
      (message "%S(%S) vs %S(%S) : %S" ca sca cb scb x)
      x)))



(defun hand-to-string (hand)
  (concat "|"
          (apply 'concat (mapcar (lambda (c)
                                   (substring "23456789TJQKA" c (1+ c)))
                                 (cdr (assoc :cards hand))))
          " "
          (number-to-string (cdr (assoc :bid hand)))
          "|"))

(let* ((score 0)
       (hands (sort (mapcar 'aoc23/string-to-hand (string-split (string-trim input) "\n"))
                    'aoc23/sort-hands))
       (rank (length hands)))
  (message (apply 'concat (mapcar 'hand-to-string hands)))
  (dolist (hand hands)
    (setq score (+ score
                   (* rank (cdr (assoc :bid hand)))))
    (setq rank (1- rank)))
  score)

Part 2

(defun aoc23/char-to-card (c)
  (string-search (char-to-string c) "J23456789TQKA"))

(defun aoc23/string-to-hand (string)
  (let* ((segs (string-split string " "))
         (cards (car segs))
         (cards (mapcar 'aoc23/char-to-card cards))
         (bid (string-to-number (cadr segs))))
    `((:cards . ,cards)
      (:bid . ,bid))))

(defun aoc23/replace-jokers (cards card)
  ;(message "replace %S" card)
  (mapcar (lambda (c)
            (if (= c 0)
                card
              c))
          cards))



(defun aoc23/make-set-score-with-jokers (cards)
;      (error "%S" (mapcar (lambda (c) (if (= c 0) "Y" c)) cards))
  (let ((highest 0))
    (dolist (card cards)
      (let* ((adjusted-cards (aoc23/replace-jokers cards card))
             (score (aoc23/make-set-score adjusted-cards)))
        ;(message "%S > %S" cards adjusted-cards)
        (when (< highest score)
          (setq highest score))))
    highest))

(defun aoc23/make-set-score (cards)
  (let* ((map (make-hash-table))
         (out 0))
    (dolist (card cards)
      (let ((c (gethash card map 0)))
        (setq c (1+ c))
        (puthash card c map)))

    (let ((scores (sort (hash-table-values map) '>)))
      (dolist (v scores)
        (setq out (+ (* 10 out)
                     v)))
      (dotimes (i (- 5 (length scores)))
        (setq out (* 10 out))))
    out
  ))

(defun aoc23/compare-hands (a b)
  (let ((aa a)
        (bb b))
    (while (and (car aa)
                (car bb)
                (= (car aa) (car bb)))
      (setq aa (cdr aa))
      (setq bb (cdr bb)))
    (> (car aa) (car bb))))

(defun aoc23/sort-hands (a b)
  (let* ((ca (cdr (assoc :cards a)))
         (cb (cdr (assoc :cards b)))
         (sca (aoc23/make-set-score-with-jokers ca))
         (scb (aoc23/make-set-score-with-jokers cb)))
    (let ((x (if (= sca scb)
                 (aoc23/compare-hands ca cb)
               (> sca scb))))
      ;(message "%S(%S) vs %S(%S) : %S" ca sca cb scb x)
      x)))



(defun hand-to-string (hand)
  (concat "|"
          (apply 'concat (mapcar (lambda (c)
                                   (substring "J23456789TQKA" c (1+ c)))
                                 (cdr (assoc :cards hand))))
          " "
          (number-to-string (cdr (assoc :bid hand)))
          "|"))

(let* ((score 0)
       (hands (sort (mapcar 'aoc23/string-to-hand (string-split (string-trim input) "\n"))
                    'aoc23/sort-hands))
       (rank (length hands)))
  ;(message (apply 'concat (mapcar 'hand-to-string hands)))
  (dolist (hand hands)
    (setq score (+ score
                   (* rank (cdr (assoc :bid hand)))))
    (setq rank (1- rank)))
  score)