summaryrefslogtreecommitdiff
path: root/src/state.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/state.rs')
-rw-r--r--src/state.rs355
1 files changed, 0 insertions, 355 deletions
diff --git a/src/state.rs b/src/state.rs
deleted file mode 100644
index acbce80..0000000
--- a/src/state.rs
+++ /dev/null
@@ -1,355 +0,0 @@
-use crate::command::Command;
-use crate::consts::*;
-use std::collections::BTreeSet;
-use std::ops::Bound::{Excluded, Included};
-use std::rc::Rc;
-
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
-pub enum GameStatus {
- Continue,
- PlayerOneWon,
- PlayerTwoWon,
- Draw, // Until I add score I guess
-}
-
-// TODO: Maintain sorted vecs for these BTrees? Do the range counts
-// with binary searches to find indices only.
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-pub struct GameState {
- pub status: GameStatus,
- pub players: [Player; 2],
- pub muds: Rc<BTreeSet<Position>>,
- pub oil_spills: Rc<BTreeSet<Position>>,
- pub powerup_oils: Rc<BTreeSet<Position>>,
- pub powerup_boosts: Rc<BTreeSet<Position>>,
-}
-
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-pub struct Player {
- pub position: Position,
- pub speed: u16,
- pub boost_remaining: u8,
- pub oils: u16,
- pub boosts: u16,
-}
-
-#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Position {
- pub y: u8,
- pub x: u16,
-}
-
-#[derive(Debug, Clone, Default)]
-pub struct GameStateUpdateEvents {
- pub players: [GameStatePlayerUpdateEvents; 2],
-}
-#[derive(Debug, Clone, Default)]
-pub struct GameStatePlayerUpdateEvents {
- pub boosts_used: u16,
- pub boosts_collected: u16,
- pub boosts_maintained: u8,
- pub mud_hit: u16,
- pub oil_collected: u16,
- pub distance_travelled: u16,
-}
-
-impl GameState {
- pub fn update(&mut self, commands: [Command; 2], events: &mut GameStateUpdateEvents) {
- if self.status != GameStatus::Continue {
- return;
- }
-
- let next_positions = [
- self.do_command(0, &commands[0], &mut events.players[0]),
- self.do_command(1, &commands[1], &mut events.players[1]),
- ];
- let next_positions = self.update_player_collisions(next_positions, events);
- self.update_player_travel(next_positions, events);
-
- self.status = if self.players[0].finished() && self.players[1].finished() {
- if self.players[0].speed > self.players[1].speed {
- GameStatus::PlayerOneWon
- } else if self.players[0].speed < self.players[1].speed {
- GameStatus::PlayerTwoWon
- } else {
- GameStatus::Draw
- }
- } else if self.players[0].finished() {
- GameStatus::PlayerOneWon
- } else if self.players[1].finished() {
- GameStatus::PlayerTwoWon
- } else {
- GameStatus::Continue
- };
- }
-
- pub fn reset_players_to_start(&mut self) {
- self.players[0].position = Position { x: 1, y: 1 };
- self.players[1].position = Position { x: 1, y: 4 };
- for player in &mut self.players {
- player.speed = 5;
- player.boost_remaining = 0;
- player.oils = 0;
- player.boosts = 0;
- }
- }
-
- fn do_command(
- &mut self,
- player_index: usize,
- command: &Command,
- events: &mut GameStatePlayerUpdateEvents,
- ) -> Position {
- use Command::*;
- self.players[player_index].tick_boost();
- let mut next_y = self.players[player_index].position.y;
-
- match command {
- Nothing => {}
- Accelerate => self.players[player_index].accelerate(),
- Decelerate => self.players[player_index].decelerate(),
- TurnLeft => next_y = next_y.saturating_sub(1).max(MIN_Y),
- TurnRight => next_y = next_y.saturating_add(1).min(MAX_Y),
- UseBoost => {
- events.boosts_used += 1;
- self.players[player_index].boost();
- }
- UseOil => {
- debug_assert!(self.players[player_index].oils > 0);
- self.players[player_index].oils = self.players[player_index].oils.saturating_sub(1);
- let player_position = self.players[player_index].position;
- let mut oil_spills = (*self.oil_spills).clone();
- oil_spills.insert(Position {
- x: player_position.x.saturating_sub(1),
- y: player_position.y,
- });
- self.oil_spills = Rc::new(oil_spills);
- }
- }
-
- let turning = match command {
- TurnLeft | TurnRight => true,
- _ => false,
- };
-
- let next_x = self.players[player_index].next_position_x(turning);
- Position {
- x: next_x,
- y: next_y,
- }
- }
-
- fn update_player_collisions(
- &mut self,
- next_positions: [Position; 2],
- _events: &mut GameStateUpdateEvents,
- ) -> [Position; 2] {
- let same_lanes_before = self.players[0].position.y == self.players[1].position.y;
- let same_lanes_after = next_positions[0].y == next_positions[1].y;
- let first_passing_second = self.players[0].position.x < self.players[1].position.x
- && next_positions[0].x >= next_positions[1].x;
- let second_passing_first = self.players[1].position.x < self.players[0].position.x
- && next_positions[1].x >= next_positions[0].x;
- let same_x_after = next_positions[0].x == next_positions[1].x;
-
- if same_lanes_before && same_lanes_after && first_passing_second {
- [
- Position {
- y: next_positions[0].y,
- x: next_positions[1].x.saturating_sub(1),
- },
- next_positions[1],
- ]
- } else if same_lanes_before && same_lanes_after && second_passing_first {
- [
- next_positions[0],
- Position {
- y: next_positions[1].y,
- x: next_positions[0].x.saturating_sub(1),
- },
- ]
- } else if same_lanes_after && same_x_after {
- [
- Position {
- y: self.players[0].position.y,
- x: self.players[0].next_position_x(true),
- },
- Position {
- y: self.players[1].position.y,
- x: self.players[1].next_position_x(true),
- },
- ]
- } else {
- next_positions
- }
- }
-
- fn update_player_travel(
- &mut self,
- next_positions: [Position; 2],
- events: &mut GameStateUpdateEvents,
- ) {
- for (i, (player, next_position)) in self
- .players
- .iter_mut()
- .zip(next_positions.iter())
- .enumerate()
- {
- player.move_along(
- *next_position,
- &self.muds,
- &self.oil_spills,
- &self.powerup_oils,
- &self.powerup_boosts,
- &mut events.players[i],
- );
- }
- }
-
- pub fn valid_moves(&self, player_index: usize) -> Vec<Command> {
- let player = &self.players[player_index];
- let mut result = Vec::with_capacity(7);
- result.push(Command::Nothing);
- result.push(Command::Accelerate);
- if player.speed > SPEED_0 {
- result.push(Command::Decelerate);
- }
- if player.position.y > MIN_Y {
- result.push(Command::TurnLeft);
- }
- if player.position.y < MAX_Y - 1 {
- result.push(Command::TurnRight);
- }
- if player.boosts > 0 {
- result.push(Command::UseBoost);
- }
- if player.oils > 0 {
- result.push(Command::UseOil);
- }
- result
- }
-
- pub fn good_moves(&self, player_index: usize) -> Vec<Command> {
- let player = &self.players[player_index];
- let mut result = Vec::with_capacity(5);
- result.push(Command::Accelerate);
- if player.position.y > MIN_Y {
- result.push(Command::TurnLeft);
- }
- if player.position.y < MAX_Y - 1 {
- result.push(Command::TurnRight);
- }
- if player.boosts > 0 {
- result.push(Command::UseBoost);
- }
- if player.oils > 0 {
- result.push(Command::UseOil);
- }
- result
- }
-}
-
-impl Player {
- fn accelerate(&mut self) {
- self.speed = match self.speed {
- i if i < SPEED_1 => SPEED_1,
- i if i < SPEED_2 => SPEED_2,
- i if i < SPEED_3 => SPEED_3,
- SPEED_BOOST => SPEED_BOOST,
- _ => SPEED_4,
- };
- }
-
- fn decelerate(&mut self) {
- self.speed = match self.speed {
- i if i <= SPEED_1 => SPEED_0,
- i if i <= SPEED_2 => SPEED_1,
- i if i <= SPEED_3 => SPEED_2,
- i if i <= SPEED_4 => SPEED_3,
- _ => SPEED_4,
- };
- self.boost_remaining = 0;
- }
-
- fn decelerate_from_obstacle(&mut self) {
- self.speed = match self.speed {
- i if i <= SPEED_2 => SPEED_1,
- i if i <= SPEED_3 => SPEED_2,
- i if i <= SPEED_4 => SPEED_3,
- _ => SPEED_4,
- };
- self.boost_remaining = 0;
- }
-
- fn boost(&mut self) {
- debug_assert!(self.boosts > 0);
- self.speed = SPEED_BOOST;
- self.boost_remaining = BOOST_DURATION;
- self.boosts = self.boosts.saturating_sub(1);
- }
-
- fn tick_boost(&mut self) {
- self.boost_remaining = self.boost_remaining.saturating_sub(1);
- if self.boost_remaining == 0 && self.speed == SPEED_BOOST {
- self.speed = SPEED_4;
- }
- }
-
- fn next_position_x(&mut self, turning: bool) -> u16 {
- if turning {
- self.position.x.saturating_add(self.speed.saturating_sub(1))
- } else {
- self.position.x.saturating_add(self.speed)
- }
- }
-
- fn move_along(
- &mut self,
- next_position: Position,
- muds: &BTreeSet<Position>,
- oil_spills: &BTreeSet<Position>,
- powerup_oils: &BTreeSet<Position>,
- powerup_boosts: &BTreeSet<Position>,
- events: &mut GameStatePlayerUpdateEvents,
- ) {
- let range = (
- Included(Position {
- y: next_position.y,
- x: self.position.x.saturating_add(1),
- }),
- Excluded(Position {
- y: next_position.y,
- x: next_position.x.saturating_add(1),
- }),
- );
-
- let mud_hit = muds
- .range(range)
- .count()
- .saturating_add(oil_spills.range(range).count());
- for _ in 0..mud_hit {
- self.decelerate_from_obstacle();
- }
-
- let oil_collected = powerup_oils.range(range).count() as u16;
- self.oils = self.oils.saturating_add(oil_collected);
- let boosts_collected = powerup_boosts.range(range).count() as u16;
- self.boosts = self.boosts.saturating_add(boosts_collected);
-
- events.mud_hit = events.mud_hit.saturating_add(mud_hit as u16);
- events.boosts_collected = events.boosts_collected.saturating_add(boosts_collected);
- events.oil_collected = events.oil_collected.saturating_add(oil_collected);
- events.distance_travelled = events
- .distance_travelled
- .saturating_add(next_position.x.saturating_sub(self.position.x));
- if self.speed == SPEED_BOOST {
- events.boosts_maintained = events.boosts_maintained.saturating_add(1);
- }
-
- self.position = next_position;
- }
-
- fn finished(&self) -> bool {
- self.position.x >= WIDTH
- }
-}