DEVELOPMENT ENVIRONMENT

~liljamo/deck-builder

ref: b764b2150cb7a3f64fb03177893ab0b6ed650674 deck-builder/client/src/game_status/parser.rs -rw-r--r-- 3.3 KiB
b764b215Jonni Liljamo feat(client): player state, state change command 1 year, 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
 * 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}, game_status::SupplyPile};

use super::{GameStatus, PlayerState, PlayerStatus, Card};

pub fn parse(game: &Game) -> Result<GameStatus, ()> {
    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::<u64>().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);
}