aboutsummaryrefslogtreecommitdiff
path: root/2021/day-21/day-21.rkt
blob: d2e17b6d82fa419cdda256d5ab149ddcd273dff9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#lang racket
(require threading
         memoize)

;; not going to bother importing the data since it's just two lines of text
(define player-1-start 4)
(define player-2-start 6)

(define track (sequence->stream (in-cycle (inclusive-range 1 10))))
(define current-turn (in-cycle (list 'player-1 'player-2)))
(define die-rolls (sequence->stream (in-cycle (inclusive-range 1 100))))

;; part 1
(~> (for/fold ([player-1-score 0]
               [player-1-track (stream-tail track (sub1 player-1-start))]
               [player-2-score 0]
               [player-2-track (stream-tail track (sub1 player-2-start))]
               [dice die-rolls]
               [last-turn 0]
               #:result (list (min player-1-score player-2-score) (* 3 last-turn)))
              ([turn-count (in-naturals 1)]
               [turn current-turn]
               #:break (or (player-1-score . >= . 1000)
                           (player-2-score . >= . 1000)))
      (define rolls (apply + (stream->list (stream-take dice 3))))
      (cond
        [(equal? turn 'player-1)
         (values (+ player-1-score
                    (stream-first (stream-tail player-1-track rolls)))
                 (stream-tail player-1-track rolls)
                 player-2-score
                 player-2-track
                 (stream-tail dice 3)
                 turn-count)]
        [(equal? turn 'player-2)
         (values player-1-score
                 player-1-track
                 (+ player-2-score
                    (stream-first (stream-tail player-2-track rolls)))
                 (stream-tail player-2-track rolls)
                 (stream-tail dice 3)
                 turn-count)]))
  (apply * _))

;; part 2
(define d3 (list 1 2 3))
(define roll-space (~>> (cartesian-product d3 d3 d3)
                        (map (λ~>> (apply +)))))

(define/memo (next-turns p1-score p2-score p1-start p2-start)
  (cond
    [(p1-score . >= . 21) '(1 0)]
    [(p2-score . >= . 21) '(0 1)]
    [else
     (for/fold ([p-wins '(0 0)])
               ([roll (in-list roll-space)])
       (define move-to (~> p1-start
                         (+ roll)
                         sub1
                         (modulo 10)
                         add1))
       (match-define (list p1-wins p2-wins) p-wins)
       (match-define (list p2-possible-win p1-possible-win)
         (next-turns p2-score
                     (+ p1-score move-to)
                     p2-start
                     move-to))
       (list (+ p1-wins p1-possible-win)
             (+ p2-wins p2-possible-win)))]))

(~>> (next-turns 0 0 player-1-start player-2-start) (apply max))