better performances + show team
This commit is contained in:
parent
f3124bcf03
commit
d949fd80c3
119
src/game.rs
119
src/game.rs
@ -12,17 +12,76 @@ static BOARD: AtomicU32 = AtomicU32::new(0);
|
|||||||
|
|
||||||
pub struct GameClient {
|
pub struct GameClient {
|
||||||
res_buf: Vec<u8, 4096>,
|
res_buf: Vec<u8, 4096>,
|
||||||
|
/// State of the board last time it has been sent
|
||||||
|
last_board: u32,
|
||||||
team: Team
|
team: Team
|
||||||
}
|
}
|
||||||
impl GameClient {
|
impl GameClient {
|
||||||
pub fn new(team: Team) -> Self {
|
pub fn new(team: Team) -> Self {
|
||||||
Self {
|
Self {
|
||||||
res_buf: Vec::new(),
|
res_buf: Vec::new(),
|
||||||
|
last_board: 0,
|
||||||
team
|
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"<div \
|
||||||
|
id=\"game\" \
|
||||||
|
hx-get=\"/ttt/game\" \
|
||||||
|
hx-swap=\"innerHTML\" \
|
||||||
|
hx-trigger=\"every 100ms\" \
|
||||||
|
hx-target=\"this\"\
|
||||||
|
>"
|
||||||
|
)).await;
|
||||||
|
}
|
||||||
|
unwrap(write!(
|
||||||
|
self.res_buf,
|
||||||
|
"<h3>Team : <span style=\"color:{}\">{}</span></h3>\
|
||||||
|
<div id=\"grid\">",
|
||||||
|
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,
|
||||||
|
"<div class=\"cell\" style=\"background-color:{}\"></div>",
|
||||||
|
t.color()
|
||||||
|
)).await;
|
||||||
|
}
|
||||||
|
None => if self.team == turn.into() {
|
||||||
|
unwrap(write!(
|
||||||
|
self.res_buf,
|
||||||
|
"<button class=\"cell\" hx-post=\"/ttt/cell{}\" hx-trigger=\"click\" hx-target=\"#game\" hx-swap=\"innerHTML\"></button>",
|
||||||
|
c
|
||||||
|
)).await;
|
||||||
|
} else {
|
||||||
|
unwrap(self.res_buf.extend_from_slice(
|
||||||
|
b"<div class=\"cell\"></div>",
|
||||||
|
)).await;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
unwrap(self.res_buf.extend_from_slice(b"</div>")).await;
|
||||||
|
if outer_html {
|
||||||
|
unwrap(self.res_buf.extend_from_slice(b"</div>")).await;
|
||||||
|
}
|
||||||
|
&self.res_buf
|
||||||
|
}
|
||||||
pub async fn handle_request<'a>(&'a mut self, path: &str) -> (HttpResCode, &'static str, &'a [u8]) {
|
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 board = BOARD.load(Ordering::Acquire);
|
||||||
let mut turn = TURN.load(Ordering::Acquire);
|
let mut turn = TURN.load(Ordering::Acquire);
|
||||||
|
|
||||||
@ -46,42 +105,16 @@ impl GameClient {
|
|||||||
BOARD.store(board, Ordering::Release);
|
BOARD.store(board, Ordering::Release);
|
||||||
TURN.store(turn, Ordering::Release);
|
TURN.store(turn, Ordering::Release);
|
||||||
}
|
}
|
||||||
|
if self.last_board != board {
|
||||||
self.res_buf.clear();
|
self.last_board = board;
|
||||||
for c in 0..=8 {
|
(HttpResCode::Ok, "html", self.generate_board_res(board, turn.into(), false).await)
|
||||||
let picked_by = if board & 2_u32.pow(c) != 0 {
|
} else {
|
||||||
Some(Team::Zero)
|
(HttpResCode::NoContent, "", &[])
|
||||||
} 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"<div class=\"cell\" style=\"background-color:blue\"></div>",
|
|
||||||
)).await;
|
|
||||||
}
|
|
||||||
Some(Team::One) => {
|
|
||||||
unwrap(self.res_buf.extend_from_slice(
|
|
||||||
b"<div class=\"cell\" style=\"background-color:red\"></div>",
|
|
||||||
)).await;
|
|
||||||
}
|
|
||||||
None => if self.team == turn.into() {
|
|
||||||
unwrap(write!(
|
|
||||||
self.res_buf,
|
|
||||||
"<button class=\"cell\" hx-post=\"/ttt/cell{}\" hx-trigger=\"click\" hx-target=\"#grid\" hx-swap=\"innerHTML\"></button>",
|
|
||||||
c
|
|
||||||
)).await;
|
|
||||||
} else {
|
|
||||||
unwrap(self.res_buf.extend_from_slice(
|
|
||||||
b"<div class=\"cell\"></div>",
|
|
||||||
)).await;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
(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 {
|
} else {
|
||||||
(HttpResCode::NotFound, "", &[])
|
(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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum Cell {
|
enum Cell {
|
||||||
|
@ -105,16 +105,16 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, team: Team, port: u
|
|||||||
Timer::after_secs(0).await;
|
Timer::after_secs(0).await;
|
||||||
|
|
||||||
let (code, res_type, res_content): (HttpResCode, &str, &[u8]) = match path {
|
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" => (
|
"/htmx.min.js" => (
|
||||||
HttpResCode::Ok,
|
HttpResCode::Ok,
|
||||||
"javascript",
|
"javascript",
|
||||||
include_bytes!("../web/htmx.min.js"),
|
include_bytes!("../static/htmx.min.js"),
|
||||||
),
|
),
|
||||||
"/htmx.js" => (
|
"/htmx.js" => (
|
||||||
HttpResCode::Ok,
|
HttpResCode::Ok,
|
||||||
"javascript",
|
"javascript",
|
||||||
include_bytes!("../web/htmx.js"),
|
include_bytes!("../static/htmx.js"),
|
||||||
),
|
),
|
||||||
p => game_client.handle_request(p).await
|
p => game_client.handle_request(p).await
|
||||||
};
|
};
|
||||||
@ -168,6 +168,7 @@ impl Into<&str> for HttpRequestType {
|
|||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum HttpResCode {
|
pub enum HttpResCode {
|
||||||
Ok,
|
Ok,
|
||||||
|
NoContent,
|
||||||
NotFound,
|
NotFound,
|
||||||
Forbidden,
|
Forbidden,
|
||||||
}
|
}
|
||||||
@ -175,6 +176,7 @@ impl Into<&str> for HttpResCode {
|
|||||||
fn into(self) -> &'static str {
|
fn into(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
HttpResCode::Ok => "HTTP/1.1 200 OK",
|
HttpResCode::Ok => "HTTP/1.1 200 OK",
|
||||||
|
HttpResCode::NoContent => "HTTP/1.1 204 NO CONTENT",
|
||||||
HttpResCode::NotFound => "HTTP/1.1 404 NOT FOUND",
|
HttpResCode::NotFound => "HTTP/1.1 404 NOT FOUND",
|
||||||
HttpResCode::Forbidden => "HTTP/1.1 403 FORBIDDEN",
|
HttpResCode::Forbidden => "HTTP/1.1 403 FORBIDDEN",
|
||||||
}
|
}
|
||||||
|
0
web/htmx.min.js → static/htmx.min.js
vendored
0
web/htmx.min.js → static/htmx.min.js
vendored
@ -20,10 +20,11 @@
|
|||||||
<body>
|
<body>
|
||||||
<h1>TicTacToe</h1>
|
<h1>TicTacToe</h1>
|
||||||
<div
|
<div
|
||||||
id="grid"
|
id="game"
|
||||||
hx-post="/ttt/board"
|
hx-get="/ttt/initial_game"
|
||||||
hx-swap="innerHTML"
|
hx-swap="outerHTML"
|
||||||
hx-trigger="every 1s"
|
hx-trigger="load"
|
||||||
|
hx-target="this"
|
||||||
></div>
|
></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user