# Player = Struct.new(:space, :score)
# one = Player.new(7, 0)
# two = Player.new(3, 0)

# class Die
#   def initialize
#     @value = 0
#     @rolls = 0
#   end

#   attr_reader :rolls

#   def roll
#     value = @value

#     @value += 1
#     @value %= 100

#     @rolls += 1

#     value
#   end
# end
# die = Die.new

# loop do
#   one.space += 3.times.sum { die.roll + 1 }
#   one.space %= 10
#   one.score += one.space + 1
#   break if one.score >= 1000

#   two.space += 3.times.sum { die.roll + 1 }
#   two.space %= 10
#   two.score += two.space + 1
#   break if two.score >= 1000
# end

# p [one, two].map(&:score).min * die.rolls

ROLLS = (1..3).flat_map {|a| (1..3).flat_map {|b| (1..3).map {|c|
  [a, b, c].sum
}}}.tally
Player = Struct.new(:score, :space, keyword_init: true)
wins = Hash.new {|h,k|
  one, two = k

  multiverse = ROLLS.map {|delta,n|
    space = (one.space + delta) % 10
    [Player.new(score: one.score + space + 1, space: space), n]
  }
  one_wins, one_ongoing = multiverse.partition {|player,_| player.score >= 21 }
  one_wins = one_wins.sum(&:last)

  multiverse = ROLLS.map {|delta,n|
    space = (two.space + delta) % 10
    [Player.new(score: two.score + space + 1, space: space), n]
  }

  wins = one_ongoing.flat_map {|one, n_one| multiverse.map {|two, n_two|
    n = n_one * n_two
    if two.score >= 21
      { one: 0, two: n }
    else
      h[[one, two]].map { [_1, _2 * n] }.to_h
    end
  }}
  wins = wins.inject({one: 0, two: 0}) {|acc,wins| acc.merge(wins) { _2 + _3 }}

  h[k] = {
    one: one_wins + wins.fetch(:one),
    two: wins.fetch(:two),
  }
}

# p wins[[Player.new(score: 0, space: 3), Player.new(score: 0, space: 7)]]
p wins[[Player.new(score: 0, space: 7), Player.new(score: 0, space: 3)]].values.max