Advent-of-Code/day2.lisp

175 lines
5.5 KiB
Common Lisp

;;;; https://adventofcode.com/2022/day/2
;; input is lines [A B C] [X Y Z]
;; meaning a-b-c what opponent will play
;; and x y z what i should play in rock-paper-scissors
;;
;; score is calculated as:
;; 1 for Rock X
;; 2 for Paper Y
;; 3 for Scissors Z
;;
;; 0 if Lost
;; 3 if Tie
;; 6 if Win
;;
;; Win if
;; (A Y) (B Z) (C X)
(setq MY-WIN-COMBINATIONS '((A Y) (B Z) (C X)))
;;
;; Loss if
;; (X B) (Y C) (Z A)
(setq MY-LOSS-COMBINATIONS '((B X) (C Y) (A Z)))
;;
;; otherwise it's a tie
(setq TIE-COMBINATIONS '((A X) (B Y) (C Z)))
;; now i'd also like to get symbol from the string...
(equal (intern "a") (intern "A")) ; not exactly what i means, but yeah this is it
;; now i'd like to get list of two symbols from string of two symbols
(setq my-test-line "A Z")
;; https://stackoverflow.com/questions/59516459/split-string-by-delimiter-and-include-delimiter-common-lisp
(require 'cl-ppcre)
(cl-ppcre:split "(\\.)" "a.bc.def.com" :with-registers-p t)
(cl-ppcre:split "(\\.)" "a.bc.def.com" :with-registers-p nil)
(setq my-test-line-list (mapcar #'intern (cl-ppcre:split "(\\ )" my-test-line :with-registers-p nil)))
;; yay
;;; now write scoring function over the lists of chars, for tie-win-loose match and for "my-selection-match"
;; sum the scores of the two parts of scoring
;; and iterate over input
;; would be cool to use pattern matching...
;; that's something like CASE in my
(case 1
((:in :in2) :lala)
((2 3) :numBig)
((1 -1) :numOne))
(case (list 1 2)
((:in :in2) :just-sym)
((list 1 2) :a-list))
;; this doesn't work with lists.
;; COND is similar to CASE, except it is more general. It accepts arbitrary
(find my-test-line-list my-win-combinations :TEST #'equal)
(find my-test-line-list my-loss-combinations :TEST #'equal)
(cond
((find my-test-line-list my-win-combinations :TEST #'equal) :WIN)
((find my-test-line-list my-loss-combinations :TEST #'equal) :LOSS)
(t :TIE))
(defun score-result (hands)
(cond
((find hands my-win-combinations :TEST #'equal)
6)
((find hands my-loss-combinations :TEST #'equal)
0)
(t 3)))
(score-result '(A Z))
(score-result '(A Y))
;;; now let's get score of the hands, by only my hand
(defun score-my-hand (hands)
(let ((my-hand (second hands)))
(case my-hand
(X 1)
(Y 2)
(z 3))))
(score-my-hand '(A Z))
(score-my-hand '(A Y))
(score-my-hand '(A X))
(defun full-score-hands (hands)
(+ (score-my-hand hands) (score-result hands)))
(full-score-hands '(A Y))
(full-score-hands '(B X))
(full-score-hands '(C Z))
;;; and now, iterate over file, converting strings into symbols and accumulating the score...
(require 'cl-ppcre)
(setq running-sum 0)
(let ((running-sum 0))
(with-open-file (in "~/Documents/personal/advent-of-code/2022/day2-input.txt")
(loop
for line = (read-line in nil nil)
while line
;; do (format t "line ~A~%" line)
do (let* ((line-word-list (cl-ppcre:split "(\\ )" line :with-registers-p nil))
(hands (mapcar #'intern line-word-list)))
(incf running-sum (full-score-hands hands)))
finally (return running-sum)
)))
;; (setq my-test-line-list (mapcar #'intern (cl-ppcre:split "(\\ )" my-test-line :with-registers-p nil)))
;; 12156 is the right answer!
;; let's wrap this into a function
(defun count-plays-score (filename)
(require 'cl-ppcre)
(let ((running-sum 0))
(with-open-file (in filename)
(loop
for line = (read-line in nil nil)
while line
do (let* ((line-word-list (cl-ppcre:split "(\\ )" line :with-registers-p nil))
(hands (mapcar #'intern line-word-list)))
(incf running-sum (full-score-hands hands)))
finally (return running-sum)
))))
(count-plays-score "~/Documents/personal/advent-of-code/2022/day2-input.txt")
;;; now for the Second part of the game
;; second part means something else!
;; X - need to loose
;; Y - need to draw
;; Z - need to win
;;
;; so, scoring is the same, but I need to calculate what is my hand
;; C Z means they play (SCISSORS) and i need to WIN, so I need to get ROCK
;; that goes into the calculation of the score
;; i would be able to reuse the scoring function,
;; but! i need a funtion that returns my hand
;; let's put it off for a bit?
;; or no. so. this would be best with what? ugh.
;; so Z - find hand from loose-hands that starts with required hand
;; Y - find from draw, Z - find from win
;; could use #'FIND with cusom :TEST - to compare only first item
(defun get-hand-set-by-result (hands)
(case (second hands)
(X my-loss-combinations)
(Y tie-combinations)
(Z my-win-combinations)))
(get-hand-set-by-result '(A Y))
(get-hand-set-by-result '(B X))
(get-hand-set-by-result '(C Z))
;; ok, somewhat like that
(find (first '(A Y))
(get-hand-set-by-result '(A Y)) :KEY (lambda (hands) (first hands)) )
(defun count-plays-score-2 (filename)
(require 'cl-ppcre)
(let ((running-sum 0))
(with-open-file (in filename)
(loop
for line = (read-line in nil nil)
while line
do (let* ((line-word-list (cl-ppcre:split "(\\ )" line :with-registers-p nil))
(hand-and-result (mapcar #'intern line-word-list))
(handset (get-hand-set-by-result hand-and-result))
(hands (find (first hand-and-result) handset :KEY (lambda (hands) (first hands)) )))
(incf running-sum (full-score-hands hands)))
finally (return running-sum)
))))
(count-plays-score-2 "~/Documents/personal/advent-of-code/2022/day2-input.txt")
;; 10835 is the right answer!