diff --git a/.gitignore b/.gitignore index ea8c4bf..c1cdd55 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +Rocket.toml diff --git a/Cargo.lock b/Cargo.lock index e4c37fc..fe188bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1105,6 +1105,7 @@ dependencies = [ "rocket_codegen", "rocket_http", "serde", + "serde_json", "state", "tempfile", "time", diff --git a/Cargo.toml b/Cargo.toml index 6f0410b..40b258e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ features = [ "serde" ] [dependencies.rocket] version = "0.5.1" -features = [ "uuid" ] +features = [ "uuid", "json" ] [dependencies.uuid] version = "1.13.1" diff --git a/src/game.rs b/src/game.rs index a91cb91..1edd652 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,7 +1,6 @@ use rand::seq::SliceRandom; use rand::{random_bool, rng}; use rocket::serde::{Deserialize, Serialize}; -use std::collections::HashMap; use url::Url; use uuid::Uuid; @@ -17,7 +16,7 @@ struct CardInfo { count: usize, } -#[derive(Deserialize, Serialize, Clone)] +#[derive(Deserialize, Serialize, Clone, Copy)] #[serde(crate = "rocket::serde")] pub enum Player { A, @@ -46,7 +45,15 @@ struct Hand { enum Event { Shuffle(Player), Draw(Player, usize), - Pass, + Pass(Player, Player), + ChangeLifeTotal(Player, i32, i32), +} + +#[derive(Serialize, Clone)] +#[serde(crate = "rocket::serde")] +struct CountedEvent { + id: usize, + event: Event, } #[derive(Clone)] @@ -56,9 +63,10 @@ pub struct GameState { shadow_realm: Vec, play: Vec, hands: Vec, + life_totals: Vec, turn_player: Player, - card_map: HashMap, - events: Vec, + //card_map: HashMap, + events: Vec, } #[derive(Serialize)] @@ -68,13 +76,14 @@ pub struct OnePlayerGameState { shadow_realm: Vec, play: Vec, hand: Vec, + life_totals: Vec, turn_player: Player, opponent_cards_in_hand: usize, you: Player, } impl GameState { - pub fn as_one_player(&self, player: Player) -> OnePlayerGameState { + fn as_one_player(&self, player: Player) -> OnePlayerGameState { OnePlayerGameState { discard_pile: self.discard_pile.clone(), shadow_realm: self.shadow_realm.clone(), @@ -83,6 +92,7 @@ impl GameState { Player::A => self.hands[0].cards.clone(), _ => self.hands[1].cards.clone(), }, + life_totals: self.life_totals.clone(), turn_player: self.turn_player.clone(), opponent_cards_in_hand: match player { Player::A => self.hands[1].cards.len(), @@ -97,17 +107,17 @@ const CARD_DATA_JSON: &str = include_str!("cards.json"); pub fn new() -> GameState { let parsed_cards: Vec = serde_json::from_str(CARD_DATA_JSON).unwrap(); - let card_map = parsed_cards - .into_iter() - .map(|card| (card.scryfall_id, card)) - .collect::>(); + /*let card_map = parsed_cards + .into_iter() + .map(|card| (card.scryfall_id, card)) + .collect::>();*/ let starting_player = match random_bool(0.5) { true => Player::A, _ => Player::B, }; - let mut deck: Vec = card_map + let mut deck: Vec = parsed_cards .iter() - .flat_map(move |(id, card)| vec![id.clone(); card.count]) + .flat_map(move |card| vec![card.scryfall_id.clone(); card.count]) .collect(); deck.shuffle(&mut rng()); GameState { @@ -125,8 +135,9 @@ pub fn new() -> GameState { owner: Player::B, }, ], + life_totals: vec![20; 2], turn_player: starting_player, - card_map, + //card_map, events: vec![], } } @@ -136,9 +147,10 @@ pub fn draw(game_state: &mut GameState, count: usize, player: Player) { Player::A => &mut game_state.hands[0], _ => &mut game_state.hands[1], }; - game_state - .events - .push(Event::Draw(player.clone(), count.clone())); + game_state.events.push(CountedEvent { + id: game_state.events.len(), + event: Event::Draw(player.clone(), count.clone()), + }); player_hand.cards.extend_from_slice( game_state .deck @@ -148,7 +160,10 @@ pub fn draw(game_state: &mut GameState, count: usize, player: Player) { } pub fn shuffle(game_state: &mut GameState, player: Player) { - game_state.events.push(Event::Shuffle(player)); + game_state.events.push(CountedEvent { + id: game_state.events.len(), + event: Event::Shuffle(player), + }); game_state.deck.shuffle(&mut rng()); } @@ -159,3 +174,33 @@ pub fn get_game_one_player(game_state: &GameState, player: Player) -> String { pub fn get_events(game_state: &GameState) -> String { serde_json::to_string(&game_state.events).unwrap() } + +pub fn pass(game_state: &mut GameState) { + let current_player = &game_state.turn_player; + let new_player = match current_player { + Player::A => Player::B, + _ => Player::A, + }; + game_state.events.push(CountedEvent { + id: game_state.events.len(), + event: Event::Pass(*current_player, new_player.clone()), + }); + game_state.turn_player = new_player; +} + +pub fn change_life(game_state: &mut GameState, diff: i32, player: Player) { + let mut player_life = match player { + Player::A => game_state.life_totals[0].clone(), + _ => game_state.life_totals[1].clone(), + }; + //let diffed_player = player_life.clone() + diff; + game_state.events.push(CountedEvent { + id: game_state.events.len(), + event: Event::ChangeLifeTotal(player, player_life.clone(), player_life.clone() + diff), + }); + player_life += diff; + match player { + Player::A => game_state.life_totals[0] = player_life, + _ => game_state.life_totals[1] = player_life, + }; +} diff --git a/src/main.rs b/src/main.rs index 7616c25..7f32c24 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,32 +1,21 @@ +#[macro_use] +extern crate rocket; mod game; use game::GameState; use game::Player; +use rocket::fs::{relative, FileServer}; use rocket::response::status::BadRequest; use rocket::State; +use std::collections::HashMap; use std::sync::{Arc, Mutex}; - -#[macro_use] -extern crate rocket; +use uuid::Uuid; #[get("/")] -fn index() -> &'static str { - "Hello, world!" -} - -#[get("/shuffle/")] -fn shuffle( - player_id: &str, - game_state_arc: &State, -) -> Result> { - let game_state_mutex = Arc::clone(&game_state_arc.state); - let mut game_state = game_state_mutex.lock().unwrap(); - let player = match player_id { - "a" => Player::A, - "b" => Player::B, - _ => return Err(BadRequest(format!("Invalid player {}.", player_id))), - }; - game::shuffle(&mut game_state, player); - Ok(format!("Deck Shuffled!")) +fn index(player_uuids: &State) -> String { + format!( + "a: localhost:8000/{}/\nb: localhost:8000/{}/", + player_uuids.a, player_uuids.b + ) } #[get("/get_events")] @@ -36,41 +25,93 @@ fn get_events(game_state_arc: &State) -> String { format!("{}", game::get_events(&game_state)) } -#[get("/get_state/")] -fn get_state( - player_id: &str, - game_state_arc: &State, -) -> Result> { - let game_state_mutex = Arc::clone(&game_state_arc.state); - let game_state = game_state_mutex.lock().unwrap(); - let player = match player_id { - "a" => Player::A, - "b" => Player::B, - _ => return Err(BadRequest(format!("Invalid player {}.", player_id))), - }; - Ok(format!( - "{}", - game::get_game_one_player(&game_state, player) - )) -} - -#[get("/draw//")] -fn draw( - player_id: &str, - count: usize, +#[post("//shuffle")] +fn shuffle( + uuid: Uuid, game_state_arc: &State, + player_uuids: &State, ) -> Result> { let game_state_mutex = Arc::clone(&game_state_arc.state); let mut game_state = game_state_mutex.lock().unwrap(); - let player = match player_id { - "a" => Player::A, - "b" => Player::B, - _ => return Err(BadRequest(format!("Invalid player {}.", player_id))), + let player = match player_uuids.map.get(&uuid) { + Some(player) => player, + None => return Err(BadRequest(format!("Invalid player {}.", uuid))), + }; + game::shuffle(&mut game_state, player.clone()); + Ok(format!("Deck Shuffled!")) +} + +#[get("//pass")] +fn pass( + uuid: Uuid, + game_state_arc: &State, + player_uuids: &State, +) -> Result> { + match player_uuids.map.get(&uuid) { + Some(_) => (), + None => return Err(BadRequest(format!("Invalid player {}.", uuid))), + }; + let game_state_mutex = Arc::clone(&game_state_arc.state); + let mut game_state = game_state_mutex.lock().unwrap(); + game::pass(&mut game_state); + Ok(format!("{}", game::get_events(&game_state))) +} + +#[get("//get_state")] +fn get_state( + uuid: Uuid, + game_state_arc: &State, + player_uuids: &State, +) -> Result> { + let game_state_mutex = Arc::clone(&game_state_arc.state); + let game_state = game_state_mutex.lock().unwrap(); + let player = match player_uuids.map.get(&uuid) { + Some(player) => player, + None => return Err(BadRequest(format!("Invalid player {}.", uuid))), + }; + Ok(format!( + "{}", + game::get_game_one_player(&game_state, player.clone()) + )) +} + +#[get("//draw/")] +fn draw( + uuid: Uuid, + count: usize, + game_state_arc: &State, + player_uuids: &State, +) -> Result> { + let game_state_mutex = Arc::clone(&game_state_arc.state); + let mut game_state = game_state_mutex.lock().unwrap(); + let player = match player_uuids.map.get(&uuid) { + Some(player) => player, + None => return Err(BadRequest(format!("Invalid player {}.", uuid))), }; game::draw(&mut game_state, count, player.clone()); Ok(format!( "{}", - game::get_game_one_player(&game_state, player) + game::get_game_one_player(&game_state, player.clone()) + )) +} + +#[get("//life/")] +fn life( + uuid: Uuid, + count: i32, + game_state_arc: &State, + player_uuids: &State, +) -> Result> { + let game_state_mutex = Arc::clone(&game_state_arc.state); + let mut game_state = game_state_mutex.lock().unwrap(); + let player = match player_uuids.map.get(&uuid) { + Some(player) => player, + None => return Err(BadRequest(format!("Invalid player {}.", uuid))), + }; + game::change_life(&mut game_state, count, player.clone()); + Ok(format!( + "{}", + game::get_game_one_player(&game_state, player.clone()) )) } @@ -78,16 +119,41 @@ struct ArcMutexGameState { state: Arc>, } +struct PlayerUuids { + a: Uuid, + b: Uuid, + map: HashMap, +} + #[launch] fn rocket() -> _ { - let mut game_state = game::new(); + let game_state = game::new(); let game_state_arc = Arc::new(Mutex::new(game_state)); + let a_uuid: Uuid = Uuid::new_v4(); + let b_uuid: Uuid = Uuid::new_v4(); + let uuid_map = HashMap::from([(a_uuid, Player::A), (b_uuid, Player::B)]); + println!("A: {}", a_uuid); + println!("B: {}", b_uuid); + rocket::build() - .mount("/", routes![index, get_events]) - .mount("/", routes![get_state]) - .mount("/", routes![draw]) - .mount("/", routes![shuffle]) + .mount( + format!("/{}", a_uuid.hyphenated()), + FileServer::from(relative!("static")), + ) + .mount( + format!("/{}", b_uuid.hyphenated()), + FileServer::from(relative!("static")), + ) + .mount( + "/", + routes![index, get_events, get_state, draw, shuffle, pass, life,], + ) .manage(ArcMutexGameState { state: game_state_arc, }) + .manage(PlayerUuids { + a: a_uuid, + b: b_uuid, + map: uuid_map, + }) }