diff --git a/21-dirac-dice/code.scm b/21-dirac-dice/code.scm index 440d554..c876326 100644 --- a/21-dirac-dice/code.scm +++ b/21-dirac-dice/code.scm @@ -49,13 +49,76 @@ (set! next (cdr next)) value))))) +(define (vector-sum vec start end) + (vector-fold + (lambda (i a x) + (if (and (>= i start) + (< i end)) + (+ a x) + a)) + 0 vec)) + +;;; TODO: handle not playing if opponent already won +;;; not loose winning games in the process x_x +(define (dirac-roll! ongoings) + (let [(new (make-vector 220 0))] + ; keep the ones that already won + (vector-copy! new 210 ongoings 210) ; this should keep winning games, why do I loose some? + ; for each possible combination of 3 rolls of 3-sided dice + (for-each + (lambda (dice-1) + (for-each + (lambda (dice-2) + (for-each + (lambda (dice-3) + ; increase scores of ongoing games + (vector-for-each + (lambda (index ongoing) + (when (and (> ongoing 0) (< index 210)) + (let* [(position (mod index 10)) + (score (div index 10)) + (new-position (mod (+ position dice-1 dice-2 dice-3) 10)) + (new-score (min 21 (+ score new-position 1))) + (new-index (+ new-position (* new-score 10)))] + (vector-set! new new-index + (+ ongoing (vector-ref new new-index)))))) + ongoings)) + '(1 2 3))) + '(1 2 3))) + '(1 2 3)) + (vector-copy! ongoings 0 new))) + +(define (print-ongoing vec) + (vector-for-each + (lambda (index ongoing) + (when (> ongoing 0) + (printf " ~12a games with score ~a at position ~a~%" + ongoing (div index 10) (+ (mod index 10) 1)))) + vec)) + (define (play-dirac position-1 position-2) - (let [(player-1 (list (cons position-1 0))) - (player-2 (list (cons position-2 0))) - (wins-1 0) - (wins-2 0)] + ; the vectors track the number of games going on at given position and score, + ; where position = index % 10 and score = index / 10 + ; 10 because there are 10 positions on board + ; max score is 21 so 22 entries total accounting for starting zero + ; => 10 * 22 = 220 entries + (let [(player-1 (make-vector 220 0)) + (player-2 (make-vector 220 0))] + (vector-set! player-1 position-1 1) + (vector-set! player-2 position-2 1) + (printf "Player 1 starting at ~a, player 2 at ~a~%" position-1 position-2) (let loop () - 'no-idea-yet))) + (set! wins-1 (dirac-roll! player-1)) + (set! wins-2 (dirac-roll! player-2)) + (printf "P1:~%") (print-ongoing player-1) + (printf "P2:~%") (print-ongoing player-2) + ; compute how many games are still going (not reached 21) + (if (= (+ (vector-sum player-1 0 210) (vector-sum player-2 0 210)) 0) + ; sum how many winning games (the ones that reached 21) + ; and return biggest + (max (vector-sum player-1 210 220) + (vector-sum player-2 210 220)) + (loop))))) (let-values [((position-1 position-2) (read-starting-positions "input"))] (printf "part 1:~% Rolls * Opponent Score = ~a~%"