Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions server/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,20 @@ pub fn apply_turn(game: &mut EngineGame, moves: &[(String, Direction)]) {
}
}

/// Spawn food for the next turn in modes that spawn food.
///
/// Food spawning lives outside the per-turn rules pipeline (matching the Go
/// engine, where the game loop spawns food between turns), so every caller of
/// `apply_turn` must also call this. Constrictor games never spawn food; all
/// other modes use the standard chance/minimum settings.
pub fn spawn_food(game: &mut EngineGame) {
if game.meta.ruleset_name == "constrictor" {
return;
}
let mut rng = rand::thread_rng();
rules::food::maybe_spawn_food(&mut rng, &mut game.board, &game.meta.settings);
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -1275,6 +1289,38 @@ mod tests {
}
}

#[test]
fn test_spawn_food_standard_respects_minimum_food() {
let mut game = create_test_game(2);
game.board.food.clear();

spawn_food(&mut game);

// minimum_food is 1, so an empty board must get food back.
assert!(
!game.board.food.is_empty(),
"standard games must respawn food up to minimum_food"
);
}

#[test]
fn test_spawn_food_constrictor_never_spawns() {
let mut game = create_test_game(2);
game.meta.ruleset_name = "constrictor".to_string();
game.board.food.clear();

// food_spawn_chance is probabilistic; run enough iterations that a
// broken guard would virtually always spawn at least once.
for _ in 0..100 {
spawn_food(&mut game);
}

assert!(
game.board.food.is_empty(),
"constrictor games must never spawn food"
);
}

/// Test that create_initial_game assigns unique IDs when the same battlesnake
/// appears multiple times (duplicate snakes in a game)
#[test]
Expand Down
3 changes: 3 additions & 0 deletions server/src/game_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ pub async fn run_game(app_state: &AppState, game_id: Uuid) -> cja::Result<()> {
// Apply the moves using the engine
crate::engine::apply_turn(&mut engine_game, &moves);
engine_game.board.turn += 1;
// Spawn food for the next turn before the frame is recorded, so the
// viewer and the snakes' next /move requests both see it.
crate::engine::spawn_food(&mut engine_game);

// Track newly eliminated snakes
for snake in &engine_game.board.snakes {
Expand Down
Loading