add code for 84 (WIP)
This commit is contained in:
@@ -7,3 +7,5 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
strum = "0.24.1"
|
||||||
|
strum_macros = "0.24.1"
|
||||||
|
|||||||
+188
-12
@@ -1,7 +1,15 @@
|
|||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
use std::iter::Cycle;
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rand::seq::IteratorRandom;
|
use rand::seq::IteratorRandom;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
use strum_macros::EnumIter;
|
||||||
|
|
||||||
enum Squares {
|
const NUMBER_SQUARES: usize = 40;
|
||||||
|
|
||||||
|
#[derive(Debug, EnumIter, PartialEq, Hash, Eq, PartialOrd)]
|
||||||
|
pub enum Squares {
|
||||||
Go = 0,
|
Go = 0,
|
||||||
A1 = 1,
|
A1 = 1,
|
||||||
CC1 = 2,
|
CC1 = 2,
|
||||||
@@ -9,7 +17,7 @@ enum Squares {
|
|||||||
T1 = 4,
|
T1 = 4,
|
||||||
R1 = 5,
|
R1 = 5,
|
||||||
B1 = 6,
|
B1 = 6,
|
||||||
Ch1 = 7,
|
CH1 = 7,
|
||||||
B2 = 8,
|
B2 = 8,
|
||||||
B3 = 9,
|
B3 = 9,
|
||||||
Jail = 10,
|
Jail = 10,
|
||||||
@@ -24,7 +32,7 @@ enum Squares {
|
|||||||
D3 = 19,
|
D3 = 19,
|
||||||
FP = 20,
|
FP = 20,
|
||||||
E1 = 21,
|
E1 = 21,
|
||||||
Ch2 = 22,
|
CH2 = 22,
|
||||||
E2 = 23,
|
E2 = 23,
|
||||||
E3 = 24,
|
E3 = 24,
|
||||||
R3 = 25,
|
R3 = 25,
|
||||||
@@ -32,10 +40,10 @@ enum Squares {
|
|||||||
F2 = 27,
|
F2 = 27,
|
||||||
U2 = 28,
|
U2 = 28,
|
||||||
F3 = 29,
|
F3 = 29,
|
||||||
G2j = 30,
|
G2J = 30,
|
||||||
G1 = 31,
|
G1 = 31,
|
||||||
G2 = 32,
|
G2 = 32,
|
||||||
Cc3 = 33,
|
CC3 = 33,
|
||||||
G3 = 34,
|
G3 = 34,
|
||||||
R4 = 35,
|
R4 = 35,
|
||||||
Ch3 = 36,
|
Ch3 = 36,
|
||||||
@@ -44,11 +52,13 @@ enum Squares {
|
|||||||
H2 = 39,
|
H2 = 39,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, EnumIter, Clone)]
|
||||||
enum CommunityChest {
|
enum CommunityChest {
|
||||||
AdvanceToGo,
|
AdvanceToGo,
|
||||||
GoToJail,
|
GoToJail,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, EnumIter, Clone)]
|
||||||
enum Chance {
|
enum Chance {
|
||||||
AdvanceToGo,
|
AdvanceToGo,
|
||||||
GoToJail,
|
GoToJail,
|
||||||
@@ -62,28 +72,194 @@ enum Chance {
|
|||||||
GoBack3Squares,
|
GoBack3Squares,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
enum Dice {
|
enum Dice {
|
||||||
FourSided = 4,
|
FourSided = 4,
|
||||||
SixSided = 6,
|
SixSided = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dice {
|
impl Dice {
|
||||||
fn throw(&self, rng: &mut ThreadRng) -> isize {
|
fn throw(&self, rng: &mut ThreadRng) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::SixSided => (1..=6).choose(rng).unwrap(),
|
Self::SixSided => (1..=6).choose(rng).unwrap() as usize,
|
||||||
Self::FourSided => (1..=4).choose(rng).unwrap(),
|
Self::FourSided => (1..=4).choose(rng).unwrap() as usize,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Monopoly {
|
pub struct Monopoly {
|
||||||
position: Squares,
|
rng: ThreadRng,
|
||||||
|
board: Cycle<SquaresIter>,
|
||||||
dice: Dice,
|
dice: Dice,
|
||||||
|
community_pile: VecDeque<CommunityChest>,
|
||||||
|
chance_pile: VecDeque<Chance>,
|
||||||
|
number_consecutive_doubles: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Monopoly {
|
impl Monopoly {
|
||||||
fn throw_dice(&mut self) {
|
fn throw_dice(&mut self) -> (usize, bool) {
|
||||||
|
let mut iter = (0..2).map(|_| self.dice.throw(&mut self.rng));
|
||||||
|
let t1 = iter.next().unwrap();
|
||||||
|
let t2 = iter.next().unwrap();
|
||||||
|
let is_double = t1 == t2;
|
||||||
|
// dbg!(t1, t2);
|
||||||
|
(t1 + t2, is_double)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::new_without_default)]
|
||||||
|
pub fn new() -> Self {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let result: isize = (0..2).map(|_| self.dice.throw(&mut rng)).sum();
|
let community_pile = Self::gen_random_community_pile(&mut rng);
|
||||||
|
let chance_pile = Self::gen_random_chance_pile(&mut rng);
|
||||||
|
Self {
|
||||||
|
rng,
|
||||||
|
board: Squares::iter().cycle(),
|
||||||
|
dice: Dice::SixSided,
|
||||||
|
community_pile,
|
||||||
|
chance_pile,
|
||||||
|
number_consecutive_doubles: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_random_chance_pile(rng: &mut ThreadRng) -> VecDeque<Chance> {
|
||||||
|
let mut instances: Vec<_> = Chance::iter().collect();
|
||||||
|
instances.shuffle(rng);
|
||||||
|
instances.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_random_community_pile(rng: &mut ThreadRng) -> VecDeque<CommunityChest> {
|
||||||
|
let mut instances: Vec<_> = CommunityChest::iter().collect();
|
||||||
|
instances.shuffle(rng);
|
||||||
|
instances.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn make_move(&mut self) -> Squares {
|
||||||
|
let (distance, is_double) = self.throw_dice();
|
||||||
|
if self.check_too_many_doubles(is_double) {
|
||||||
|
return self.go_to_jail();
|
||||||
|
}
|
||||||
|
|
||||||
|
let square = self.board.nth(distance).unwrap();
|
||||||
|
match square {
|
||||||
|
Squares::G2J => self.go_to_jail(),
|
||||||
|
Squares::CC1 | Squares::CC2 | Squares::CC3 => self.handle_community_chest(),
|
||||||
|
Squares::CH1 | Squares::CH2 => self.handle_chance(),
|
||||||
|
_ => square,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_to_jail(&mut self) -> Squares {
|
||||||
|
let _ = (&mut self.board).skip_while(|c| *c != Squares::Jail);
|
||||||
|
Squares::Jail
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_chance(&mut self) -> Squares {
|
||||||
|
let card = self.draw_from_chance_pile_and_put_at_bottom();
|
||||||
|
// dbg!(card);
|
||||||
|
match card {
|
||||||
|
Chance::AdvanceToGo => self.advance_to_go(),
|
||||||
|
Chance::GoToJail => self.go_to_jail(),
|
||||||
|
Chance::GoToC1 => self.go_to_square(Squares::C1),
|
||||||
|
Chance::GoToE3 => self.go_to_square(Squares::E3),
|
||||||
|
Chance::GoToH2 => self.go_to_square(Squares::H2),
|
||||||
|
Chance::GoToR1 => self.go_to_square(Squares::R1),
|
||||||
|
Chance::GoToNextR | Chance::GoToNextRAgain => self.go_to_railway(),
|
||||||
|
Chance::GoToNextU => self.go_to_utility(),
|
||||||
|
Chance::GoBack3Squares => self.go_back_3_squares(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_to_square(&mut self, square: Squares) -> Squares {
|
||||||
|
let _ = (&mut self.board).skip_while(|c| *c != square);
|
||||||
|
square
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_to_squares(&mut self, squares: &[Squares]) -> Squares {
|
||||||
|
let result = self.board.find(|c| squares.iter().any(|s| s == c)).unwrap();
|
||||||
|
assert!(squares.contains(&result));
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_community_chest(&mut self) -> Squares {
|
||||||
|
let card = self.draw_from_community_chest_pile_and_put_at_bottom();
|
||||||
|
match card {
|
||||||
|
CommunityChest::AdvanceToGo => self.advance_to_go(),
|
||||||
|
CommunityChest::GoToJail => self.go_to_jail(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_to_go(&mut self) -> Squares {
|
||||||
|
let _ = (&mut self.board).skip_while(|c| *c != Squares::Go);
|
||||||
|
Squares::Go
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_from_chance_pile_and_put_at_bottom(&mut self) -> &Chance {
|
||||||
|
let card = self.chance_pile.pop_front().unwrap();
|
||||||
|
self.chance_pile.push_back(card);
|
||||||
|
self.chance_pile.back().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_from_community_chest_pile_and_put_at_bottom(&mut self) -> &CommunityChest {
|
||||||
|
let card = self.community_pile.pop_front().unwrap();
|
||||||
|
self.community_pile.push_back(card);
|
||||||
|
self.community_pile.back().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_to_railway(&mut self) -> Squares {
|
||||||
|
self.go_to_squares(&[Squares::R1, Squares::R2, Squares::R3, Squares::R4])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_to_utility(&mut self) -> Squares {
|
||||||
|
self.go_to_squares(&[Squares::U1, Squares::U2])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_back_3_squares(&mut self) -> Squares {
|
||||||
|
self.board.nth(NUMBER_SQUARES - 3).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_too_many_doubles(&mut self, is_double: bool) -> bool {
|
||||||
|
if is_double {
|
||||||
|
self.number_consecutive_doubles += 1;
|
||||||
|
self.number_consecutive_doubles == 3
|
||||||
|
} else {
|
||||||
|
self.number_consecutive_doubles = 0;
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Statistics {
|
||||||
|
monopoly: Monopoly,
|
||||||
|
iterations: usize,
|
||||||
|
fields_count: HashMap<Squares, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statistics {
|
||||||
|
pub fn new(monopoly: Monopoly, iterations: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
monopoly,
|
||||||
|
iterations,
|
||||||
|
fields_count: HashMap::from_iter(Squares::iter().zip([0].into_iter().cycle())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
for _ in 0..self.iterations {
|
||||||
|
let square = self.monopoly.make_move();
|
||||||
|
*self.fields_count.get_mut(&square).unwrap() += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn show(&self) {
|
||||||
|
let mut result: Vec<(&Squares, f64)> = self
|
||||||
|
.fields_count
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k, *v as f64 / self.iterations as f64 * 100.))
|
||||||
|
.collect();
|
||||||
|
result.sort_unstable_by(|(_, v1), (_, v2)| v2.partial_cmp(v1).unwrap());
|
||||||
|
for (s, v) in result {
|
||||||
|
println!("{s:?}: {v}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
mod lib;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
let monopoly = lib::Monopoly::new();
|
||||||
|
let mut statistics = lib::Statistics::new(monopoly, 100_000);
|
||||||
|
statistics.run();
|
||||||
|
statistics.show();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user