Files
contests/projecteuler/084/src/main.rs

284 lines
7.3 KiB
Rust

use rand::prelude::*;
#[derive(Debug, Clone, Copy)]
enum CommunityChest {
ToGo,
ToJail,
Empty,
}
struct CommunityChestDeck {
deck: Vec<CommunityChest>,
current_index: usize,
}
impl CommunityChestDeck {
fn next(&mut self) -> CommunityChest {
self.current_index = (self.current_index + 1) % self.deck.len();
self.deck[self.current_index]
}
}
#[derive(Debug, Clone, Copy)]
enum Chance {
ToGo,
ToJail,
ToC1,
ToE3,
ToH2,
ToR1,
ToNextRailway,
ToNextUtility,
GoBack3,
Empty,
}
struct ChanceDeck {
deck: Vec<Chance>,
current_index: usize,
}
impl ChanceDeck {
fn next(&mut self) -> Chance {
self.current_index = (self.current_index + 1) % self.deck.len();
self.deck[self.current_index]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum TileType {
Go,
Jail,
GoToJail,
C1,
E3,
H2,
R1,
Railway,
Utility,
Empty,
CommunityChest,
Chance,
}
use TileType::*;
struct Board {
board: Vec<TileType>,
current_index: usize,
}
impl Board {
fn next(&mut self) -> TileType {
self.current_index = (self.current_index + 1) % self.board.len();
self.board[self.current_index]
}
fn prev(&mut self) -> TileType {
self.current_index = ((self.current_index as i32 - 1) % self.board.len() as i32) as usize;
self.board[self.current_index]
}
}
struct DoubleDice {
sides: u32,
rng: ThreadRng,
}
impl DoubleDice {
// Need to know each specific throw because we need to keep track of the doubles
fn throw(&mut self) -> (u32, u32) {
let dice1 = self.rng.gen_range(1..=self.sides);
let dice2 = self.rng.gen_range(1..=self.sides);
(dice1, dice2)
}
}
enum ThrowResult {
ToJail,
Moves(u32),
}
fn handle_dice(dice: &mut DoubleDice, past_throws: &mut [(u32, u32)]) -> ThrowResult {
let dice_throw = dice.throw();
if past_throws[0] == past_throws[1] && past_throws[1] == dice_throw {
past_throws[0] = (0, 0);
past_throws[1] = (0, 0);
ThrowResult::ToJail
} else {
past_throws[0] = past_throws[1];
past_throws[1] = dice_throw;
ThrowResult::Moves(dice_throw.0 + dice_throw.1)
}
}
fn main() {
println!("Hello, this is Patrick!");
let mut rng = thread_rng();
// First create card decks, board and dice
let mut community_chest_cards = vec![
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::Empty,
CommunityChest::ToGo,
CommunityChest::ToJail,
];
community_chest_cards.shuffle(&mut rng);
let mut chance_cards = vec![
Chance::Empty,
Chance::Empty,
Chance::Empty,
Chance::Empty,
Chance::Empty,
Chance::Empty,
Chance::ToGo,
Chance::ToJail,
Chance::ToC1,
Chance::ToE3,
Chance::ToH2,
Chance::ToR1,
Chance::ToNextRailway,
Chance::ToNextRailway,
Chance::ToNextUtility,
Chance::GoBack3,
];
chance_cards.shuffle(&mut rng);
let board_tiles = vec![
Go,
Empty,
CommunityChest,
Empty,
Empty,
R1,
Empty,
Chance,
Empty,
Empty,
Jail,
C1,
Utility,
Empty,
Empty,
Railway,
Empty,
CommunityChest,
Empty,
Empty,
Empty,
Empty,
Chance,
Empty,
E3,
Railway,
Empty,
Empty,
Utility,
Empty,
GoToJail,
Empty,
Empty,
CommunityChest,
Empty,
Railway,
Chance,
Empty,
Empty,
H2,
];
let mut cc_deck = CommunityChestDeck {
deck: community_chest_cards,
current_index: 0,
};
let mut chance_deck = ChanceDeck {
deck: chance_cards,
current_index: 0,
};
let mut board = Board {
board: board_tiles,
current_index: 0,
};
let mut dice = DoubleDice { sides: 4, rng };
let mut square_popularity = vec![0; board.board.len()];
let mut dice_throws = [(0, 0), (0, 0)];
for _ in 0..2000000 {
match handle_dice(&mut dice, &mut dice_throws) {
ThrowResult::ToJail => {
board.current_index = 10;
}
ThrowResult::Moves(n) => {
let mut next_tile = Empty;
for _ in 0..n {
next_tile = board.next();
}
match next_tile {
GoToJail => {
board.current_index = 10;
}
CommunityChest => {
let card_drawn = cc_deck.next();
match card_drawn {
CommunityChest::ToGo => {
board.current_index = 0;
}
CommunityChest::ToJail => {
board.current_index = 10;
}
_ => {}
}
}
Chance => {
let card_drawn = chance_deck.next();
match card_drawn {
Chance::ToJail => {
board.current_index = 10;
}
Chance::ToGo => {
board.current_index = 0;
}
Chance::Empty => {}
Chance::GoBack3 => {
for _ in 0..3 {
_ = board.prev()
}
}
Chance::ToC1 => while board.next() != TileType::C1 {},
Chance::ToE3 => while board.next() != TileType::E3 {},
Chance::ToH2 => while board.next() != TileType::H2 {},
Chance::ToNextUtility => while board.next() != TileType::Utility {},
Chance::ToR1 => while board.next() != TileType::R1 {},
Chance::ToNextRailway => {
let mut next_tile = board.next();
while next_tile != TileType::R1 && next_tile != TileType::Railway {
next_tile = board.next();
}
}
}
}
_ => {}
}
}
}
square_popularity[board.current_index] += 1;
}
let mut squares_sorted: Vec<(usize, u32)> = square_popularity.into_iter().enumerate().collect();
squares_sorted.sort_by(|(_, a), (_, b)| a.cmp(b));
println!("Square popularity: {:?}", squares_sorted);
}