diff --git a/src/apps/ttt.js b/src/apps/ttt.js index b77430d..1575d95 100644 --- a/src/apps/ttt.js +++ b/src/apps/ttt.js @@ -24,12 +24,7 @@ ws.onmessage = (event) => { let msg = JSON.parse(event.data); let cells = []; for (let i = 0; i < 9; i++) { - let owner = null; - if (((msg.board >> (17 - i)) & 1) == 1) { - owner = 0; - } else if (((msg.board >> (8 - i)) & 1) == 1) { - owner = 1; - } + let owner = msg.board[i]; let tagName; if (msg.turn == team && owner === null) { diff --git a/src/apps/ttt.rs b/src/apps/ttt.rs index 818806e..d88f2ab 100644 --- a/src/apps/ttt.rs +++ b/src/apps/ttt.rs @@ -16,31 +16,63 @@ use super::App; // bits [0; 8] : player zero board / bits [9; 17] : player one board / is_ended [18] / is_draw [19] / winner [20]: 0=blue 1=green / current_turn [21]: 0=blue 1=green -#[derive(Debug, Serialize, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Serialize, Clone, PartialEq, Eq)] struct Game { board: [Option; 9], turn: Option, winner: Option, } -static GAME: Mutex = Mutex::new(Game { - board: [None; 9], - turn: Some(Team::Zero), - winner: None, -}); +impl Game { + const fn default() -> Self { + Game { + board: [None; 9], + turn: Some(Team::Zero), + winner: None, + } + } + fn check_end(&mut self) -> bool { + for [a, b, c] in [ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8], + [0, 3, 6], + [1, 4, 7], + [2, 5, 8], + [0, 4, 8], + [2, 4, 6], + ] { + if let Some(t) = self.board[a] { + if self.board[b] == Some(t) && self.board[c] == Some(t) { + self.winner = Some(t); + self.turn = None; + return true; + } + } + } + false + } +} + +static GAME: Mutex = Mutex::new(Game::default()); // {"board"=[null,null,null,null,null,null,null,null,null],"turn"=null,"winner":null} pub struct TttApp { team: Team, last_game: Game, - end: Option<(Instant, Option)>, + /// Only one socket manages the end, this can be None even when it's the end + end: Option, json_buf: [u8; 128], } impl TttApp { pub fn new(team: Team) -> Self { Self { team, - last_game: Game::default(), + last_game: Game { + board: [None; 9], + turn: None, + winner: None, + }, end: None, json_buf: [0; 128], } @@ -134,24 +166,35 @@ impl App for TttApp { ws.send(WsMsg::Ping(&[])).await?; info!("ping"); } + if self.end.map(|e| e.elapsed()).unwrap_or_default() > Duration::from_secs(5) { + self.end = None; + *game = Game { + turn: Some(!unwrap_opt(game.winner).await), + ..Game::default() + }; + } while let Some(r) = ws.rcv().await? { info!("{:?}", r); if let WsMsg::Bytes([c]) = r { - let c = *c; + let c = *c as usize; info!("c={}", c); - if c > 8 {} - match game.board.get_mut(c as usize) { - None => { - warn!("Cell played is too big!"); - return; - } - Some(Some(_)) => { - warn!("Cell is already taken!"); - return; - } - Some(cell) => { - *cell = Some(self.team); + if c >= game.board.len() { + warn!("Cell played is too big!"); + return; + } + if game.board[c].is_some() { + warn!("Cell is already taken!"); + return; + } + if game.turn == Some(self.team) { + game.board[c] = Some(self.team); + game.turn = Some(!self.team); + if game.check_end() { + self.end = Some(Instant::now()); } + } else { + warn!("It's not your turn!"); + return; } info!("{:#?}", game); }