feat(backend): use pre-game roll result for the first move
This commit is contained in:
parent
1562ed1e40
commit
00326cd645
1 changed files with 41 additions and 14 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
use backbone_lib::traits::{BackEndArchitecture, BackendCommand};
|
use backbone_lib::traits::{BackEndArchitecture, BackendCommand};
|
||||||
use trictrac_store::{DiceRoller, GameEvent, GameState, TurnStage};
|
use trictrac_store::{Dice, DiceRoller, GameEvent, GameState, TurnStage};
|
||||||
|
|
||||||
use crate::trictrac::types::{GameDelta, PlayerAction, PreGameRollState, SerStage, ViewState};
|
use crate::trictrac::types::{GameDelta, PlayerAction, PreGameRollState, SerStage, ViewState};
|
||||||
|
|
||||||
|
|
@ -66,9 +66,21 @@ impl TrictracBackend {
|
||||||
self.broadcast_state();
|
self.broadcast_state();
|
||||||
} else {
|
} else {
|
||||||
// Highest die goes first.
|
// Highest die goes first.
|
||||||
let goes_first = if h > g { HOST_PLAYER_ID } else { GUEST_PLAYER_ID };
|
let goes_first = if h > g {
|
||||||
|
HOST_PLAYER_ID
|
||||||
|
} else {
|
||||||
|
GUEST_PLAYER_ID
|
||||||
|
};
|
||||||
self.ceremony_started = false;
|
self.ceremony_started = false;
|
||||||
let _ = self.game.consume(&GameEvent::BeginGame { goes_first });
|
let _ = self.game.consume(&GameEvent::BeginGame { goes_first });
|
||||||
|
// Use pre-game dice roll for the first move
|
||||||
|
let _ = self.game.consume(&GameEvent::Roll {
|
||||||
|
player_id: goes_first,
|
||||||
|
});
|
||||||
|
let _ = self.game.consume(&GameEvent::RollResult {
|
||||||
|
player_id: goes_first,
|
||||||
|
dice: Dice { values: (g, h) },
|
||||||
|
});
|
||||||
self.broadcast_state();
|
self.broadcast_state();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -162,7 +174,9 @@ impl BackEndArchitecture<PlayerAction, GameDelta, ViewState> for TrictracBackend
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start the ceremony once both players have arrived.
|
// Start the ceremony once both players have arrived.
|
||||||
if self.arrived[0] && self.arrived[1] && self.game.stage == trictrac_store::Stage::PreGame
|
if self.arrived[0]
|
||||||
|
&& self.arrived[1]
|
||||||
|
&& self.game.stage == trictrac_store::Stage::PreGame
|
||||||
&& !self.ceremony_started
|
&& !self.ceremony_started
|
||||||
{
|
{
|
||||||
self.ceremony_started = true;
|
self.ceremony_started = true;
|
||||||
|
|
@ -275,8 +289,8 @@ impl BackEndArchitecture<PlayerAction, GameDelta, ViewState> for TrictracBackend
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use backbone_lib::traits::BackEndArchitecture;
|
|
||||||
use crate::trictrac::types::{SerStage, SerTurnStage};
|
use crate::trictrac::types::{SerStage, SerTurnStage};
|
||||||
|
use backbone_lib::traits::BackEndArchitecture;
|
||||||
|
|
||||||
fn make_backend() -> TrictracBackend {
|
fn make_backend() -> TrictracBackend {
|
||||||
TrictracBackend::new(0)
|
TrictracBackend::new(0)
|
||||||
|
|
@ -306,8 +320,12 @@ mod tests {
|
||||||
if !host_needs && !guest_needs {
|
if !host_needs && !guest_needs {
|
||||||
break; // both rolled but stage not yet resolved — shouldn't happen
|
break; // both rolled but stage not yet resolved — shouldn't happen
|
||||||
}
|
}
|
||||||
if host_needs { b.inform_rpc(0, PlayerAction::PreGameRoll); }
|
if host_needs {
|
||||||
if guest_needs { b.inform_rpc(1, PlayerAction::PreGameRoll); }
|
b.inform_rpc(0, PlayerAction::PreGameRoll);
|
||||||
|
}
|
||||||
|
if guest_needs {
|
||||||
|
b.inform_rpc(1, PlayerAction::PreGameRoll);
|
||||||
|
}
|
||||||
b.drain_commands();
|
b.drain_commands();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -324,7 +342,10 @@ mod tests {
|
||||||
let has_reset = cmds
|
let has_reset = cmds
|
||||||
.iter()
|
.iter()
|
||||||
.any(|c| matches!(c, BackendCommand::ResetViewState));
|
.any(|c| matches!(c, BackendCommand::ResetViewState));
|
||||||
assert!(has_reset, "expected ResetViewState after both players arrive");
|
assert!(
|
||||||
|
has_reset,
|
||||||
|
"expected ResetViewState after both players arrive"
|
||||||
|
);
|
||||||
|
|
||||||
// Stage should now be PreGameRoll, not InGame.
|
// Stage should now be PreGameRoll, not InGame.
|
||||||
assert_eq!(b.get_view_state().stage, SerStage::PreGameRoll);
|
assert_eq!(b.get_view_state().stage, SerStage::PreGameRoll);
|
||||||
|
|
@ -352,9 +373,15 @@ mod tests {
|
||||||
// Guest may roll before host.
|
// Guest may roll before host.
|
||||||
b.inform_rpc(1, PlayerAction::PreGameRoll);
|
b.inform_rpc(1, PlayerAction::PreGameRoll);
|
||||||
let states = drain_deltas(&mut b);
|
let states = drain_deltas(&mut b);
|
||||||
assert!(!states.is_empty(), "guest PreGameRoll should broadcast a state");
|
assert!(
|
||||||
|
!states.is_empty(),
|
||||||
|
"guest PreGameRoll should broadcast a state"
|
||||||
|
);
|
||||||
let pgr = states.last().unwrap().pre_game_roll.as_ref().unwrap();
|
let pgr = states.last().unwrap().pre_game_roll.as_ref().unwrap();
|
||||||
assert!(pgr.guest_die.is_some(), "guest die should be set after guest rolls");
|
assert!(
|
||||||
|
pgr.guest_die.is_some(),
|
||||||
|
"guest die should be set after guest rolls"
|
||||||
|
);
|
||||||
assert!(pgr.host_die.is_none(), "host die should still be blank");
|
assert!(pgr.host_die.is_none(), "host die should still be blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -379,7 +406,10 @@ mod tests {
|
||||||
complete_ceremony(&mut b);
|
complete_ceremony(&mut b);
|
||||||
|
|
||||||
// Roll for whoever won the ceremony (either player could go first).
|
// Roll for whoever won the ceremony (either player could go first).
|
||||||
let first_player = b.get_view_state().active_mp_player.expect("someone should be active");
|
let first_player = b
|
||||||
|
.get_view_state()
|
||||||
|
.active_mp_player
|
||||||
|
.expect("someone should be active");
|
||||||
b.inform_rpc(first_player, PlayerAction::Roll);
|
b.inform_rpc(first_player, PlayerAction::Roll);
|
||||||
let states = drain_deltas(&mut b);
|
let states = drain_deltas(&mut b);
|
||||||
assert!(!states.is_empty(), "expected a state broadcast after roll");
|
assert!(!states.is_empty(), "expected a state broadcast after roll");
|
||||||
|
|
@ -411,10 +441,7 @@ mod tests {
|
||||||
let wrong_player = if active == Some(0) { 1u16 } else { 0u16 };
|
let wrong_player = if active == Some(0) { 1u16 } else { 0u16 };
|
||||||
b.inform_rpc(wrong_player, PlayerAction::Roll);
|
b.inform_rpc(wrong_player, PlayerAction::Roll);
|
||||||
let cmds = b.drain_commands();
|
let cmds = b.drain_commands();
|
||||||
assert!(
|
assert!(cmds.is_empty(), "wrong player roll should be ignored");
|
||||||
cmds.is_empty(),
|
|
||||||
"wrong player roll should be ignored"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue