refactor(backend): encapsulate throw lifecycle and clean dead code in game.rs
Add Game::process_throw to centralize throw→simulation→scoring→state flow. Remove dead room_tx field, simplify add_player, and rename end_ends_or_continue. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
27e524a418
commit
1f673b4eba
@ -24,7 +24,13 @@ pub struct Game {
|
||||
stones_red: u8,
|
||||
stones_yellow: u8,
|
||||
last_end_scored: Option<(u8, i32, Option<Team>)>,
|
||||
pub room_tx: Option<tokio::sync::broadcast::Sender<ServerMessage>>,
|
||||
}
|
||||
|
||||
pub struct ThrowOutcome {
|
||||
pub trajectory: Vec<(f32, f32, f32)>,
|
||||
pub end_scored: Option<ServerMessage>,
|
||||
pub state_message: ServerMessage,
|
||||
pub game_over: Option<ServerMessage>,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
@ -42,43 +48,31 @@ impl Game {
|
||||
stones_red: STONES_PER_TEAM,
|
||||
stones_yellow: STONES_PER_TEAM,
|
||||
last_end_scored: None,
|
||||
room_tx: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_player(&mut self, id: String, preferred: Option<Team>) -> Option<Team> {
|
||||
let team = match preferred {
|
||||
Some(Team::Red) if self.red.is_none() => Some(Team::Red),
|
||||
Some(Team::Yellow) if self.yellow.is_none() => Some(Team::Yellow),
|
||||
Some(_) => {
|
||||
// Preferred is taken; fall back to the other free team.
|
||||
if self.red.is_none() {
|
||||
Some(Team::Red)
|
||||
} else if self.yellow.is_none() {
|
||||
Some(Team::Yellow)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Legacy first-free logic.
|
||||
if self.red.is_none() {
|
||||
Some(Team::Red)
|
||||
} else if self.yellow.is_none() {
|
||||
Some(Team::Yellow)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
let team = preferred
|
||||
.filter(|t| self.slot_for(t).is_none())
|
||||
.or_else(|| self.first_open_team())?;
|
||||
|
||||
if let Some(t) = team {
|
||||
let player = Player { id, team: t, connected: true };
|
||||
match t {
|
||||
Team::Red => self.red = Some(player),
|
||||
Team::Yellow => self.yellow = Some(player),
|
||||
}
|
||||
Some(t)
|
||||
let player = Player { id, team, connected: true };
|
||||
*self.slot_for(&team) = Some(player);
|
||||
Some(team)
|
||||
}
|
||||
|
||||
fn slot_for(&mut self, team: &Team) -> &mut Option<Player> {
|
||||
match team {
|
||||
Team::Red => &mut self.red,
|
||||
Team::Yellow => &mut self.yellow,
|
||||
}
|
||||
}
|
||||
|
||||
fn first_open_team(&self) -> Option<Team> {
|
||||
if self.red.is_none() {
|
||||
Some(Team::Red)
|
||||
} else if self.yellow.is_none() {
|
||||
Some(Team::Yellow)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -171,6 +165,34 @@ impl Game {
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
pub fn process_throw(
|
||||
&mut self,
|
||||
player_id: &str,
|
||||
broom_x: f32,
|
||||
broom_y: f32,
|
||||
weight: u8,
|
||||
curl: i8,
|
||||
friction: f32,
|
||||
) -> Result<ThrowOutcome, String> {
|
||||
let trajectory = self.handle_throw(player_id, broom_x, broom_y, weight, curl, friction)?;
|
||||
self.finish_simulation();
|
||||
|
||||
let end_scored = self.take_last_end_scored();
|
||||
let state_message = self.game_state_message();
|
||||
let game_over = if self.phase == GamePhase::GameComplete {
|
||||
Some(self.game_over_message())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(ThrowOutcome {
|
||||
trajectory,
|
||||
end_scored,
|
||||
state_message,
|
||||
game_over,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn finish_simulation(&mut self) {
|
||||
if self.phase != GamePhase::Simulating {
|
||||
return;
|
||||
@ -229,10 +251,10 @@ impl Game {
|
||||
|
||||
self.last_end_scored = Some((self.end, points, scoring_team));
|
||||
self.phase = GamePhase::EndComplete;
|
||||
self.end_ends_or_continue(points, scoring_team);
|
||||
self.advance_end_or_finish();
|
||||
}
|
||||
|
||||
fn end_ends_or_continue(&mut self, _points: i32, _scoring_team: Option<Team>) {
|
||||
fn advance_end_or_finish(&mut self) {
|
||||
let tied = self.scores[0] == self.scores[1];
|
||||
let after_regulation = self.end >= ENDS;
|
||||
|
||||
@ -241,10 +263,6 @@ impl Game {
|
||||
return;
|
||||
}
|
||||
|
||||
if after_regulation && tied {
|
||||
// Extra end
|
||||
}
|
||||
|
||||
self.end += 1;
|
||||
self.stones_red = STONES_PER_TEAM;
|
||||
self.stones_yellow = STONES_PER_TEAM;
|
||||
@ -311,13 +329,11 @@ pub struct Room {
|
||||
impl Room {
|
||||
pub fn new(id: &str) -> Self {
|
||||
let (tx, _) = tokio::sync::broadcast::channel(256);
|
||||
let mut room = Self {
|
||||
Self {
|
||||
id: id.to_string(),
|
||||
game: Game::new(),
|
||||
tx,
|
||||
};
|
||||
room.game.room_tx = Some(room.tx.clone());
|
||||
room
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user