Add card structure and treasure card type
This commit is contained in:
		
							
								
								
									
										224
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										224
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -1,4 +1,7 @@
 | 
			
		||||
mod cards;
 | 
			
		||||
 | 
			
		||||
use async_std::{prelude::*, sync::RwLock};
 | 
			
		||||
use cards::*;
 | 
			
		||||
use itertools::Itertools;
 | 
			
		||||
use rand::{seq::SliceRandom, thread_rng};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
@@ -7,8 +10,6 @@ use tide::{Body, Redirect, Request, Response};
 | 
			
		||||
use tide_websockets::{Message, WebSocket, WebSocketConnection};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
type Card = String;
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
#[serde(tag = "type")]
 | 
			
		||||
enum ClientMessage {
 | 
			
		||||
@@ -70,23 +71,33 @@ struct PlayerState {
 | 
			
		||||
    name: String,
 | 
			
		||||
    draw_pile_count: usize,
 | 
			
		||||
    hand_count: usize,
 | 
			
		||||
    discard_pile: Option<Card>,
 | 
			
		||||
    played_cards: Vec<Card>,
 | 
			
		||||
    discard_pile: Option<String>,
 | 
			
		||||
    played_cards: Vec<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
struct PileState {
 | 
			
		||||
    name: String,
 | 
			
		||||
    name: Card,
 | 
			
		||||
    count: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
#[derive(Clone, Serialize)]
 | 
			
		||||
struct TurnState {
 | 
			
		||||
    actions: u32,
 | 
			
		||||
    buys: u32,
 | 
			
		||||
    coin: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for TurnState {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        TurnState {
 | 
			
		||||
            actions: 1,
 | 
			
		||||
            buys: 1,
 | 
			
		||||
            coin: 0,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Player {
 | 
			
		||||
    id: String,
 | 
			
		||||
    name: String,
 | 
			
		||||
@@ -121,10 +132,6 @@ impl Player {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn play_card(&mut self, index: usize) {
 | 
			
		||||
        self.played_cards.push(self.hand.remove(index));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn discard(&mut self, index: usize) {
 | 
			
		||||
        self.discard_pile.push(self.hand.remove(index));
 | 
			
		||||
    }
 | 
			
		||||
@@ -141,16 +148,16 @@ impl Default for GameSetup {
 | 
			
		||||
    fn default() -> GameSetup {
 | 
			
		||||
        GameSetup {
 | 
			
		||||
            deck: vec![
 | 
			
		||||
                "Copper".into(),
 | 
			
		||||
                "Copper".into(),
 | 
			
		||||
                "Copper".into(),
 | 
			
		||||
                "Copper".into(),
 | 
			
		||||
                "Copper".into(),
 | 
			
		||||
                "Copper".into(),
 | 
			
		||||
                "Copper".into(),
 | 
			
		||||
                "Estate".into(),
 | 
			
		||||
                "Estate".into(),
 | 
			
		||||
                "Estate".into(),
 | 
			
		||||
                copper(),
 | 
			
		||||
                copper(),
 | 
			
		||||
                copper(),
 | 
			
		||||
                copper(),
 | 
			
		||||
                copper(),
 | 
			
		||||
                copper(),
 | 
			
		||||
                copper(),
 | 
			
		||||
                estate(),
 | 
			
		||||
                estate(),
 | 
			
		||||
                estate(),
 | 
			
		||||
            ],
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -162,8 +169,9 @@ struct Game {
 | 
			
		||||
    setup: GameSetup,
 | 
			
		||||
    connections: HashMap<Uuid, (String, WebSocketConnection)>,
 | 
			
		||||
    active_player: usize,
 | 
			
		||||
    supply: Vec<(String, usize)>,
 | 
			
		||||
    supply: Vec<(Card, usize)>,
 | 
			
		||||
    trash: Vec<Card>,
 | 
			
		||||
    turn_state: TurnState,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Game {
 | 
			
		||||
@@ -176,6 +184,7 @@ impl Game {
 | 
			
		||||
            active_player: 0,
 | 
			
		||||
            supply: vec![],
 | 
			
		||||
            trash: vec![],
 | 
			
		||||
            turn_state: TurnState::default(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -195,23 +204,114 @@ impl Game {
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                self.supply = vec![
 | 
			
		||||
                    ("Copper".into(), 60 - self.players.len() * 7),
 | 
			
		||||
                    ("Silver".into(), 40),
 | 
			
		||||
                    ("Gold".into(), 30),
 | 
			
		||||
                    ("Estate".into(), victory_qty),
 | 
			
		||||
                    ("Duchery".into(), victory_qty),
 | 
			
		||||
                    ("Province".into(), victory_qty),
 | 
			
		||||
                    ("Curse".into(), 10),
 | 
			
		||||
                    ("Cellar".into(), 10),
 | 
			
		||||
                    ("Moat".into(), 10),
 | 
			
		||||
                    ("Village".into(), 10),
 | 
			
		||||
                    ("Merchant".into(), 10),
 | 
			
		||||
                    ("Workshop".into(), 10),
 | 
			
		||||
                    ("Smithy".into(), 10),
 | 
			
		||||
                    ("Remodel".into(), 10),
 | 
			
		||||
                    ("Militia".into(), 10),
 | 
			
		||||
                    ("Market".into(), 10),
 | 
			
		||||
                    ("Mine".into(), 10),
 | 
			
		||||
                    (copper(), 60 - self.players.len() * 7),
 | 
			
		||||
                    (silver(), 40),
 | 
			
		||||
                    (gold(), 30),
 | 
			
		||||
                    (estate(), victory_qty),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Duchy".into(),
 | 
			
		||||
                            cost: 5,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        victory_qty,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Province".into(),
 | 
			
		||||
                            cost: 8,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        victory_qty,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Curse".into(),
 | 
			
		||||
                            cost: 0,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Cellar".into(),
 | 
			
		||||
                            cost: 2,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Moat".into(),
 | 
			
		||||
                            cost: 2,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Village".into(),
 | 
			
		||||
                            cost: 3,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Merchant".into(),
 | 
			
		||||
                            cost: 3,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Workshop".into(),
 | 
			
		||||
                            cost: 3,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Smithy".into(),
 | 
			
		||||
                            cost: 4,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Remodel".into(),
 | 
			
		||||
                            cost: 4,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Militia".into(),
 | 
			
		||||
                            cost: 4,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Market".into(),
 | 
			
		||||
                            cost: 5,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                    (
 | 
			
		||||
                        Card {
 | 
			
		||||
                            name: "Mine".into(),
 | 
			
		||||
                            cost: 5,
 | 
			
		||||
                            types: vec![],
 | 
			
		||||
                        },
 | 
			
		||||
                        10,
 | 
			
		||||
                    ),
 | 
			
		||||
                ];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -233,12 +333,16 @@ impl Game {
 | 
			
		||||
 | 
			
		||||
        self.active_player += 1;
 | 
			
		||||
        self.active_player %= self.players.len();
 | 
			
		||||
        self.turn_state = TurnState::default();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check if the end game condition is reached and finish the game if so,
 | 
			
		||||
    // sending a message to all clients.
 | 
			
		||||
    fn end_game(&mut self) {
 | 
			
		||||
        let provinces = self.supply.iter().any(|(c, n)| *c == "Province" && *n == 0);
 | 
			
		||||
        let provinces = self
 | 
			
		||||
            .supply
 | 
			
		||||
            .iter()
 | 
			
		||||
            .any(|(c, n)| (*c).name == "Province" && *n == 0);
 | 
			
		||||
        let supply = self.supply.iter().filter(|(_, n)| *n == 0).count() > 2;
 | 
			
		||||
 | 
			
		||||
        if supply || provinces {
 | 
			
		||||
@@ -263,6 +367,17 @@ impl Game {
 | 
			
		||||
        self.trash
 | 
			
		||||
            .push(self.players[player_number].hand.remove(index));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn play_card(&mut self, player_number: usize, index: usize) {
 | 
			
		||||
        let player = self.players.get_mut(player_number).unwrap();
 | 
			
		||||
        let card = player.hand.remove(index);
 | 
			
		||||
 | 
			
		||||
        if let Some(coin) = card.treasure() {
 | 
			
		||||
            self.turn_state.coin += coin;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        player.played_cards.push(card);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Default)]
 | 
			
		||||
@@ -293,24 +408,20 @@ async fn broadcast_state(game: &Game) {
 | 
			
		||||
                name: html_escape::encode_text(&p.name).into(),
 | 
			
		||||
                draw_pile_count: p.draw_pile.len(),
 | 
			
		||||
                hand_count: p.hand.len(),
 | 
			
		||||
                discard_pile: p.discard_pile.last().map(|c| c.clone()),
 | 
			
		||||
                played_cards: p.played_cards.clone(),
 | 
			
		||||
                discard_pile: p.discard_pile.last().map(|c| c.name.clone()),
 | 
			
		||||
                played_cards: p.played_cards.iter().map(|c| c.name.clone()).collect(),
 | 
			
		||||
            })
 | 
			
		||||
            .collect(),
 | 
			
		||||
        active_player: game.active_player,
 | 
			
		||||
        supply: game
 | 
			
		||||
            .supply
 | 
			
		||||
            .iter()
 | 
			
		||||
            .map(|(name, count)| PileState {
 | 
			
		||||
                name: name.into(),
 | 
			
		||||
            .map(|(card, count)| PileState {
 | 
			
		||||
                name: card.clone(),
 | 
			
		||||
                count: count.clone(),
 | 
			
		||||
            })
 | 
			
		||||
            .collect(),
 | 
			
		||||
        turn_state: TurnState {
 | 
			
		||||
            actions: 1,
 | 
			
		||||
            buys: 1,
 | 
			
		||||
            coin: 0,
 | 
			
		||||
        },
 | 
			
		||||
        turn_state: game.turn_state.clone(),
 | 
			
		||||
        trash: game.trash.clone(),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -331,7 +442,10 @@ async fn broadcast_state(game: &Game) {
 | 
			
		||||
                .iter()
 | 
			
		||||
                .enumerate()
 | 
			
		||||
                .map(|(i, p)| {
 | 
			
		||||
                    let score = p.draw_pile.iter().fold(0, |acc, card| match card.as_str() {
 | 
			
		||||
                    let score = p
 | 
			
		||||
                        .draw_pile
 | 
			
		||||
                        .iter()
 | 
			
		||||
                        .fold(0, |acc, card| match card.name.as_str() {
 | 
			
		||||
                            "Province" => acc + 6,
 | 
			
		||||
                            "Duchery" => acc + 3,
 | 
			
		||||
                            "Estate" => acc + 1,
 | 
			
		||||
@@ -537,8 +651,8 @@ async fn main() -> Result<(), std::io::Error> {
 | 
			
		||||
                        let mut games = req.state().games.write().await;
 | 
			
		||||
                        let game = games.get_mut(&game_id).unwrap();
 | 
			
		||||
 | 
			
		||||
                        let card_name = game.players[player_number].hand[index].clone();
 | 
			
		||||
                        game.players[player_number].play_card(index);
 | 
			
		||||
                        let card_name = game.players[player_number].hand[index].name.clone();
 | 
			
		||||
                        game.play_card(player_number, index);
 | 
			
		||||
 | 
			
		||||
                        notify_players(
 | 
			
		||||
                            &game,
 | 
			
		||||
@@ -554,15 +668,13 @@ async fn main() -> Result<(), std::io::Error> {
 | 
			
		||||
 | 
			
		||||
                        game.supply.get_mut(index).unwrap().1 =
 | 
			
		||||
                            game.supply.get(index).unwrap().1 - 1;
 | 
			
		||||
                        let card_name = game.supply[index].0.clone();
 | 
			
		||||
                        let card = game.supply[index].0.clone();
 | 
			
		||||
 | 
			
		||||
                        game.players[player_number]
 | 
			
		||||
                            .discard_pile
 | 
			
		||||
                            .push(card_name.clone());
 | 
			
		||||
                        game.players[player_number].discard_pile.push(card.clone());
 | 
			
		||||
 | 
			
		||||
                        notify_players(
 | 
			
		||||
                            &game,
 | 
			
		||||
                            format!("{} nimmt {}", game.players[player_number].name, card_name),
 | 
			
		||||
                            format!("{} nimmt {}", game.players[player_number].name, card.name),
 | 
			
		||||
                        )
 | 
			
		||||
                        .await;
 | 
			
		||||
                        broadcast_state(&game).await;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user