use std::collections::BTreeMap;
type Win = BTreeMap<GameState, (usize, usize)>;
fn main() {
let mut rolls: BTreeMap<u32, usize> = BTreeMap::new();
for r1 in 1..=3 {
for r2 in 1..=3 {
for r3 in 1..=3 {
let roll = r1 + r2 + r3;
*rolls.entry(roll).or_insert(0) += 1;
}
}
}
let mut wins: Win = BTreeMap::new();
let game = Game::new(4, 8, 21).play_quantum(&rolls, &mut wins);
println!("{:?} , {:?}", game.0, game.1);
let game = Game::new(3, 7, 1000).play_deterministic();
println!("{:?}", game.game_score);
}
#[derive(Debug, Eq, Ord, PartialOrd, PartialEq, Clone, Copy, Hash)]
struct GameState {
win_score: u32,
track_len: u32,
player1: PlayerState,
player2: PlayerState,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, PartialOrd, Ord)]
enum Player {
One,
Two,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
struct Game {
won: Option<Player>,
game_score: Option<u32>,
state: GameState,
dices_rolled: u32,
dice: Dice,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
struct Dice {
last_roll: u32,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, PartialOrd, Ord)]
struct PlayerState {
id: Player,
pos: u32,
score: u32,
rolled: u32,
}
impl Game {
fn new(position1: u32, position2: u32, win_score: u32) -> Self {
Game {
won: None,
game_score: None,
state: GameState {
win_score,
track_len: 10,
player1: PlayerState {
id: Player::One,
pos: position1,
score: 0,
rolled: 0,
},
player2: PlayerState {
id: Player::Two,
pos: position2,
score: 0,
rolled: 0,
},
},
dices_rolled: 0,
dice: Dice { last_roll: 1 },
}
}
fn play_deterministic(&self) -> Self {
let mut result: Game = *self;
loop {
let roll1 = result.dice.roll_d();
let roll2 = result.dice.roll_d();
let (state, rolled) = round(&(roll1, roll2), &result.state);
result.dices_rolled += rolled;
result.state = state;
if result.is_win() {
return result;
}
}
}
fn play_quantum(&self, rolls: &BTreeMap<u32, usize>, win_map: &mut Win) -> (usize, usize) {
let mut wins = (0, 0);
for (roll1, count1) in rolls.iter() {
for (roll2, count2) in rolls.iter() {
let (win1, win2) = self.quantum_game(&(*roll1, *roll2), win_map, rolls);
let mult = count1 * count2;
wins.0 += mult * win1;
if win1 == 1 && win2 == 0 {
break;
}
wins.1 += mult * win2;
}
}
wins
}
fn quantum_game(
&self,
entry: &(u32, u32),
win_map: &mut BTreeMap<GameState, (usize, usize)>,
rolls: &BTreeMap<u32, usize>,
) -> (usize, usize) {
let mut result: Game = *self;
let (state, _rolled) = round(entry, &result.state);
result.state = state;
if !result.is_win() {
if let Some(x) = win_map.get(&state) {
*x
} else {
let tmp = result.play_quantum(rolls, win_map);
return *win_map.entry(state).or_insert(tmp);
}
} else if result.won == Some(Player::One) {
(1, 0)
} else if result.won == Some(Player::Two) {
(0, 1)
} else {
(0, 0)
}
}
fn is_win(&mut self) -> bool {
if self.state.player1.score >= self.state.win_score {
self.won = Some(Player::One);
self.game_score = Some(self.state.player2.score * self.dices_rolled);
true
} else if self.state.player2.score >= self.state.win_score {
self.won = Some(Player::Two);
self.game_score = Some(self.state.player1.score * self.dices_rolled);
true
} else {
false
}
}
}
impl Dice {
fn roll_d(&mut self) -> u32 {
let roll = self.last_roll;
let roll = 3 * roll + 3;
self.last_roll += 3;
roll
}
}
impl PlayerState {
fn new_position(&self, track_len: u32, roll: u32) -> u32 {
let pos = (self.pos + roll) % track_len;
if pos == 0 {
track_len
} else {
pos
}
}
fn rolled(&mut self, track_len: u32, roll: u32) {
self.pos = self.new_position(track_len, roll);
self.score += self.pos;
}
}
type Roll = (u32, u32);
fn round(dice_roll: &Roll, state: &GameState) -> (GameState, u32) {
let mut new_state = *state;
new_state.player1.rolled(state.track_len, dice_roll.0);
if new_state.player1.score >= state.win_score {
return (new_state, 3);
}
new_state.player2.rolled(state.track_len, dice_roll.1);
(new_state, 6)
}
dXNlIHN0ZDo6Y29sbGVjdGlvbnM6OkJUcmVlTWFwOwoKdHlwZSBXaW4gPSBCVHJlZU1hcDxHYW1lU3RhdGUsICh1c2l6ZSwgdXNpemUpPjsKCmZuIG1haW4oKSB7CiAgICBsZXQgbXV0IHJvbGxzOiBCVHJlZU1hcDx1MzIsIHVzaXplPiA9IEJUcmVlTWFwOjpuZXcoKTsKICAgIGZvciByMSBpbiAxLi49MyB7CiAgICAgICAgZm9yIHIyIGluIDEuLj0zIHsKICAgICAgICAgICAgZm9yIHIzIGluIDEuLj0zIHsKICAgICAgICAgICAgICAgIGxldCByb2xsID0gcjEgKyByMiArIHIzOwogICAgICAgICAgICAgICAgKnJvbGxzLmVudHJ5KHJvbGwpLm9yX2luc2VydCgwKSArPSAxOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQogICAgbGV0IG11dCB3aW5zOiBXaW4gPSBCVHJlZU1hcDo6bmV3KCk7CiAgICBsZXQgZ2FtZSA9IEdhbWU6Om5ldyg0LCA4LCAyMSkucGxheV9xdWFudHVtKCZyb2xscywgJm11dCB3aW5zKTsKICAgIHByaW50bG4hKCJ7Oj99ICwgezo/fSIsIGdhbWUuMCwgZ2FtZS4xKTsKICAgIGxldCBnYW1lID0gR2FtZTo6bmV3KDMsIDcsIDEwMDApLnBsYXlfZGV0ZXJtaW5pc3RpYygpOwogICAgcHJpbnRsbiEoIns6P30iLCBnYW1lLmdhbWVfc2NvcmUpOwp9CgojW2Rlcml2ZShEZWJ1ZywgRXEsIE9yZCwgUGFydGlhbE9yZCwgUGFydGlhbEVxLCBDbG9uZSwgQ29weSwgSGFzaCldCnN0cnVjdCBHYW1lU3RhdGUgewogICAgd2luX3Njb3JlOiB1MzIsCiAgICB0cmFja19sZW46IHUzMiwKICAgIHBsYXllcjE6IFBsYXllclN0YXRlLAogICAgcGxheWVyMjogUGxheWVyU3RhdGUsCn0KCiNbZGVyaXZlKERlYnVnLCBFcSwgUGFydGlhbEVxLCBDbG9uZSwgQ29weSwgSGFzaCwgUGFydGlhbE9yZCwgT3JkKV0KZW51bSBQbGF5ZXIgewogICAgT25lLAogICAgVHdvLAp9CgojW2Rlcml2ZShEZWJ1ZywgRXEsIFBhcnRpYWxFcSwgQ2xvbmUsIENvcHkpXQpzdHJ1Y3QgR2FtZSB7CiAgICB3b246IE9wdGlvbjxQbGF5ZXI+LAogICAgZ2FtZV9zY29yZTogT3B0aW9uPHUzMj4sCiAgICBzdGF0ZTogR2FtZVN0YXRlLAogICAgZGljZXNfcm9sbGVkOiB1MzIsCiAgICBkaWNlOiBEaWNlLAp9CgojW2Rlcml2ZShEZWJ1ZywgRXEsIFBhcnRpYWxFcSwgQ2xvbmUsIENvcHkpXQpzdHJ1Y3QgRGljZSB7CiAgICBsYXN0X3JvbGw6IHUzMiwKfQoKI1tkZXJpdmUoRGVidWcsIEVxLCBQYXJ0aWFsRXEsIENsb25lLCBDb3B5LCBIYXNoLCBQYXJ0aWFsT3JkLCBPcmQpXQpzdHJ1Y3QgUGxheWVyU3RhdGUgewogICAgaWQ6IFBsYXllciwKICAgIHBvczogdTMyLAogICAgc2NvcmU6IHUzMiwKICAgIHJvbGxlZDogdTMyLAp9CgppbXBsIEdhbWUgewogICAgZm4gbmV3KHBvc2l0aW9uMTogdTMyLCBwb3NpdGlvbjI6IHUzMiwgd2luX3Njb3JlOiB1MzIpIC0+IFNlbGYgewogICAgICAgIEdhbWUgewogICAgICAgICAgICB3b246IE5vbmUsCiAgICAgICAgICAgIGdhbWVfc2NvcmU6IE5vbmUsCiAgICAgICAgICAgIHN0YXRlOiBHYW1lU3RhdGUgewogICAgICAgICAgICAgICAgd2luX3Njb3JlLAogICAgICAgICAgICAgICAgdHJhY2tfbGVuOiAxMCwKICAgICAgICAgICAgICAgIHBsYXllcjE6IFBsYXllclN0YXRlIHsKICAgICAgICAgICAgICAgICAgICBpZDogUGxheWVyOjpPbmUsCiAgICAgICAgICAgICAgICAgICAgcG9zOiBwb3NpdGlvbjEsCiAgICAgICAgICAgICAgICAgICAgc2NvcmU6IDAsCiAgICAgICAgICAgICAgICAgICAgcm9sbGVkOiAwLAogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIHBsYXllcjI6IFBsYXllclN0YXRlIHsKICAgICAgICAgICAgICAgICAgICBpZDogUGxheWVyOjpUd28sCiAgICAgICAgICAgICAgICAgICAgcG9zOiBwb3NpdGlvbjIsCiAgICAgICAgICAgICAgICAgICAgc2NvcmU6IDAsCiAgICAgICAgICAgICAgICAgICAgcm9sbGVkOiAwLAogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgfSwKICAgICAgICAgICAgZGljZXNfcm9sbGVkOiAwLAogICAgICAgICAgICBkaWNlOiBEaWNlIHsgbGFzdF9yb2xsOiAxIH0sCiAgICAgICAgfQogICAgfQoKICAgIGZuIHBsYXlfZGV0ZXJtaW5pc3RpYygmc2VsZikgLT4gU2VsZiB7CiAgICAgICAgbGV0IG11dCByZXN1bHQ6IEdhbWUgPSAqc2VsZjsKICAgICAgICBsb29wIHsKICAgICAgICAgICAgbGV0IHJvbGwxID0gcmVzdWx0LmRpY2Uucm9sbF9kKCk7CiAgICAgICAgICAgIGxldCByb2xsMiA9IHJlc3VsdC5kaWNlLnJvbGxfZCgpOwogICAgICAgICAgICBsZXQgKHN0YXRlLCByb2xsZWQpID0gcm91bmQoJihyb2xsMSwgcm9sbDIpLCAmcmVzdWx0LnN0YXRlKTsKICAgICAgICAgICAgcmVzdWx0LmRpY2VzX3JvbGxlZCArPSByb2xsZWQ7CiAgICAgICAgICAgIHJlc3VsdC5zdGF0ZSA9IHN0YXRlOwogICAgICAgICAgICBpZiByZXN1bHQuaXNfd2luKCkgewogICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBmbiBwbGF5X3F1YW50dW0oJnNlbGYsIHJvbGxzOiAmQlRyZWVNYXA8dTMyLCB1c2l6ZT4sIHdpbl9tYXA6ICZtdXQgV2luKSAtPiAodXNpemUsIHVzaXplKSB7CiAgICAgICAgbGV0IG11dCB3aW5zID0gKDAsIDApOwoKICAgICAgICBmb3IgKHJvbGwxLCBjb3VudDEpIGluIHJvbGxzLml0ZXIoKSB7CiAgICAgICAgICAgIGZvciAocm9sbDIsIGNvdW50MikgaW4gcm9sbHMuaXRlcigpIHsKICAgICAgICAgICAgICAgIGxldCAod2luMSwgd2luMikgPSBzZWxmLnF1YW50dW1fZ2FtZSgmKCpyb2xsMSwgKnJvbGwyKSwgd2luX21hcCwgcm9sbHMpOwogICAgICAgICAgICAgICAgbGV0IG11bHQgPSBjb3VudDEgKiBjb3VudDI7CiAgICAgICAgICAgICAgICB3aW5zLjAgKz0gbXVsdCAqIHdpbjE7CiAgICAgICAgICAgICAgICBpZiB3aW4xID09IDEgJiYgd2luMiA9PSAwIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHdpbnMuMSArPSBtdWx0ICogd2luMjsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICB3aW5zCiAgICB9CgogICAgZm4gcXVhbnR1bV9nYW1lKAogICAgICAgICZzZWxmLAogICAgICAgIGVudHJ5OiAmKHUzMiwgdTMyKSwKICAgICAgICB3aW5fbWFwOiAmbXV0IEJUcmVlTWFwPEdhbWVTdGF0ZSwgKHVzaXplLCB1c2l6ZSk+LAogICAgICAgIHJvbGxzOiAmQlRyZWVNYXA8dTMyLCB1c2l6ZT4sCiAgICApIC0+ICh1c2l6ZSwgdXNpemUpIHsKICAgICAgICBsZXQgbXV0IHJlc3VsdDogR2FtZSA9ICpzZWxmOwogICAgICAgIGxldCAoc3RhdGUsIF9yb2xsZWQpID0gcm91bmQoZW50cnksICZyZXN1bHQuc3RhdGUpOwogICAgICAgIHJlc3VsdC5zdGF0ZSA9IHN0YXRlOwogICAgICAgIGlmICFyZXN1bHQuaXNfd2luKCkgewogICAgICAgICAgICBpZiBsZXQgU29tZSh4KSA9IHdpbl9tYXAuZ2V0KCZzdGF0ZSkgewogICAgICAgICAgICAgICAgKngKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGxldCB0bXAgPSByZXN1bHQucGxheV9xdWFudHVtKHJvbGxzLCB3aW5fbWFwKTsKICAgICAgICAgICAgICAgIHJldHVybiAqd2luX21hcC5lbnRyeShzdGF0ZSkub3JfaW5zZXJ0KHRtcCk7CiAgICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgaWYgcmVzdWx0LndvbiA9PSBTb21lKFBsYXllcjo6T25lKSB7CiAgICAgICAgICAgICgxLCAwKQogICAgICAgIH0gZWxzZSBpZiByZXN1bHQud29uID09IFNvbWUoUGxheWVyOjpUd28pIHsKICAgICAgICAgICAgKDAsIDEpCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgKDAsIDApCiAgICAgICAgfQogICAgfQoKICAgIGZuIGlzX3dpbigmbXV0IHNlbGYpIC0+IGJvb2wgewogICAgICAgIGlmIHNlbGYuc3RhdGUucGxheWVyMS5zY29yZSA+PSBzZWxmLnN0YXRlLndpbl9zY29yZSB7CiAgICAgICAgICAgIHNlbGYud29uID0gU29tZShQbGF5ZXI6Ok9uZSk7CiAgICAgICAgICAgIHNlbGYuZ2FtZV9zY29yZSA9IFNvbWUoc2VsZi5zdGF0ZS5wbGF5ZXIyLnNjb3JlICogc2VsZi5kaWNlc19yb2xsZWQpOwogICAgICAgICAgICB0cnVlCiAgICAgICAgfSBlbHNlIGlmIHNlbGYuc3RhdGUucGxheWVyMi5zY29yZSA+PSBzZWxmLnN0YXRlLndpbl9zY29yZSB7CiAgICAgICAgICAgIHNlbGYud29uID0gU29tZShQbGF5ZXI6OlR3byk7CiAgICAgICAgICAgIHNlbGYuZ2FtZV9zY29yZSA9IFNvbWUoc2VsZi5zdGF0ZS5wbGF5ZXIxLnNjb3JlICogc2VsZi5kaWNlc19yb2xsZWQpOwogICAgICAgICAgICB0cnVlCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgZmFsc2UKICAgICAgICB9CiAgICB9Cn0KCmltcGwgRGljZSB7CiAgICBmbiByb2xsX2QoJm11dCBzZWxmKSAtPiB1MzIgewogICAgICAgIGxldCByb2xsID0gc2VsZi5sYXN0X3JvbGw7CiAgICAgICAgbGV0IHJvbGwgPSAzICogcm9sbCArIDM7CiAgICAgICAgc2VsZi5sYXN0X3JvbGwgKz0gMzsKICAgICAgICByb2xsCiAgICB9Cn0KCmltcGwgUGxheWVyU3RhdGUgewogICAgZm4gbmV3X3Bvc2l0aW9uKCZzZWxmLCB0cmFja19sZW46IHUzMiwgcm9sbDogdTMyKSAtPiB1MzIgewogICAgICAgIGxldCBwb3MgPSAoc2VsZi5wb3MgKyByb2xsKSAlIHRyYWNrX2xlbjsKICAgICAgICBpZiBwb3MgPT0gMCB7CiAgICAgICAgICAgIHRyYWNrX2xlbgogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHBvcwogICAgICAgIH0KICAgIH0KCiAgICBmbiByb2xsZWQoJm11dCBzZWxmLCB0cmFja19sZW46IHUzMiwgcm9sbDogdTMyKSB7CiAgICAgICAgc2VsZi5wb3MgPSBzZWxmLm5ld19wb3NpdGlvbih0cmFja19sZW4sIHJvbGwpOwogICAgICAgIHNlbGYuc2NvcmUgKz0gc2VsZi5wb3M7CiAgICB9Cn0KCnR5cGUgUm9sbCA9ICh1MzIsIHUzMik7CgpmbiByb3VuZChkaWNlX3JvbGw6ICZSb2xsLCBzdGF0ZTogJkdhbWVTdGF0ZSkgLT4gKEdhbWVTdGF0ZSwgdTMyKSB7CiAgICBsZXQgbXV0IG5ld19zdGF0ZSA9ICpzdGF0ZTsKICAgIG5ld19zdGF0ZS5wbGF5ZXIxLnJvbGxlZChzdGF0ZS50cmFja19sZW4sIGRpY2Vfcm9sbC4wKTsKICAgIGlmIG5ld19zdGF0ZS5wbGF5ZXIxLnNjb3JlID49IHN0YXRlLndpbl9zY29yZSB7CiAgICAgICAgcmV0dXJuIChuZXdfc3RhdGUsIDMpOwogICAgfQogICAgbmV3X3N0YXRlLnBsYXllcjIucm9sbGVkKHN0YXRlLnRyYWNrX2xlbiwgZGljZV9yb2xsLjEpOwogICAgKG5ld19zdGF0ZSwgNikKfQo=