/* * This file is part of laurelin_client * Copyright (C) 2023 Jonni Liljamo * * 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}, game_status::SupplyPile}; use super::{GameStatus, PlayerState, PlayerStatus, Card}; pub fn parse(game: &Game) -> Result { let mut game_status = GameStatus { actions: game.actions.as_ref().unwrap().to_vec(), supply_piles: vec![], players: HashMap::new() }; game_status.players.insert(game.host_id.clone(), PlayerStatus { state: PlayerState::Idle, currency: 0, vp: 2, hand: vec![], deck: vec![], discard: vec![] }); game_status.players.insert(game.guest_id.clone(), PlayerStatus { state: PlayerState::Idle, currency: 0, vp: 2, hand: vec![], deck: vec![], discard: vec![] }); // TODO: a system for reparsing if needed, e.g. after something // modifies the actions Vector. 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.parse::().unwrap()); } 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)); } Command::ChangePlayerState { state } => { target.state = *state; } _ => 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); }