-
Notifications
You must be signed in to change notification settings - Fork 0
/
21b_solution.rb
72 lines (60 loc) · 1.45 KB
/
21b_solution.rb
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
72
start_pos = [6, 3]
start_player = 0
single_rolls = [1,2,3]
possible_rolls = single_rolls.flat_map do |a|
single_rolls.flat_map do |b|
single_rolls.map do |c|
[a, b, c]
end
end
end
$possible_roll_values = possible_rolls
.group_by { |e| e.sum }
.map { |k, v| [k, v.count] }
.to_h
def mod_add1(a, b, mod)
((a-1+b) % mod) + 1
end
def other(player)
player == 0 ? 1 : 0
end
$memo = {}
def play(player, current_pos, score)
key = [player, current_pos, score]
memoized = $memo[key]
if memoized.nil?
_play(player, current_pos, score).tap do |val|
$memo[key] = val
end
else
memoized
end
end
def _play(player, current_pos, score)
if score[player] >= 21
num_wins = []
num_wins[player] = 1
num_wins[other(player)] = 0
return num_wins
end
if score[other(player)] >= 21
num_wins = []
num_wins[other(player)] = 1
num_wins[player] = 0
return num_wins
end
$possible_roll_values.reduce([0, 0]) do |num_wins, (value, count)|
new_pos = []
new_pos[player] = mod_add1(current_pos[player], value, 10)
new_pos[other(player)] = current_pos[other(player)]
new_score = []
new_score[player] = score[player] + new_pos[player]
new_score[other(player)] = score[other(player)]
sub_num_wins = play(other(player), new_pos, new_score)
[
num_wins[0]+count*sub_num_wins[0],
num_wins[1]+count*sub_num_wins[1]
]
end
end
puts play(start_player, start_pos, [0, 0]).max