DEVELOPMENT ENVIRONMENT

~liljamo/deck-builder

ref: 6aef1e4c3df7b09fe0f40fa6e8498fc9249d7eea deck-builder/client/src/game_status/parser.rs -rw-r--r-- 2.9 KiB
6aef1e4c — skye feat(api): change action seed to string 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
/*
 * 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, 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 {
        hand: vec![],
        deck: vec![],
        discard: vec![]
    });

    game_status.players.insert(game.guest_id.clone(), PlayerStatus {
        hand: vec![],
        deck: vec![],
        discard: vec![]
    });

    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);
}