diff --git a/src/main.rs b/src/main.rs index 88054c2..2957784 100644 --- a/src/main.rs +++ b/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, - played_cards: Vec, + discard_pile: Option, + played_cards: Vec, } #[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, active_player: usize, - supply: Vec<(String, usize)>, + supply: Vec<(Card, usize)>, trash: Vec, + turn_state: TurnState, } impl Game { @@ -176,6 +184,7 @@ impl Game { active_player: 0, supply: vec![], trash: vec![], + turn_state: TurnState::default(), } } @@ -190,28 +199,119 @@ impl Game { } let victory_qty = match self.players.len() { - x if x <=2 => 8, + x if x <= 2 => 8, _ => 12, }; 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,12 +442,15 @@ 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() { - "Province" => acc + 6, - "Duchery" => acc + 3, - "Estate" => acc + 1, - _ => acc, - }); + let score = p + .draw_pile + .iter() + .fold(0, |acc, card| match card.name.as_str() { + "Province" => acc + 6, + "Duchery" => acc + 3, + "Estate" => acc + 1, + _ => acc, + }); (i, score) }) .sorted_by(|a, b| Ord::cmp(&b.1, &a.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;