From 159126e7ca785b75f19d5ecf70579656e8484cca Mon Sep 17 00:00:00 2001 From: Seoxi Ryouko Date: Sun, 2 Mar 2025 04:57:58 -0600 Subject: [PATCH] =?UTF-8?q?Got=20refactor=20to=20compile=E2=9A=99=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/game.rs | 242 ++++++++++++++++++++++++++++++---------------------- src/main.rs | 57 ++++++++----- 2 files changed, 176 insertions(+), 123 deletions(-) diff --git a/src/game.rs b/src/game.rs index b3d7ac8..282efba 100644 --- a/src/game.rs +++ b/src/game.rs @@ -47,7 +47,7 @@ enum Event { Shuffle(Player), Draw(Player, usize), Pass(Player, Player), - ChangeLifeTotal(Player, i32, i32), + ChangeLifeTotal(Player, isize, isize), FadeFromHand(Player), PlayFromHand(Player), Bounce(Player), @@ -69,6 +69,15 @@ struct CountedEvent { event: Event, } +macro_rules! gen_event { + ($list:expr,$event:expr) => { + $list.push(CountedEvent { + id: $list.len(), + event: $event, + }) + }; +} + #[derive(Clone, Debug)] pub struct GameState { deck: VecDeque, @@ -76,7 +85,7 @@ pub struct GameState { shadow_realm: Vec, play: HashMap, hands: Vec, - life_totals: Vec, + life_totals: Vec, turn_player: Player, events: Vec, } @@ -87,7 +96,7 @@ pub struct OnePlayerGameState { shadow_realm: Vec, play: Vec, hand: Vec, - life_totals: Vec, + life_totals: Vec, turn_player: Player, opponent_cards_in_hand: usize, you: Player, @@ -150,21 +159,21 @@ pub fn new() -> GameState { } } -pub fn draw(game_state: &mut GameState, count: usize, player: Player) { +pub fn draw(game_state: &mut GameState, count: usize, player: Player) -> Result<(), String> { let player_hand = match player { Player::A => &mut game_state.hands[0], Player::B => &mut game_state.hands[1], }; - 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 - .split_off(game_state.deck.len() - count) - .make_contiguous(), + let remaining_cards = + std::cmp::max(0, game_state.deck.len() as isize - count as isize) as usize; + gen_event!( + game_state.events, + Event::Draw(player.clone(), count.clone()) ); + player_hand + .cards + .extend_from_slice(game_state.deck.split_off(remaining_cards).make_contiguous()); + Ok(()) } pub fn yoink(game_state: &mut GameState, deck_index: usize, player: Player) -> Result<(), String> { @@ -172,10 +181,7 @@ pub fn yoink(game_state: &mut GameState, deck_index: usize, player: Player) -> R Player::A => &mut game_state.hands[0], Player::B => &mut game_state.hands[1], }; - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::Yoink(player.clone()), - }); + gen_event!(game_state.events, Event::Yoink(player.clone())); match game_state.deck.remove(deck_index) { Some(card) => Ok(player_hand.cards.push(card)), None => Err(format!("Yoink index out of bounds: {}", deck_index)), @@ -196,10 +202,7 @@ pub fn yoink_mill( )) } }; - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::YoinkMill(card.clone()), - }); + gen_event!(game_state.events, Event::YoinkMill(card.clone())); if shadow { game_state.shadow_realm.push(card); } else { @@ -209,10 +212,7 @@ pub fn yoink_mill( } pub fn shuffle(game_state: &mut GameState, player: Player) { - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::Shuffle(player), - }); + gen_event!(game_state.events, Event::Shuffle(player)); game_state.deck.make_contiguous().shuffle(&mut rng()); } @@ -230,22 +230,22 @@ pub fn pass(game_state: &mut GameState) { Player::A => Player::B, Player::B => Player::A, }; - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::Pass(*current_player, new_player.clone()), - }); + gen_event!( + game_state.events, + 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) { +pub fn change_life(game_state: &mut GameState, diff: isize, player: Player) { let mut player_life = match player { Player::A => game_state.life_totals[0].clone(), Player::B => game_state.life_totals[1].clone(), }; - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::ChangeLifeTotal(player, player_life.clone(), player_life.clone() + diff), - }); + gen_event!( + game_state.events, + Event::ChangeLifeTotal(player, player_life.clone(), player_life.clone() + diff) + ); player_life += diff; match player { Player::A => game_state.life_totals[0] = player_life, @@ -253,21 +253,28 @@ pub fn change_life(game_state: &mut GameState, diff: i32, player: Player) { }; } -pub fn fade_from_hand(game_state: &mut GameState, hand_index: usize, player: Player, bottom: bool) { +pub fn fade_from_hand( + game_state: &mut GameState, + hand_index: usize, + player: Player, + bottom: bool, +) -> Result<(), String> { let player_hand = match player { Player::A => &mut game_state.hands[0], Player::B => &mut game_state.hands[1], }; - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::FadeFromHand(player.clone()), - }); + gen_event!(game_state.events, Event::FadeFromHand(player.clone())); + + if None == player_hand.cards.get(hand_index) { + return Err(format!("Fade index out of bounds: {}", hand_index)); + } let card = player_hand.cards.remove(hand_index); if bottom { game_state.deck.push_front(card); } else { game_state.deck.push_back(card); } + Ok(()) } pub fn play_from_hand( @@ -279,12 +286,9 @@ pub fn play_from_hand( Player::A => &mut game_state.hands[0], Player::B => &mut game_state.hands[1], }; - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::PlayFromHand(player.clone()), - }); + gen_event!(game_state.events, Event::PlayFromHand(player.clone())); if None == player_hand.cards.get(hand_index) { - return Err(format!("Yoink index out of bounds: {}", hand_index)); + return Err(format!("Play index out of bounds: {}", hand_index)); } let card = player_hand.cards.remove(hand_index); let play_uuid = Uuid::new_v4(); @@ -311,18 +315,12 @@ pub fn bounce(game_state: &mut GameState, play_id: Uuid) -> Result<(), String> { Player::A => &mut game_state.hands[0], Player::B => &mut game_state.hands[1], }; - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::Bounce(played_card.owner), - }); + gen_event!(game_state.events, Event::Bounce(played_card.owner)); Ok(player_hand.cards.push(played_card.id)) } pub fn tap(game_state: &mut GameState, play_id: Uuid) -> Result<(), String> { - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::Tap(play_id.clone()), - }); + gen_event!(game_state.events, Event::Tap(play_id.clone())); match game_state.play.get_mut(&play_id) { Some(played_card) => { played_card.tapped = !played_card.tapped; @@ -338,6 +336,7 @@ pub fn move_played_card( position_x: u8, position_y: u8, ) -> Result<(), String> { + // no event made, intentionally match game_state.play.get_mut(&play_id) { Some(played_card) => { played_card.position_x = position_x; @@ -348,64 +347,94 @@ pub fn move_played_card( } } -pub fn discard(game_state: &mut GameState, hand_index: usize, player: Player, shadow: bool) { +pub fn discard( + game_state: &mut GameState, + hand_index: usize, + player: Player, + shadow: bool, +) -> Result<(), String> { let player_hand = match player { Player::A => &mut game_state.hands[0], Player::B => &mut game_state.hands[1], }; - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::Discard(player.clone()), - }); + gen_event!(game_state.events, Event::Discard(player.clone())); + if None == player_hand.cards.get(hand_index) { + return Err(format!("Discard index out of bounds: {}", hand_index)); + } let card = player_hand.cards.remove(hand_index); if shadow { game_state.shadow_realm.push(card); } else { game_state.discard_pile.push(card); } + Ok(()) } -pub fn undiscard(game_state: &mut GameState, pile_index: usize, player: Player, shadow: bool) { +pub fn undiscard( + game_state: &mut GameState, + pile_index: usize, + player: Player, + shadow: bool, +) -> Result<(), String> { let player_hand = match player { Player::A => &mut game_state.hands[0], Player::B => &mut game_state.hands[1], }; - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::Undiscard(player.clone()), - }); - let card = if shadow { - game_state.shadow_realm.remove(pile_index) + let pile = if shadow { + &mut game_state.shadow_realm } else { - game_state.discard_pile.remove(pile_index) + &mut game_state.discard_pile }; - player_hand.cards.push(card); + if None == pile.get(pile_index) { + return Err(format!("Discard index out of bounds: {}", pile_index)); + } + gen_event!(game_state.events, Event::Undiscard(player.clone())); + player_hand.cards.push(pile.remove(pile_index)); + Ok(()) } -pub fn kill(game_state: &mut GameState, play_id: Uuid, shadow: bool) { - let played_card = game_state.play.remove(&play_id).unwrap(); - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::Kill(played_card.id.clone(), shadow), - }); +pub fn kill(game_state: &mut GameState, play_id: Uuid, shadow: bool) -> Result<(), String> { + let played_card = match game_state.play.remove(&play_id) { + Some(played_card) => played_card, + None => return Err(format!("Nonexistant play id: {}", play_id)), + }; + gen_event!( + game_state.events, + Event::Kill(played_card.id.clone(), shadow) + ); if shadow { game_state.shadow_realm.push(played_card.id); } else { game_state.discard_pile.push(played_card.id); } + Ok(()) } -pub fn unkill(game_state: &mut GameState, player: Player, pile_index: usize, shadow: bool) { - let card = if shadow { - game_state.shadow_realm.remove(pile_index) +pub fn unkill( + game_state: &mut GameState, + player: Player, + pile_index: usize, + shadow: bool, +) -> Result<(), String> { + let pile = if shadow { + &mut game_state.shadow_realm } else { - game_state.discard_pile.remove(pile_index) + &mut game_state.discard_pile }; + if None == pile.get(pile_index) { + let pile_name = if shadow { + "shadow realm" + } else { + "discard pile" + }; + return Err(format!( + "Transfer index out of bounds: {} ({})", + pile_index, pile_name + )); + } + let card = pile.remove(pile_index); + gen_event!(game_state.events, Event::Unkill(card, shadow)); let play_uuid = Uuid::new_v4(); - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::Unkill(card, shadow), - }); game_state.play.insert( play_uuid, InPlay { @@ -417,31 +446,43 @@ pub fn unkill(game_state: &mut GameState, player: Player, pile_index: usize, sha play_id: play_uuid, }, ); + Ok(()) } -pub fn transfer_dead_card(game_state: &mut GameState, pile_index: usize, shadow_to_discard: bool) { - let card_id = if shadow_to_discard { - let card = game_state.shadow_realm.remove(pile_index); - let ret = card.clone(); - game_state.discard_pile.push(card); - ret +pub fn transfer_dead_card( + game_state: &mut GameState, + pile_index: usize, + shadow_to_discard: bool, +) -> Result<(), String> { + let (source, target) = if shadow_to_discard { + (&mut game_state.shadow_realm, &mut game_state.discard_pile) } else { - let card = game_state.discard_pile.remove(pile_index); - let ret = card.clone(); - game_state.shadow_realm.push(card); - ret + (&mut game_state.discard_pile, &mut game_state.shadow_realm) }; - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::TransferDeadCard(card_id, shadow_to_discard), - }); + + if pile_index >= source.len() { + let direction = if shadow_to_discard { + "shadow realm -> discard pile" + } else { + "discard pile -> shadow realm" + }; + return Err(format!( + "Transfer index out of bounds: {} ({})", + pile_index, direction + )); + } + let card = source.remove(pile_index); + let card_id = card.clone(); + gen_event!( + game_state.events, + Event::TransferDeadCard(card_id, shadow_to_discard) + ); + target.push(card); + Ok(()) } pub fn untap_all(game_state: &mut GameState, player: Player) { - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::UntapAll(player), - }); + gen_event!(game_state.events, Event::UntapAll(player)); for (_, card) in game_state.play.iter_mut() { if card.owner == player { card.tapped = false; @@ -450,10 +491,7 @@ pub fn untap_all(game_state: &mut GameState, player: Player) { } pub fn get_deck(game_state: &mut GameState, player: Player) -> String { - game_state.events.push(CountedEvent { - id: game_state.events.len(), - event: Event::ViewDeck(player), - }); + gen_event!(game_state.events, Event::ViewDeck(player)); let deck_copy = game_state.deck.clone(); serde_json::to_string(&deck_copy).unwrap() } diff --git a/src/main.rs b/src/main.rs index 93b2229..cb10482 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,10 +39,16 @@ macro_rules! get_player { }; } +macro_rules! respond_ok { + () => { + (Status::Ok, (ContentType::Plain, "Ok!".to_string())) + }; +} + macro_rules! respond { ($state:expr) => { match $state { - Ok(()) => (Status::Ok, (ContentType::Plain, "Ok!".to_string())), + Ok(()) => respond_ok!(), Err(err_string) => (Status::BadRequest, (ContentType::Plain, err_string)), } }; @@ -67,7 +73,7 @@ fn index(player_uuids: &State) -> content::RawHtml { content::RawHtml(format!( "/{}
/{}", player_uuids.a, player_uuids.a, player_uuids.b, player_uuids.b - )) + )) } #[get("/get_events")] @@ -84,7 +90,8 @@ fn shuffle( ) -> (Status, (ContentType, String)) { let player = get_player!(player_uuids, uuid); unlock_state_mut!(game_state_arc, mutex, game_state); - respond!(game::shuffle(&mut game_state, player.clone())) + game::shuffle(&mut game_state, player.clone()); + respond_ok!() } #[post("//pass")] @@ -95,7 +102,8 @@ fn pass( ) -> (Status, (ContentType, String)) { assert_player!(player_uuids, uuid); unlock_state_mut!(game_state_arc, mutex, game_state); - respond!(game::pass(&mut game_state)) + game::pass(&mut game_state); + respond_ok!() } #[post("//bounce/")] @@ -322,10 +330,13 @@ fn get_state( ) -> (Status, (ContentType, String)) { let player = get_player!(player_uuids, uuid); unlock_state!(game_state_arc, mutex, game_state); - (Status::Ok, (ContentType::JSON, format!( - "{}", - game::get_game_one_player(&game_state, player.clone()) - ))) + ( + Status::Ok, + ( + ContentType::JSON, + format!("{}", game::get_game_one_player(&game_state, player.clone())), + ), + ) } #[post("//get_deck")] @@ -336,10 +347,13 @@ fn get_deck( ) -> (Status, (ContentType, String)) { let player = get_player!(player_uuids, uuid); unlock_state_mut!(game_state_arc, mutex, game_state); - (Status::Ok, (ContentType::JSON, format!( - "{}", - game::get_deck(&mut game_state, player.clone()) - ))) + ( + Status::Ok, + ( + ContentType::JSON, + format!("{}", game::get_deck(&mut game_state, player.clone())), + ), + ) } #[post("//untap_all")] @@ -350,7 +364,8 @@ fn untap_all( ) -> (Status, (ContentType, String)) { let player = get_player!(player_uuids, uuid); unlock_state_mut!(game_state_arc, mutex, game_state); - respond!(game::untap_all(&mut game_state, player.clone())) + game::untap_all(&mut game_state, player.clone()); + respond_ok!() } #[post("//draw/")] @@ -402,13 +417,14 @@ fn fade_bottom( #[post("//life/")] fn life( uuid: Uuid, - count: i32, + count: isize, game_state_arc: &State, player_uuids: &State, ) -> (Status, (ContentType, String)) { let player = get_player!(player_uuids, uuid); unlock_state_mut!(game_state_arc, mutex, game_state); - respond!(game::change_life(&mut game_state, count, player.clone())) + game::change_life(&mut game_state, count, player.clone()); + respond_ok!() } struct ArcMutexGameState { @@ -427,13 +443,12 @@ fn rocket() -> _ { let game_state_arc = Arc::new(Mutex::new(game_state)); #[cfg(debug_assertions)] - let a_uuid: Uuid = uuid!("9b0a2a95-72a9-4e03-930e-a9583d2a2a5a"); + let (a_uuid, b_uuid) = ( + uuid!("9b0a2a95-72a9-4e03-930e-a9583d2a2a5a"), + uuid!("2efc0332-975d-4f71-9dd0-ffc9213098a5"), + ); #[cfg(not(debug_assertions))] - let a_uuid: Uuid = Uuid::new_v4(); - #[cfg(debug_assertions)] - let b_uuid: Uuid = uuid!("2efc0332-975d-4f71-9dd0-ffc9213098a5"); - #[cfg(not(debug_assertions))] - let b_uuid: Uuid = Uuid::new_v4(); + let (a_uuid, b_uuid) = (Uuid::new_v4(), Uuid::new_v4()); let uuid_map = HashMap::from([(a_uuid, Player::A), (b_uuid, Player::B)]); println!("A: {}", a_uuid);