diff --git a/.gitignore b/.gitignore index ea8c4bf..55a3905 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /target +/flamegraph.svg +/perf.data +/perf.data.old \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 2e6c22e..d516d25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,10 +38,32 @@ name = "mercury" version = "0.1.0" dependencies = [ "coz", + "modular-bitfield", "rand", "tinyvec", ] +[[package]] +name = "modular-bitfield" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" +dependencies = [ + "modular-bitfield-impl", + "static_assertions", +] + +[[package]] +name = "modular-bitfield-impl" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "once_cell" version = "1.5.2" @@ -55,10 +77,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] -name = "rand" -version = "0.8.0" +name = "proc-macro2" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76330fb486679b4ace3670f117bbc9e16204005c4bde9c4bd372f45bed34f12" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c24fcd450d3fa2b592732565aa4f17a27a61c65ece4726353e000939b0edee34" dependencies = [ "libc", "rand_chacha", @@ -94,12 +134,35 @@ dependencies = [ "rand_core", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "tinyvec" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index e102287..a50eb0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,10 +7,12 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.0" +rand = "0.8.1" coz = "0.1" tinyvec = "1.1.0" +modular-bitfield = "0.11.2" + #jemallocator = "0.3.2" #mimalloc = { version = "0.1.22", default-features = false } diff --git a/shell.nix b/shell.nix index a51c134..3ab8928 100644 --- a/shell.nix +++ b/shell.nix @@ -1,7 +1,7 @@ let moz_overlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz); nixpkgs = import { overlays = [ moz_overlay ]; }; - rustNightlyChannel = (nixpkgs.rustChannelOf { date = "2020-03-19"; channel = "nightly"; }).rust.override { + rustNightlyChannel = (nixpkgs.rustChannelOf { date = "2021-01-01"; channel = "nightly"; }).rust.override { extensions = [ "rust-src" "rls-preview" @@ -22,7 +22,7 @@ with nixpkgs; stdenv.mkDerivation { name = "moz_overlay_shell"; buildInputs = [ - rustStableChannel + rustNightlyChannel (vscode-with-extensions.override { vscodeExtensions = with vscode-extensions; [ bbenoist.Nix diff --git a/src/azul.rs b/src/azul.rs index b5f2ae4..8c98060 100644 --- a/src/azul.rs +++ b/src/azul.rs @@ -1,5 +1,6 @@ use std::ops::{Deref, DerefMut}; use rand::prelude::*; +use rand::distributions::WeightedIndex; //use smallvec::{SmallVec, smallvec}; //use alloc_counter::{AllocCounterSystem, no_alloc}; @@ -365,22 +366,22 @@ impl Board { #[derive(Debug, Clone, Copy)] pub struct Game { turn: u32, - player: usize, + player: u8, box_top: Bag, bag: Bag, market: Market, - factories: tinyvec::ArrayVec<[Factory; 9]>, // TODO set to 9? - boards: tinyvec::ArrayVec<[Board; 4]> // TODO set to 4? + factories: tinyvec::ArrayVec<[Factory; 5]>, // TODO set to 9? + boards: tinyvec::ArrayVec<[Board; 2]> // TODO set to 4? } impl Game { pub fn new(players: u8) -> Result { let n_factories = get_n_factories(players)?; - let mut factories = tinyvec::ArrayVec::<[Factory; 9]>::new(); + let mut factories = tinyvec::ArrayVec::<[Factory; 5]>::new(); for _ in 0..n_factories { factories.push(Factory::default()) } - let mut boards = tinyvec::ArrayVec::<[Board; 4]>::new(); + let mut boards = tinyvec::ArrayVec::<[Board; 2]>::new(); for _ in 0..players { boards.push(Board::default()); } @@ -449,7 +450,7 @@ impl Game { } // #[no_alloc(forbid)] pub fn do_move(&mut self, game_move: GameMove) -> Result<(), &'static str> { - let board = &mut self.boards[self.player]; + let board = &mut self.boards[self.player as usize]; match game_move { GameMove(_, Tile::Start, _) => return Err("You can't take the start tile specifically"), GameMove(0, _, 0) => { @@ -504,7 +505,7 @@ impl Game { } }, GameMove(1..=9, _, _) => { - let board = &mut self.boards[self.player]; + let board = &mut self.boards[self.player as usize]; if game_move.0 > self.factories.len() { return Err("That factory is out of bounds"); } @@ -578,7 +579,7 @@ impl Game { self.player = (self.player + 1) % self.boards.len(); } */ - self.player = (self.player + 1) % self.boards.len(); + self.player = (self.player + 1) % self.boards.len() as u8; self.turn += 1; Ok(()) } @@ -643,4 +644,517 @@ fn game_move_iter() { #[test] fn sizes() { println!("size of azul game: {}", std::mem::size_of::()); +} + + +use modular_bitfield::prelude::*; + +#[derive(BitfieldSpecifier)] +#[bits = 3] +#[derive(Debug, Clone, Copy, PartialEq)] +enum Tile2 { + Blue, + Yellow, + Red, + Black, + Teal, + Start, + None +} + +impl Tile2 { + fn is_none(&self) -> bool { + *self == Tile2::None + } + fn is_some(&self) -> bool { + !self.is_none() + } +} + +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +enum Player2 { + One, + Two +} + +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Bag2 { + blue: B5, + yellow: B5, + red: B5, + black: B5, + teal: B5, +} + +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Factory2 { + one: Tile2, + two: Tile2, + three: Tile2, + four: Tile2 +} +impl Factory2 { + fn is_empty(&self) -> bool { + self.one().is_none() + && self.two().is_none() + && self.three().is_none() + && self.four().is_none() + } + fn is_full(&self) -> bool { + self.one().is_some() + && self.two().is_some() + && self.three().is_some() + && self.four().is_some() + } + fn add_to_first(&mut self, tile: Tile2) -> Result<(), Tile2> { + if self.one().is_none() { + self.set_one(tile); + return Ok(()); + } + else if self.two().is_none() { + self.set_two(tile); + return Ok(()); + } + else if self.three().is_none() { + self.set_three(tile); + return Ok(()); + } + else if self.four().is_none() { + self.set_four(tile); + return Ok(()); + } + Err(tile) + } +} + +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Factories2 { + one: Factory2, + two: Factory2, + three: Factory2, + four: Factory2, + five: Factory2, +} +impl Factories2 { + fn is_empty(&self) -> bool { + self.one().is_empty() + && self.two().is_empty() + && self.three().is_empty() + && self.four().is_empty() + && self.five().is_empty() + } + fn add_to_firsts(&mut self, tile: Tile2) -> Result<(), Tile2>{ + if !self.one().is_full() { + self.one().add_to_first(tile); + return Ok(()) + } + else if !self.two().is_full() { + self.two().add_to_first(tile); + return Ok(()) + } + else if !self.three().is_full() { + self.three().add_to_first(tile); + return Ok(()) + } + else if !self.four().is_full() { + self.four().add_to_first(tile); + return Ok(()) + } + else if !self.five().is_full() { + self.five().add_to_first(tile); + return Ok(()) + } + Err(tile) + } +} + +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Row2 { + one: bool, + two: bool, + three: bool, + four: bool, + five: bool +} + +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Wall2 { + one: Row2, + two: Row2, + three: Row2, + four: Row2, + five: Row2 +} +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Market2 { + blue: B5, + yellow: B5, + red: B5, + black: B5, + teal: B5, + start: bool +} + +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Pattern2_1 (Tile2, B1); +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Pattern2_2 (Tile2, B2); +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Pattern2_3 (Tile2, B2); +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Pattern2_4 (Tile2, B3); +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Pattern2_5 (Tile2, B3); + +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Patterns2 { + one: Pattern2_1, + two: Pattern2_2, + three: Pattern2_3, + four: Pattern2_4, + five: Pattern2_5, +} + +#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +#[derive(Debug)] +struct Board2 { + score: B7, + wall: Wall2, + patterns: Patterns2, + floor: Market2 +} + +/*#[bitfield(filled = false)] +#[derive(BitfieldSpecifier)] +struct Boards2 { + one: Board2, + two: Board2 +}*/ + +#[bitfield] +#[derive(Debug, Copy, Clone)] +pub struct Game2 { + player: Player2, + box_top: Bag2, + bag: Bag2, + market: Market2, + factories: Factories2, + board_1: Board2, + board_2: Board2, + #[skip] + unused: B7 +} + +impl Game2 { + pub fn create() -> Self { + let game = Game2::new() + .with_player(Player2::One) + .with_box_top(Bag2::new() + .with_blue(0) + .with_yellow(0) + .with_red(0) + .with_black(0) + .with_teal(0) + ) + .with_bag(Bag2::new() + .with_blue(20) + .with_yellow(20) + .with_red(20) + .with_black(20) + .with_teal(20) + ) + .with_market(Market2::new() + .with_start(true) + .with_blue(0) + .with_yellow(0) + .with_red(0) + .with_black(0) + .with_teal(0) + ) + .with_factories(Factories2::new() + .with_one(Factory2::new() + .with_one(Tile2::None) + .with_two(Tile2::None) + .with_three(Tile2::None) + .with_four(Tile2::None) + ) + .with_two(Factory2::new() + .with_one(Tile2::None) + .with_two(Tile2::None) + .with_three(Tile2::None) + .with_four(Tile2::None) + ) + .with_three(Factory2::new() + .with_one(Tile2::None) + .with_two(Tile2::None) + .with_three(Tile2::None) + .with_four(Tile2::None) + ) + .with_four(Factory2::new() + .with_one(Tile2::None) + .with_two(Tile2::None) + .with_three(Tile2::None) + .with_four(Tile2::None) + ) + .with_five(Factory2::new() + .with_one(Tile2::None) + .with_two(Tile2::None) + .with_three(Tile2::None) + .with_four(Tile2::None) + ) + ) + .with_board_1(Board2::new() + .with_score(0) + .with_wall(Wall2::new() + .with_one(Row2::new() + .with_one(false) + .with_two(false) + .with_three(false) + .with_four(false) + .with_five(false) + ) + .with_two(Row2::new() + .with_one(false) + .with_two(false) + .with_three(false) + .with_four(false) + .with_five(false) + ) + .with_three(Row2::new() + .with_one(false) + .with_two(false) + .with_three(false) + .with_four(false) + .with_five(false) + ) + .with_four(Row2::new() + .with_one(false) + .with_two(false) + .with_three(false) + .with_four(false) + .with_five(false) + ) + .with_five(Row2::new() + .with_one(false) + .with_two(false) + .with_three(false) + .with_four(false) + .with_five(false) + ) + ) + .with_patterns(Patterns2::new() + .with_one(Pattern2_1::new() + .with_0(Tile2::None) + .with_1(0) + ) + .with_two(Pattern2_2::new() + .with_0(Tile2::None) + .with_1(0) + ) + .with_three(Pattern2_3::new() + .with_0(Tile2::None) + .with_1(0) + ) + .with_four(Pattern2_4::new() + .with_0(Tile2::None) + .with_1(0) + ) + .with_five(Pattern2_5::new() + .with_0(Tile2::None) + .with_1(0) + ) + ) + .with_floor(Market2::new() + .with_start(false) + .with_blue(0) + .with_yellow(0) + .with_red(0) + .with_black(0) + .with_teal(0) + ) + ) + .with_board_2(Board2::new() + .with_score(0) + .with_wall(Wall2::new() + .with_one(Row2::new() + .with_one(false) + .with_two(false) + .with_three(false) + .with_four(false) + .with_five(false) + ) + .with_two(Row2::new() + .with_one(false) + .with_two(false) + .with_three(false) + .with_four(false) + .with_five(false) + ) + .with_three(Row2::new() + .with_one(false) + .with_two(false) + .with_three(false) + .with_four(false) + .with_five(false) + ) + .with_four(Row2::new() + .with_one(false) + .with_two(false) + .with_three(false) + .with_four(false) + .with_five(false) + ) + .with_five(Row2::new() + .with_one(false) + .with_two(false) + .with_three(false) + .with_four(false) + .with_five(false) + ) + ) + .with_patterns(Patterns2::new() + .with_one(Pattern2_1::new() + .with_0(Tile2::None) + .with_1(0) + ) + .with_two(Pattern2_2::new() + .with_0(Tile2::None) + .with_1(0) + ) + .with_three(Pattern2_3::new() + .with_0(Tile2::None) + .with_1(0) + ) + .with_four(Pattern2_4::new() + .with_0(Tile2::None) + .with_1(0) + ) + .with_five(Pattern2_5::new() + .with_0(Tile2::None) + .with_1(0) + ) + ) + .with_floor(Market2::new() + .with_start(false) + .with_blue(0) + .with_yellow(0) + .with_red(0) + .with_black(0) + .with_teal(0) + ) + ); + game + } + pub fn fill(&mut self, mut rng: StdRng) -> Result<(), &'static str> { + if !self.factories().is_empty() { + return Err("Factories are not empty"); + } + + for _ in 0..(4*5) { + let choices = [Tile2::Blue, Tile2::Yellow, Tile2::Red, Tile2::Black, Tile2::Teal]; + let weights = [self.bag().blue(), self.bag().yellow(), self.bag().red(), self.bag().black(), self.bag().teal()]; + let dist = WeightedIndex::new(&weights).unwrap(); + + let tile = choices[dist.sample(&mut rng)]; + + match self.set_factories(self.factories().add_to_firsts(tile)) { + Err(e) => return Err("Couldn't add tile to factory"), + Ok(_) => { + if tile == Tile2::Blue { + self.set_bag(self.bag().with_blue(self.bag().blue() - 1)); + } + else if tile == Tile2::Yellow { + self.set_bag(self.bag().with_yellow(self.bag().yellow() - 1)); + } + } + }; + + println!("{:?}", tile); + println!("{:#?}", self.bag()); + //println!("{:#?}", self.factories()); + } + + Ok(()) +/* for factory in &mut self.factories { + for _ in 0..4 { + if self.bag.len() == 0 && self.box_top.len() > 0 { + self.bag.append(&mut self.box_top); + } + else if self.bag.len() == 0 { + return Ok(()) + } + else { + let tile_i:usize = rng.gen_range(0..self.bag.len()); + let tile = self.bag.remove(tile_i); + factory.push(tile); + } + } + }; +*/ + } + /*pub fn do_move(&mut self, game_move: GameMove) -> Result<(), &'static str> { + match game_move { + () => + } + }*/ +} + +use std::time::{Instant, Duration}; + +pub fn size_of_bitfields() -> Result<(), &'static str> { + //println!("size of bitfield game: {}", std::mem::size_of::()); + + let game2 = Game2::create(); + //println!("debug: {:#?}", game2); + //println!("{:?}", game2.into_bytes()); + + let now = Instant::now(); + for _ in 0..1_000_000_000 { + let mut game2_2 = game2.clone(); + game2_2.set_player(Player2::Two); + std::hint::black_box(game2_2); + } + let game_2_time = now.elapsed().as_nanos(); + + let game1 = Game::new(2)?; + + let now = Instant::now(); + for _ in 0..1_000_000_000 { + let mut game1_2 = game1.clone(); + game1_2.turn = 1; + std::hint::black_box(game1_2); + } + let game_1_time = now.elapsed().as_nanos(); + + println!("{} | {}", game_1_time, game_2_time); + + Ok(()) + + } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c369ac0..a9a0e28 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![feature(test)] + mod azul; use azul::*; use rand::prelude::*; @@ -13,14 +15,14 @@ fn main() -> Result<(), &'static str> { let program = std::env::args().nth(1).expect("no program given") .parse().unwrap_or(1); - size_of_stuff(); + // size_of_stuff(); return match program { 1 => { let mut rng = StdRng::seed_from_u64(42); let mut game = Game::new(2)?; game.fill(StdRng::from_rng(&mut rng).expect("rng error"))?; - println!("{:#?}", game); + //println!("{:#?}", game); game.do_move(GameMove(3, Tile::Red, 3))?; game.do_move(GameMove(1, Tile::Yellow, 2))?; @@ -29,15 +31,21 @@ fn main() -> Result<(), &'static str> { game.do_move(GameMove(0, Tile::Black, 4))?; game.do_move(GameMove(5, Tile::Black, 1))?; - // game.do_move(GameMove(0, Tile::Blue, 3))?; + game.do_move(GameMove(0, Tile::Blue, 3))?; - println!("{:#?}", game); + // println!("{:#?}", game); println!("{}", count_options(game, 1, 2)); Ok(()) }, 2 => calculate_options(), + 3 => size_of_bitfields(), + 4 => { + let mut game = Game2::create(); + game.fill(StdRng::seed_from_u64(42)); + Ok(()) + }, _ => Err("Not a valid program") } }