/*
* This file is part of laurelin_client
* Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
*
* Licensed under GPL-3.0-only.
* See LICENSE for licensing information.
*/
use std::collections::HashMap;
use fastrand::Rng;
use crate::{api::game::{Action, Command}, game_status::SupplyPile};
use super::{GameStatus, PlayerStatus, Card};
pub fn parse(actions_init: &Vec<Action>) -> Result<GameStatus, ()> {
let mut game_status = GameStatus {
actions: actions_init.to_vec(),
supply_piles: vec![],
players: HashMap::new(),
};
for action in &game_status.actions {
// the one who invoked the action
let invoker = game_status.players.get_mut(&action.invoker)
.unwrap_or_else(|| unreachable!());
// the one who the action affects, may also be the invoker, e.g. draw
let target = game_status.players.get_mut(&action.target)
.unwrap_or_else(|| unreachable!());
match &action.command {
Command::InitSupplyPile { card, amount } => {
let pile = SupplyPile {
card: card.clone(),
amount: *amount,
};
game_status.supply_piles.push(pile);
}
Command::TakeFromPile { index } => {
// index should be within range
assert!(*index <= game_status.supply_piles.len());
let pile = &mut game_status.supply_piles.get_mut(*index)
.unwrap_or_else(|| unreachable!());
// pile should not be empty
assert!(pile.amount > 0);
pile.amount = pile.amount - 1;
target.discard.push(pile.card.clone());
}
Command::Draw { amount } => {
for _ in 0..*amount {
if target.deck.is_empty() {
shuffle_discard_to_deck(target, action.seed);
}
target.hand.push(target.deck.pop()
.unwrap_or_else(|| unreachable!()));
}
}
Command::Discard { index } => {
// index should be within range
assert!(*index <= target.hand.len());
target.discard.push(target.hand.remove(*index));
}
_ => todo!(),
}
}
Ok(game_status)
}
fn shuffle_discard_to_deck(target: &mut PlayerStatus, seed: u64) {
let cards = target.discard.to_vec();
target.discard.clear();
target.deck = cards;
let rng = Rng::with_seed(seed);
rng.shuffle(&mut target.deck);
}