aoc-2022/elisp/day-2/solution.el

142 lines
4.5 KiB
EmacsLisp
Executable file

#!/usr/bin/env -S emacs --script
;; -*- lexical-binding: t; -*-
;; Copyright (C) 2022
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(add-to-list 'load-path "../")
(require 'ert)
(require 'advent-of-code)
(defvar solution-example-input
"../../input/day-2-example.txt")
(defvar solution-input
"../../input/day-2.txt")
(defvar solution-shapes
'(rock paper scissors))
(defvar solution-outcomes
'(win lose draw))
(defvar solution-opponent-letter-to-shape-alist
'(("A" . rock)
("B" . paper)
("C" . scissors)))
(defvar solution-player-letter-to-shape-alist
'(("X" . rock)
("Y". paper)
("Z" . scissors)))
(defvar solution-player-letter-to-outcome-alist
'(("X" . lose)
("Y" . draw)
("Z" . win)))
(defvar solution-shape-score-alist
'((rock . 1)
(paper . 2)
(scissors . 3)))
(defvar solution-outcome-score-alist
'((win . 6)
(draw . 3)
(lose . 0)))
;; Each shape points to another shape creating a cyclical list.
;; Each shape points to the shape that it beats, so deciding a game
;; outcome is a simple list search!
(defvar solution-shape-outcome-alist
'((rock . scissors)
(scissors . paper)
(paper . rock)))
(defun solution-decide-game (a b)
(cond ((equal a b)
'draw)
((equal (cdr (assoc a solution-shape-outcome-alist)) b)
'win)
(t
'lose)))
(defun solution-shape-for-outcome (a outcome)
(pcase outcome
('lose
(cdr (assoc a solution-shape-outcome-alist)))
('draw
a)
('win
(car (seq-find (lambda (c)
(equal (cdr c) a))
solution-shape-outcome-alist)))))
(defun solution-part-1 (input)
(let ((rows (seq-map (lambda (s)
(string-split s " " t))
input)))
(seq-reduce (lambda (acc row)
(let* ((their-shape (cdr (assoc (car row) solution-opponent-letter-to-shape-alist)))
(our-shape (cdr (assoc (cadr row) solution-player-letter-to-shape-alist)))
(outcome (solution-decide-game our-shape their-shape)))
(+ acc
(cdr (assoc our-shape solution-shape-score-alist))
(cdr (assoc outcome solution-outcome-score-alist)))))
rows
0)))
(defun solution-part-2 (input)
(let ((rows (seq-map (lambda (s)
(string-split s " " t))
input)))
(seq-reduce (lambda (acc row)
(let* ((their-shape (cdr (assoc (car row) solution-opponent-letter-to-shape-alist)))
(desired-outcome (cdr (assoc (cadr row) solution-player-letter-to-outcome-alist)))
(our-shape (solution-shape-for-outcome their-shape desired-outcome)))
(+ acc
(cdr (assoc our-shape solution-shape-score-alist))
(cdr (assoc desired-outcome solution-outcome-score-alist)))))
rows
0)))
(ert-deftest solution-test-decide-game ()
(should (equal (solution-decide-game 'rock 'paper) 'lose))
(should (equal (solution-decide-game 'paper 'rock) 'win))
(should (equal (solution-decide-game 'rock 'rock) 'draw)))
(ert-deftest solution-test-part-1-example ()
(should (equal (solution-part-1 (aoc-read-file-lines solution-example-input)) 15)))
(ert-deftest solution-test-part-1-input ()
(should (equal (solution-part-1 (aoc-read-file-lines solution-input)) 12740)))
(ert-deftest solution-test-part-2-example ()
(should (equal (solution-part-2 (aoc-read-file-lines solution-example-input)) 12)))
(ert-deftest solution-test-part-2 ()
(should (equal (solution-part-2 (aoc-read-file-lines solution-input)) 11980)))
(when noninteractive
(ert-run-tests-batch-and-exit))
;; Local Variables:
;; read-symbol-shorthands: (("solution-" . "advent-of-code-day-2-") ("aoc-" . "advent-of-code-"))
;; End: