Code for the Advent of Code event
aoc
advent-of-code
1#!/usr/bin/env ruby
2# frozen_string_literal: true
3
4PLAYER_1 = ARGF.readline.split(':')[1].to_i - 1
5PLAYER_2 = ARGF.readline.split(':')[1].to_i - 1
6
7player_1_score = 0
8player_2_score = 0
9
10die = 0
11die_rolls = 0
12
13player1 = PLAYER_1
14player2 = PLAYER_2
15
16(0..).each do |n|
17 die_value = die + 1
18 die = (die + 1) % 100
19 die_value += die + 1
20 die = (die + 1) % 100
21 die_value += die + 1
22 die = (die + 1) % 100
23 die_rolls += 3
24 if n.even?
25 player1 = (player1 + die_value) % 10
26 player_1_score += player1 + 1
27 else
28 player2 = (player2 + die_value) % 10
29 player_2_score += player2 + 1
30 end
31 break if player_1_score >= 1000 || player_2_score >= 1000
32end
33
34puts [player_1_score, player_2_score].min * die_rolls
35
36OUTCOMES = [1, 2, 3].repeated_permutation(3).map(&:sum).tally
37CACHE = {} # rubocop:disable Style/MutableConstant
38
39def dirac(flag = true, p1 = 0, p2 = 0, p1_score = 0, p2_score = 0) # rubocop:disable Style/OptionalBooleanParameter
40 cache_key = [flag, p1, p2, p1_score, p2_score]
41 return CACHE[cache_key] if CACHE.key? cache_key
42
43 return [1, 0] if p1_score >= 21
44 return [0, 1] if p2_score >= 21
45
46 result = [0, 0]
47
48 if flag
49 OUTCOMES.each do |outcome, count|
50 p1_o = (p1 + outcome) % 10
51 p1_o_s = p1_score + p1_o + 1
52 o_r = dirac(false, p1_o, p2, p1_o_s, p2_score)
53 result[0] += o_r[0] * count
54 result[1] += o_r[1] * count
55 end
56 else
57 OUTCOMES.each do |outcome, count|
58 p2_o = (p2 + outcome) % 10
59 p2_o_s = p2_score + p2_o + 1
60 o_r = dirac(true, p1, p2_o, p1_score, p2_o_s)
61 result[0] += o_r[0] * count
62 result[1] += o_r[1] * count
63 end
64 end
65
66 CACHE[cache_key] = result
67
68 result
69end
70
71puts dirac(true, PLAYER_1, PLAYER_2).max