More implemented.

This commit is contained in:
Seoxi Ryouko
2025-02-08 00:17:11 -06:00
parent a9e8b2195c
commit c188cfc5e8
5 changed files with 184 additions and 71 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target /target
Rocket.toml

1
Cargo.lock generated
View File

@ -1105,6 +1105,7 @@ dependencies = [
"rocket_codegen", "rocket_codegen",
"rocket_http", "rocket_http",
"serde", "serde",
"serde_json",
"state", "state",
"tempfile", "tempfile",
"time", "time",

View File

@ -13,7 +13,7 @@ features = [ "serde" ]
[dependencies.rocket] [dependencies.rocket]
version = "0.5.1" version = "0.5.1"
features = [ "uuid" ] features = [ "uuid", "json" ]
[dependencies.uuid] [dependencies.uuid]
version = "1.13.1" version = "1.13.1"

View File

@ -1,7 +1,6 @@
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use rand::{random_bool, rng}; use rand::{random_bool, rng};
use rocket::serde::{Deserialize, Serialize}; use rocket::serde::{Deserialize, Serialize};
use std::collections::HashMap;
use url::Url; use url::Url;
use uuid::Uuid; use uuid::Uuid;
@ -17,7 +16,7 @@ struct CardInfo {
count: usize, count: usize,
} }
#[derive(Deserialize, Serialize, Clone)] #[derive(Deserialize, Serialize, Clone, Copy)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
pub enum Player { pub enum Player {
A, A,
@ -46,7 +45,15 @@ struct Hand {
enum Event { enum Event {
Shuffle(Player), Shuffle(Player),
Draw(Player, usize), 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)] #[derive(Clone)]
@ -56,9 +63,10 @@ pub struct GameState {
shadow_realm: Vec<Uuid>, shadow_realm: Vec<Uuid>,
play: Vec<InPlay>, play: Vec<InPlay>,
hands: Vec<Hand>, hands: Vec<Hand>,
life_totals: Vec<i32>,
turn_player: Player, turn_player: Player,
card_map: HashMap<Uuid, CardInfo>, //card_map: HashMap<Uuid, CardInfo>,
events: Vec<Event>, events: Vec<CountedEvent>,
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -68,13 +76,14 @@ pub struct OnePlayerGameState {
shadow_realm: Vec<Uuid>, shadow_realm: Vec<Uuid>,
play: Vec<InPlay>, play: Vec<InPlay>,
hand: Vec<Uuid>, hand: Vec<Uuid>,
life_totals: Vec<i32>,
turn_player: Player, turn_player: Player,
opponent_cards_in_hand: usize, opponent_cards_in_hand: usize,
you: Player, you: Player,
} }
impl GameState { impl GameState {
pub fn as_one_player(&self, player: Player) -> OnePlayerGameState { fn as_one_player(&self, player: Player) -> OnePlayerGameState {
OnePlayerGameState { OnePlayerGameState {
discard_pile: self.discard_pile.clone(), discard_pile: self.discard_pile.clone(),
shadow_realm: self.shadow_realm.clone(), shadow_realm: self.shadow_realm.clone(),
@ -83,6 +92,7 @@ impl GameState {
Player::A => self.hands[0].cards.clone(), Player::A => self.hands[0].cards.clone(),
_ => self.hands[1].cards.clone(), _ => self.hands[1].cards.clone(),
}, },
life_totals: self.life_totals.clone(),
turn_player: self.turn_player.clone(), turn_player: self.turn_player.clone(),
opponent_cards_in_hand: match player { opponent_cards_in_hand: match player {
Player::A => self.hands[1].cards.len(), Player::A => self.hands[1].cards.len(),
@ -97,17 +107,17 @@ const CARD_DATA_JSON: &str = include_str!("cards.json");
pub fn new() -> GameState { pub fn new() -> GameState {
let parsed_cards: Vec<CardInfo> = serde_json::from_str(CARD_DATA_JSON).unwrap(); let parsed_cards: Vec<CardInfo> = serde_json::from_str(CARD_DATA_JSON).unwrap();
let card_map = parsed_cards /*let card_map = parsed_cards
.into_iter() .into_iter()
.map(|card| (card.scryfall_id, card)) .map(|card| (card.scryfall_id, card))
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();*/
let starting_player = match random_bool(0.5) { let starting_player = match random_bool(0.5) {
true => Player::A, true => Player::A,
_ => Player::B, _ => Player::B,
}; };
let mut deck: Vec<Uuid> = card_map let mut deck: Vec<Uuid> = parsed_cards
.iter() .iter()
.flat_map(move |(id, card)| vec![id.clone(); card.count]) .flat_map(move |card| vec![card.scryfall_id.clone(); card.count])
.collect(); .collect();
deck.shuffle(&mut rng()); deck.shuffle(&mut rng());
GameState { GameState {
@ -125,8 +135,9 @@ pub fn new() -> GameState {
owner: Player::B, owner: Player::B,
}, },
], ],
life_totals: vec![20; 2],
turn_player: starting_player, turn_player: starting_player,
card_map, //card_map,
events: vec![], events: vec![],
} }
} }
@ -136,9 +147,10 @@ pub fn draw(game_state: &mut GameState, count: usize, player: Player) {
Player::A => &mut game_state.hands[0], Player::A => &mut game_state.hands[0],
_ => &mut game_state.hands[1], _ => &mut game_state.hands[1],
}; };
game_state game_state.events.push(CountedEvent {
.events id: game_state.events.len(),
.push(Event::Draw(player.clone(), count.clone())); event: Event::Draw(player.clone(), count.clone()),
});
player_hand.cards.extend_from_slice( player_hand.cards.extend_from_slice(
game_state game_state
.deck .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) { 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()); 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 { pub fn get_events(game_state: &GameState) -> String {
serde_json::to_string(&game_state.events).unwrap() 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,
};
}

View File

@ -1,32 +1,21 @@
#[macro_use]
extern crate rocket;
mod game; mod game;
use game::GameState; use game::GameState;
use game::Player; use game::Player;
use rocket::fs::{relative, FileServer};
use rocket::response::status::BadRequest; use rocket::response::status::BadRequest;
use rocket::State; use rocket::State;
use std::collections::HashMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use uuid::Uuid;
#[macro_use]
extern crate rocket;
#[get("/")] #[get("/")]
fn index() -> &'static str { fn index(player_uuids: &State<PlayerUuids>) -> String {
"Hello, world!" format!(
} "a: localhost:8000/{}/\nb: localhost:8000/{}/",
player_uuids.a, player_uuids.b
#[get("/shuffle/<player_id>")] )
fn shuffle(
player_id: &str,
game_state_arc: &State<ArcMutexGameState>,
) -> Result<String, BadRequest<String>> {
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!"))
} }
#[get("/get_events")] #[get("/get_events")]
@ -36,41 +25,93 @@ fn get_events(game_state_arc: &State<ArcMutexGameState>) -> String {
format!("{}", game::get_events(&game_state)) format!("{}", game::get_events(&game_state))
} }
#[get("/get_state/<player_id>")] #[post("/<uuid>/shuffle")]
fn get_state( fn shuffle(
player_id: &str, uuid: Uuid,
game_state_arc: &State<ArcMutexGameState>,
) -> Result<String, BadRequest<String>> {
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/<player_id>/<count>")]
fn draw(
player_id: &str,
count: usize,
game_state_arc: &State<ArcMutexGameState>, game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> { ) -> Result<String, BadRequest<String>> {
let game_state_mutex = Arc::clone(&game_state_arc.state); let game_state_mutex = Arc::clone(&game_state_arc.state);
let mut game_state = game_state_mutex.lock().unwrap(); let mut game_state = game_state_mutex.lock().unwrap();
let player = match player_id { let player = match player_uuids.map.get(&uuid) {
"a" => Player::A, Some(player) => player,
"b" => Player::B, None => return Err(BadRequest(format!("Invalid player {}.", uuid))),
_ => return Err(BadRequest(format!("Invalid player {}.", player_id))), };
game::shuffle(&mut game_state, player.clone());
Ok(format!("Deck Shuffled!"))
}
#[get("/<uuid>/pass")]
fn pass(
uuid: Uuid,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
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("/<uuid>/get_state")]
fn get_state(
uuid: Uuid,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
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("/<uuid>/draw/<count>")]
fn draw(
uuid: Uuid,
count: usize,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
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()); game::draw(&mut game_state, count, player.clone());
Ok(format!( Ok(format!(
"{}", "{}",
game::get_game_one_player(&game_state, player) game::get_game_one_player(&game_state, player.clone())
))
}
#[get("/<uuid>/life/<count>")]
fn life(
uuid: Uuid,
count: i32,
game_state_arc: &State<ArcMutexGameState>,
player_uuids: &State<PlayerUuids>,
) -> Result<String, BadRequest<String>> {
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<Mutex<GameState>>, state: Arc<Mutex<GameState>>,
} }
struct PlayerUuids {
a: Uuid,
b: Uuid,
map: HashMap<Uuid, Player>,
}
#[launch] #[launch]
fn rocket() -> _ { fn rocket() -> _ {
let mut game_state = game::new(); let game_state = game::new();
let game_state_arc = Arc::new(Mutex::new(game_state)); 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() rocket::build()
.mount("/", routes![index, get_events]) .mount(
.mount("/", routes![get_state]) format!("/{}", a_uuid.hyphenated()),
.mount("/", routes![draw]) FileServer::from(relative!("static")),
.mount("/", routes![shuffle]) )
.mount(
format!("/{}", b_uuid.hyphenated()),
FileServer::from(relative!("static")),
)
.mount(
"/",
routes![index, get_events, get_state, draw, shuffle, pass, life,],
)
.manage(ArcMutexGameState { .manage(ArcMutexGameState {
state: game_state_arc, state: game_state_arc,
}) })
.manage(PlayerUuids {
a: a_uuid,
b: b_uuid,
map: uuid_map,
})
} }