Add KeepAlive message so players can detect abandoned games

This commit is contained in:
Michael Vines 2018-09-27 19:58:51 -07:00
parent 19a7ff0c43
commit 0727c440b3
1 changed files with 28 additions and 13 deletions

View File

@ -61,6 +61,8 @@ struct Game {
player_o: Option<Pubkey>, player_o: Option<Pubkey>,
state: State, state: State,
grid: [GridItem; 9], grid: [GridItem; 9],
keep_alive_x: i64,
keep_alive_o: i64,
} }
impl Game { impl Game {
@ -114,29 +116,29 @@ impl Game {
triple.iter().all(|&i| i == x_or_o) triple.iter().all(|&i| i == x_or_o)
} }
pub fn next_move(self: &mut Game, player: Pubkey, x: usize, y: usize) -> Result<()> { pub fn next_move(self: &mut Game, player: &Pubkey, x: usize, y: usize) -> Result<()> {
let grid_index = y * 3 + x; let grid_index = y * 3 + x;
if grid_index >= self.grid.len() || self.grid[grid_index] != GridItem::Free { if grid_index >= self.grid.len() || self.grid[grid_index] != GridItem::Free {
return Err(Error::InvalidMove); Err(Error::InvalidMove)?;
} }
let (x_or_o, won_state) = match self.state { let (x_or_o, won_state) = match self.state {
State::XMove => { State::XMove => {
if player != self.player_x { if *player != self.player_x {
return Err(Error::PlayerNotFound)?; return Err(Error::PlayerNotFound);
} }
self.state = State::OMove; self.state = State::OMove;
(GridItem::X, State::XWon) (GridItem::X, State::XWon)
} }
State::OMove => { State::OMove => {
if player != self.player_o.unwrap() { if *player != self.player_o.unwrap() {
return Err(Error::PlayerNotFound)?; return Err(Error::PlayerNotFound);
} }
self.state = State::XMove; self.state = State::XMove;
(GridItem::O, State::OWon) (GridItem::O, State::OWon)
} }
_ => { _ => {
return Err(Error::NotYourTurn)?; return Err(Error::NotYourTurn);
} }
}; };
self.grid[grid_index] = x_or_o; self.grid[grid_index] = x_or_o;
@ -162,15 +164,27 @@ impl Game {
Ok(()) Ok(())
} }
pub fn keep_alive(self: &mut Game, player: &Pubkey, timestamp: i64) -> Result<()> {
if *player == self.player_x {
self.keep_alive_x = timestamp;
} else if Some(*player) == self.player_o {
self.keep_alive_o = timestamp;
} else {
Err(Error::PlayerNotFound)?;
}
Ok(())
}
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
enum Command { enum Command {
Init, // player X initializes a new game Init, // player X initializes a new game
Join, // player O wants to join Join, // player O wants to join
Accept, // player X accepts the Join request Accept, // player X accepts the Join request
Reject, // player X rejects the Join request Reject, // player X rejects the Join request
Move(u8, u8), // player X/O mark board position (x, y) KeepAlive(i64), // player X/O keep alive (seconds since UNIX epoch)
Move(u8, u8), // player X/O mark board position (x, y)
} }
#[derive(Debug, Default, Serialize, Deserialize)] #[derive(Debug, Default, Serialize, Deserialize)]
@ -229,7 +243,8 @@ impl TicTacToeProgram {
Err(Error::PlayerNotFound) Err(Error::PlayerNotFound)
} }
} }
Command::Move(x, y) => game.next_move(*player, *x as usize, *y as usize), Command::Move(x, y) => game.next_move(player, *x as usize, *y as usize),
Command::KeepAlive(timestamp) => game.keep_alive(player, *timestamp),
Command::Init => panic!("Unreachable"), Command::Init => panic!("Unreachable"),
} }
} else { } else {