use crate::{
state::gamestate::GameState,
util::rng::GameRng,
ids::{CardId, PlayerId},
rules::schema::Ruleset,
};
pub fn initialize_game(
mut state: GameState,
rules: &Ruleset,
seed: u64,
) -> GameState {
let mut rng = GameRng::new(seed);
let num_players = state.players.len() as u32;
for i in 0..num_players {
let player_id = PlayerId(i as u8);
shuffle_player_deck(&mut state, player_id, &mut rng, rules);
}
let first_player = determine_first_player(&rules.players.first_player_rule, num_players, &mut rng);
state.turn.active_player = first_player;
state.turn.priority_player = first_player;
let skip_first_draw = rules.turn.skip_first_turn_draw_for_first_player;
for i in 0..num_players {
let player_id = PlayerId(i as u8);
let should_skip = skip_first_draw && player_id == first_player;
if !should_skip {
draw_cards(&mut state, player_id, rules.players.starting_hand_size as u32, rules);
}
}
state
}
fn shuffle_player_deck(
state: &mut GameState,
player: PlayerId,
rng: &mut GameRng,
_rules: &Ruleset,
) {
let deck_zone_id_string = format!("deck@{}", player.0);
let deck_zone = state.zones.iter_mut()
.find(|z| z.id.0 == deck_zone_id_string);
if let Some(zone) = deck_zone {
for i in (1..zone.cards.len()).rev() {
let j: usize = rng.generate::<u32>() as usize % (i + 1);
zone.cards.swap(i, j);
}
}
}
fn determine_first_player(
rule: &str,
num_players: u32,
rng: &mut GameRng,
) -> PlayerId {
match rule {
"random" => {
let idx: u32 = rng.generate::<u32>() % num_players;
PlayerId(idx as u8)
}
"player_0" | "first" => PlayerId(0),
"player_1" | "second" => {
if num_players > 1 {
PlayerId(1)
} else {
PlayerId(0)
}
}
_ => {
let idx: u32 = rng.generate::<u32>() % num_players;
PlayerId(idx as u8)
}
}
}
fn draw_cards(
state: &mut GameState,
player: PlayerId,
count: u32,
rules: &Ruleset,
) {
let deck_zone_id_string = format!("deck@{}", player.0);
let hand_zone_id_string = format!("hand@{}", player.0);
let deck_cards: Vec<CardId> = state.zones.iter()
.find(|z| z.id.0 == deck_zone_id_string)
.map(|z| z.cards.clone())
.unwrap_or_default();
let cards_to_draw = deck_cards.iter()
.take(count as usize)
.cloned()
.collect::<Vec<_>>();
if let Some(deck_zone) = state.zones.iter_mut()
.find(|z| z.id.0 == deck_zone_id_string)
{
for _ in 0..cards_to_draw.len() {
if !deck_zone.cards.is_empty() {
deck_zone.cards.remove(0);
}
}
}
if let Some(hand_zone) = state.zones.iter_mut()
.find(|z| z.id.0 == hand_zone_id_string)
{
for card in cards_to_draw {
if hand_zone.cards.len() < rules.players.max_hand_size {
hand_zone.cards.push(card);
}
}
}
}