(in-package :ca.mhcat.advent2022) ;; --- Day 2: Rock Paper Scissors --- ;; The Elves begin to set up camp on the beach. To decide ;; whose tent gets to be closest to the snack storage, a ;; giant Rock Paper Scissors tournament is already in ;; progress. ;; Rock Paper Scissors is a game between two players. Each ;; game contains many rounds; in each round, the players ;; each simultaneously choose one of Rock, Paper, or ;; Scissors using a hand shape. Then, a winner for that ;; round is selected: Rock defeats Scissors, Scissors ;; defeats Paper, and Paper defeats Rock. If both players ;; choose the same shape, the round instead ends in a draw. ;; Appreciative of your help yesterday, one Elf gives you an ;; encrypted strategy guide (your puzzle input) that they ;; say will be sure to help you win. "The first column is ;; what your opponent is going to play: A for Rock, B for ;; Paper, and C for Scissors. The second column--" Suddenly, ;; the Elf is called away to help with someone's tent. ;; The second column, you reason, must be what you should ;; play in response: X for Rock, Y for Paper, and Z for ;; Scissors. Winning every time would be suspicious, so the ;; responses must have been carefully chosen. ;; The winner of the whole tournament is the player with the ;; highest score. Your total score is the sum of your scores ;; for each round. The score for a single round is the score ;; for the shape you selected (1 for Rock, 2 for Paper, and ;; 3 for Scissors) plus the score for the outcome of the ;; round (0 if you lost, 3 if the round was a draw, and 6 if ;; you won). ;; Since you can't be sure if the Elf is trying to help you ;; or trick you, you should calculate the score you would ;; get if you were to follow the strategy guide. ;; For example, suppose you were given the following ;; strategy guide: ;; A Y ;; B X ;; C Z ;; This strategy guide predicts and recommends the following: ;; In the first round, your opponent will choose Rock ;; (A), and you should choose Paper (Y). This ends in a ;; win for you with a score of 8 (2 because you chose ;; Paper + 6 because you won). ;; In the second round, your opponent will choose Paper ;; (B), and you should choose Rock (X). This ends in a ;; loss for you with a score of 1 (1 + 0). ;; The third round is a draw with both players choosing ;; Scissors, giving you a score of 3 + 3 = 6. ;; In this example, if you were to follow the strategy ;; guide, you would get a total score of 15 (8 + 1 + 6). ;; What would your total score be if everything goes exactly ;; according to your strategy guide? (defparameter day2/test-data '((#\A #\Y) (#\B #\X) (#\C #\Z))) (defparameter day2/bad-code-table '((#\A . :rock) (#\B . :paper) (#\C . :scissors) (#\X . :rock) (#\Y . :paper) (#\Z . :scissors))) (defparameter day2/hierarchy '((:rock :scissors) (:paper :rock) (:scissors :paper))) (defparameter day2/item-scores '((:rock . 1) (:paper . 2) (:scissors . 3))) (defparameter day2/outcome-scores '((:win . 6) (:draw . 3) (:lose . 0))) (defun day2/parse-strategy (lst code-table) (flet ((decode (pair) (mapcar (lambda (ch) (cdr (assoc ch code-table))) pair))) (loop for pair in lst collect (decode pair)))) (defun day2/play-round (pair) (cond ((find pair day2/hierarchy :test #'equal) '(:win :lose)) ((find (reverse pair) day2/hierarchy :test #'equal) '(:lose :win)) (t '(:draw :draw)))) (defun day2/scores (strategy outcome) (flet ((scores (table pair) (mapcar (lambda (arg) (cdr (assoc arg table))) pair))) (list (scores day2/item-scores strategy) (scores day2/outcome-scores outcome)))) (defun day2/sum-scores (scores) (list (apply #'+ (mapcar #'first scores)) (apply #'+ (mapcar #'second scores)))) (defun day2/compute-part1 (lst) (loop for pair in (day2/parse-strategy lst day2/bad-code-table) append (day2/scores pair (day2/play-round pair)) into scores finally (return (day2/sum-scores scores)))) (defun day2/load-dataset (fname) (loop for line in (load-lines fname) collect (remove #\space (coerce line 'list)))) (defun day2/part1 () (day2/compute-part1 (day2/load-dataset "day2.txt"))) ;; --- Part Two --- ;; The Elf finishes helping with the tent and sneaks back ;; over to you. "Anyway, the second column says how the ;; round needs to end: X means you need to lose, Y means you ;; need to end the round in a draw, and Z means you need to ;; win. Good luck!" ;; The total score is still calculated in the same way, but ;; now you need to figure out what shape to choose so the ;; round ends as indicated. The example above now goes like ;; this: ;; In the first round, your opponent will choose Rock ;; (A), and you need the round to end in a draw (Y), so ;; you also choose Rock. This gives you a score of 1 + 3 ;; = 4. ;; In the second round, your opponent will choose Paper ;; (B), and you choose Rock so you lose (X) with a score ;; of 1 + 0 = 1. ;; In the third round, you will defeat your opponent's ;; Scissors with Rock for a score of 1 + 6 = 7. ;; Now that you're correctly decrypting the ultra top secret ;; strategy guide, you would get a total score of 12. ;; Following the Elf's instructions for the second column, ;; what would your total score be if everything goes exactly ;; according to your strategy guide? (defparameter day2/real-code-table '((#\A . :rock) (#\B . :paper) (#\C . :scissors) (#\X . :lose) (#\Y . :draw) (#\Z . :win))) (defun day2/resolve-strategy (round) (destructuring-bind (them outcome) round (list them (case outcome (:lose (second (find them day2/hierarchy :key #'car))) (:win (second (find them (mapcar #'reverse day2/hierarchy) :key #'car))) (otherwise them))))) (defun day2/compute-part2 (lst) (loop for pair in (mapcar #'day2/resolve-strategy (day2/parse-strategy lst day2/real-code-table)) append (day2/scores pair (day2/play-round pair)) into scores finally (return (day2/sum-scores scores)))) (defun day2/part2 () (day2/compute-part2 (day2/load-dataset "day2.txt")))