From d949fd80c322626e6c01e1be6e90444b79ec8328 Mon Sep 17 00:00:00 2001 From: Arkitu <85173315+Arkitu@users.noreply.github.com> Date: Fri, 11 Apr 2025 20:28:25 +0200 Subject: [PATCH] better performances + show team --- src/game.rs | 119 +++++++++++++++++++++++++----------- src/socket.rs | 8 ++- {web => static}/htmx.js | 0 {web => static}/htmx.min.js | 0 {web => static}/index.html | 9 +-- 5 files changed, 93 insertions(+), 43 deletions(-) rename {web => static}/htmx.js (100%) rename {web => static}/htmx.min.js (100%) rename {web => static}/index.html (78%) diff --git a/src/game.rs b/src/game.rs index 79783c2..b975b13 100644 --- a/src/game.rs +++ b/src/game.rs @@ -12,17 +12,76 @@ static BOARD: AtomicU32 = AtomicU32::new(0); pub struct GameClient { res_buf: Vec, + /// State of the board last time it has been sent + last_board: u32, team: Team } impl GameClient { pub fn new(team: Team) -> Self { Self { res_buf: Vec::new(), + last_board: 0, team } } + /// Generate board html + pub async fn generate_board_res<'a>(&'a mut self, board: u32, turn: Team, outer_html: bool) -> &'a [u8] { + self.res_buf.clear(); + if outer_html { + unwrap(self.res_buf.extend_from_slice( + b"
" + )).await; + } + unwrap(write!( + self.res_buf, + "

Team : {}

\ +
", + self.team.color(), + self.team.name() + )).await; + for c in 0..=8 { + let picked_by = if board & 2_u32.pow(c) != 0 { + Some(Team::Zero) + } else if board & 2_u32.pow(9 + c) != 0 { + Some(Team::One) + } else { + None + }; + match picked_by { + Some(t) => { + unwrap(write!( + self.res_buf, + "
", + t.color() + )).await; + } + None => if self.team == turn.into() { + unwrap(write!( + self.res_buf, + "", + c + )).await; + } else { + unwrap(self.res_buf.extend_from_slice( + b"
", + )).await; + } + }; + } + unwrap(self.res_buf.extend_from_slice(b"
")).await; + if outer_html { + unwrap(self.res_buf.extend_from_slice(b"
")).await; + } + &self.res_buf + } pub async fn handle_request<'a>(&'a mut self, path: &str) -> (HttpResCode, &'static str, &'a [u8]) { - if (path.starts_with("/ttt/cell") && path.len() == 10) || path == "/ttt/board" { + if (path.starts_with("/ttt/cell") && path.len() == 10) || path == "/ttt/game" { let mut board = BOARD.load(Ordering::Acquire); let mut turn = TURN.load(Ordering::Acquire); @@ -46,42 +105,16 @@ impl GameClient { BOARD.store(board, Ordering::Release); TURN.store(turn, Ordering::Release); } - - self.res_buf.clear(); - for c in 0..=8 { - let picked_by = if board & 2_u32.pow(c) != 0 { - Some(Team::Zero) - } else if board & 2_u32.pow(9 + c) != 0 { - Some(Team::One) - } else { - None - }; - match picked_by { - Some(Team::Zero) => { - unwrap(self.res_buf - .extend_from_slice( - b"
", - )).await; - } - Some(Team::One) => { - unwrap(self.res_buf.extend_from_slice( - b"
", - )).await; - } - None => if self.team == turn.into() { - unwrap(write!( - self.res_buf, - "", - c - )).await; - } else { - unwrap(self.res_buf.extend_from_slice( - b"
", - )).await; - } - }; + if self.last_board != board { + self.last_board = board; + (HttpResCode::Ok, "html", self.generate_board_res(board, turn.into(), false).await) + } else { + (HttpResCode::NoContent, "", &[]) } - (HttpResCode::Ok, "html", &self.res_buf) + } else if path == "/ttt/initial_game" { + let board = BOARD.load(Ordering::Acquire); + let turn = TURN.load(Ordering::Acquire); + (HttpResCode::Ok, "html", self.generate_board_res(board, turn.into(), true).await) } else { (HttpResCode::NotFound, "", &[]) } @@ -115,6 +148,20 @@ impl Not for Team { } } } +impl Team { + fn color(self) -> &'static str { + match self { + Team::Zero => "dodgerblue", + Team::One => "firebrick" + } + } + fn name(self) -> &'static str { + match self { + Team::Zero => "blue", + Team::One => "red" + } + } +} #[derive(Debug, Clone, Copy)] enum Cell { diff --git a/src/socket.rs b/src/socket.rs index a38c190..3075a7f 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -105,16 +105,16 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, team: Team, port: u Timer::after_secs(0).await; let (code, res_type, res_content): (HttpResCode, &str, &[u8]) = match path { - "/" => (HttpResCode::Ok, "html", include_bytes!("../web/index.html")), + "/" => (HttpResCode::Ok, "html", include_bytes!("../static/index.html")), "/htmx.min.js" => ( HttpResCode::Ok, "javascript", - include_bytes!("../web/htmx.min.js"), + include_bytes!("../static/htmx.min.js"), ), "/htmx.js" => ( HttpResCode::Ok, "javascript", - include_bytes!("../web/htmx.js"), + include_bytes!("../static/htmx.js"), ), p => game_client.handle_request(p).await }; @@ -168,6 +168,7 @@ impl Into<&str> for HttpRequestType { #[derive(Debug, Clone, Copy)] pub enum HttpResCode { Ok, + NoContent, NotFound, Forbidden, } @@ -175,6 +176,7 @@ impl Into<&str> for HttpResCode { fn into(self) -> &'static str { match self { HttpResCode::Ok => "HTTP/1.1 200 OK", + HttpResCode::NoContent => "HTTP/1.1 204 NO CONTENT", HttpResCode::NotFound => "HTTP/1.1 404 NOT FOUND", HttpResCode::Forbidden => "HTTP/1.1 403 FORBIDDEN", } diff --git a/web/htmx.js b/static/htmx.js similarity index 100% rename from web/htmx.js rename to static/htmx.js diff --git a/web/htmx.min.js b/static/htmx.min.js similarity index 100% rename from web/htmx.min.js rename to static/htmx.min.js diff --git a/web/index.html b/static/index.html similarity index 78% rename from web/index.html rename to static/index.html index f3d3bfe..f5e788e 100644 --- a/web/index.html +++ b/static/index.html @@ -20,10 +20,11 @@

TicTacToe