azul: fix add_color

This commit is contained in:
Daniel Lovbrotte Olsen 2024-01-30 03:14:20 +01:00
parent 75447b6176
commit a0edf8f87e
3 changed files with 87 additions and 37 deletions

1
Cargo.lock generated
View File

@ -632,6 +632,7 @@ dependencies = [
"rand",
"rocket",
"serde",
"serde_json",
]
[[package]]

View File

@ -10,3 +10,4 @@ rocket = { version = "0.5.0", features = ["json"] }
serde = "1.0.196"
rand = "0.8.5"
serde_json = "1.0.113"

View File

@ -6,11 +6,8 @@ use serde::{Deserialize, Serialize};
use rand::distributions::WeightedIndex;
use rand::prelude::*;
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize)]
struct GameState {
#[serde(skip)]
#[serde(default = "make_rng")]
rng: StdRng,
n_players: usize,
current_player: usize,
starting_player: usize,
@ -22,10 +19,32 @@ struct GameState {
factories: Vec<TileSet>,
market: TileSetWithStart,
players: Vec<Player>,
#[serde(skip)]
#[serde(default = "make_rng")]
rng: Box<dyn RngCore>,
}
fn make_rng() -> StdRng {
StdRng::from_entropy()
fn make_rng() -> Box<dyn RngCore> {
Box::new(StdRng::from_entropy())
}
impl Clone for GameState {
fn clone(&self) -> Self {
GameState {
n_players: self.n_players,
current_player: self.current_player,
starting_player: self.starting_player,
game_end: self.game_end,
rounds: self.rounds,
days: self.days,
bag: self.bag.clone(),
lid: self.lid.clone(),
factories: self.factories.clone(),
market: self.market.clone(),
players: self.players.clone(),
rng: make_rng(),
}
}
}
impl GameState {
@ -56,7 +75,6 @@ impl GameState {
}
let game = GameState {
rng: StdRng::from_entropy(),
n_players,
current_player: 0,
starting_player: 0,
@ -81,6 +99,7 @@ impl GameState {
white: 0,
},
players,
rng: Box::new(StdRng::from_entropy()),
};
Ok(game)
@ -90,7 +109,7 @@ impl GameState {
/// Will replenish the bag from the lid when empty
/// Will return with partially filled factories if out of tiles
fn fill(&mut self) -> Result<(), &'static str> {
if !self.is_empty() {
if !self.only_start() {
return Err("Cannot fill, there are still tiles left to be picked");
}
@ -101,28 +120,29 @@ impl GameState {
self.lid = TileSet::default();
} else if self.bag.is_empty() {
return Ok(());
} else {
let choices = [
Color::Blue,
Color::Yellow,
Color::Red,
Color::Black,
Color::White,
];
let weights = [
self.bag.blue,
self.bag.yellow,
self.bag.red,
self.bag.black,
self.bag.white,
];
let dist = WeightedIndex::new(&weights).unwrap();
let picked = choices[dist.sample(&mut self.rng)];
self.bag.add_color(picked, 1)?;
factory.add_color(picked, 1)?;
}
let choices = [
Color::Blue,
Color::Yellow,
Color::Red,
Color::Black,
Color::White,
];
let weights = [
self.bag.blue,
self.bag.yellow,
self.bag.red,
self.bag.black,
self.bag.white,
];
let dist = WeightedIndex::new(&weights).unwrap();
let picked = choices[dist.sample(&mut self.rng)];
eprintln!("picked {:?}", picked);
self.bag.add_color(picked, -1)?;
factory.add_color(picked, 1)?;
}
}
@ -137,6 +157,16 @@ impl GameState {
factories && market
}
/// Returns whether or not only the start tile is in play
fn only_start(&self) -> bool {
let factories = self.factories.iter().all(|f| f.is_empty());
let market = Color::Blue
.into_iter()
.all(|c| self.market.get_color(c) == 0);
factories && market
}
/// Scores the game and clears the boards into the lid
/// Doesn't check if game is ready to be scored!
fn score_unchecked(&mut self) -> Result<(), &'static str> {
@ -378,16 +408,16 @@ impl TileSet {
self.blue = usize::checked_add_signed(self.blue, n).ok_or("would overflow!")?
}
Color::Yellow => {
self.blue = usize::checked_add_signed(self.yellow, n).ok_or("would overflow")?
self.yellow = usize::checked_add_signed(self.yellow, n).ok_or("would overflow")?
}
Color::Red => {
self.blue = usize::checked_add_signed(self.red, n).ok_or("would overflow")?
self.red = usize::checked_add_signed(self.red, n).ok_or("would overflow")?
}
Color::Black => {
self.blue = usize::checked_add_signed(self.black, n).ok_or("would overflow")?
self.black = usize::checked_add_signed(self.black, n).ok_or("would overflow")?
}
Color::White => {
self.blue = usize::checked_add_signed(self.white, n).ok_or("would overflow")?
self.white = usize::checked_add_signed(self.white, n).ok_or("would overflow")?
}
Color::Start => return Err("tried to add Start tiles to TileSet"),
}
@ -483,16 +513,16 @@ impl TileSetWithStart {
self.blue = usize::checked_add_signed(self.blue, n).ok_or("would overflow!")?
}
Color::Yellow => {
self.blue = usize::checked_add_signed(self.yellow, n).ok_or("would overflow")?
self.yellow = usize::checked_add_signed(self.yellow, n).ok_or("would overflow")?
}
Color::Red => {
self.blue = usize::checked_add_signed(self.red, n).ok_or("would overflow")?
self.red = usize::checked_add_signed(self.red, n).ok_or("would overflow")?
}
Color::Black => {
self.blue = usize::checked_add_signed(self.black, n).ok_or("would overflow")?
self.black = usize::checked_add_signed(self.black, n).ok_or("would overflow")?
}
Color::White => {
self.blue = usize::checked_add_signed(self.white, n).ok_or("would overflow")?
self.white = usize::checked_add_signed(self.white, n).ok_or("would overflow")?
}
Color::Start if n == 1 && self.start == 0 => {
self.start = usize::checked_add_signed(self.white, n).ok_or("would overflow")?
@ -800,3 +830,21 @@ enum Destination {
#[serde(rename = "floor")]
Floor,
}
// Tests
use serde_json::to_string_pretty;
#[test]
fn test_fill() {
let mut game = GameState::new(2).unwrap();
// println!("{}", to_string_pretty(&game).unwrap());
assert!(game.only_start());
game.fill();
//println!("{}", to_string_pretty(&game).unwrap());
assert_eq!(game.bag.len(), 100 - (5 * 4));
assert_eq!(game.factories.iter().map(|f| f.len()).sum::<usize>(), 5 * 4);
}