(defpackage "AOC/9" (:use "CL"))
(in-package "AOC/9")
;; store marbles in a record (number . (prev . next))
(defun value (current)
(car current))
(defun prev (current)
(cadr current))
(defun (setf prev) (new-value current)
(setf (cadr current) new-value))
(defun next (current)
(cddr current))
(defun (setf next) (new-value current)
(setf (cddr current) new-value))
(defun print-marbles (current)
(cons (value current)
(loop for m = (next current) then (next m)
until (eq m current)
collect (value m))))
(defun insert (value current)
(let* ((a (next current))
(b (next a))
(new (cons value (cons a b))))
(setf (next a) new
(prev b) new)))
(defun start ()
(let ((node (cons 0 (cons nil nil))))
(setf (next node) node
(prev node) node)))
(defun score (value current)
(let* ((a (prev (prev (prev (prev (prev (prev current)))))))
(b (prev a))
(c (prev b)))
(setf (prev a) c
(next c) a)
(values a (+ value (value b)))))
(defun turn (value current)
(if (zerop (mod value 23))
(score value current)
(insert value current)))
;; (defun game (players high-score)
;; (loop for i from 1
;; with c = (start)
;; and scores = (make-list players)
;; while (< (apply #'max scores) high-score)
;; do (multiple-value-bind (current score)
;; (turn i c)
;; (when score
;; (incf (nth (mod i players) scores) score))
;; (setf c current))))
(defun solution-1 ()
(loop for i from 1 to 71482
with c = (start)
and scores = (make-list 424 :initial-element 0)
do (multiple-value-bind (current score)
(turn i c)
(when score
(incf (nth (mod i 424) scores) score))
(setf c current))
finally (return (apply #'max scores))))
(defun solution-2 ()
(loop for i from 1 to 7148200
with c = (start)
and scores = (make-list 424 :initial-element 0)
do (multiple-value-bind (current score)
(turn i c)
(when score
(incf (nth (mod i 424) scores) score))
(setf c current))
finally (return (apply #'max scores))))