high tech fast game structs

This commit is contained in:
Daniel Olsen 2021-01-07 23:44:44 +01:00
parent a638ba8c6a
commit 8d6365b4a2
6 changed files with 608 additions and 18 deletions

3
.gitignore vendored
View File

@ -1 +1,4 @@
/target
/flamegraph.svg
/perf.data
/perf.data.old

69
Cargo.lock generated
View File

@ -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"

View File

@ -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 }

View File

@ -1,7 +1,7 @@
let
moz_overlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz);
nixpkgs = import <nixos-unstable> { 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

View File

@ -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<Game, &'static str> {
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::<Game>());
}
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::<Game2>());
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(())
}

View File

@ -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")
}
}