end of game

This commit is contained in:
Arkitu 2025-04-12 19:14:57 +02:00
parent d949fd80c3
commit 2aabfa52d1

View File

@ -1,4 +1,5 @@
use core::{ops::Not, sync::atomic::Ordering}; use core::{ops::Not, sync::atomic::Ordering};
use embassy_time::{Duration, Instant};
use heapless::Vec; use heapless::Vec;
use pico_website::unwrap; use pico_website::unwrap;
use portable_atomic::{AtomicBool, AtomicU32}; use portable_atomic::{AtomicBool, AtomicU32};
@ -14,14 +15,52 @@ pub struct GameClient {
res_buf: Vec<u8, 4096>, res_buf: Vec<u8, 4096>,
/// State of the board last time it has been sent /// State of the board last time it has been sent
last_board: u32, last_board: u32,
team: Team team: Team,
end: Option<(Instant, Option<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, last_board: 0,
team team,
end: None
}
}
pub fn is_ended(&self, board: u32) -> (bool, Option<Team>) {
if let Some((_, t)) = self.end {
return (true, t);
}
for (t, m) in [(Team::Zero, 1), (Team::One, 2_u32.pow(9))] {
for w in [
0b111000000,
0b000111000,
0b000000111,
0b100100100,
0b010010010,
0b001001001,
0b100010001,
0b001010100
] {
if board & (w*m) == (w*m) {
return (true, Some(t))
}
}
}
// TODO: check for draw
(false, None)
}
pub fn update_end_state(&mut self, board: &mut u32) {
if let Some((i, _)) = self.end {
if i+Duration::from_secs(7) < Instant::now() {
self.end = None;
BOARD.store(0, Ordering::Release);
*board = 0;
}
} else {
if let (true, t) = self.is_ended(*board) {
self.end = Some((Instant::now(), t));
}
} }
} }
/// Generate board html /// Generate board html
@ -40,11 +79,24 @@ impl GameClient {
} }
unwrap(write!( unwrap(write!(
self.res_buf, self.res_buf,
"<h3>Team : <span style=\"color:{}\">{}</span></h3>\ "<h3>Team : <span style=\"color:{}\">{}</span></h3>",
<div id=\"grid\">",
self.team.color(), self.team.color(),
self.team.name() self.team.name()
)).await; )).await;
match self.end {
Some((_, Some(t))) => unwrap(write!(
self.res_buf,
"<br><h3>Team <span style=\"color:{}\">{}</span> has won!</h3><br>",
t.color(),
t.name()
)).await,
Some((_, None)) => unwrap(write!(
self.res_buf,
"<br><h3>Draw!</h3><br>",
)).await,
None => {}
}
unwrap(self.res_buf.extend_from_slice(b"<div id=\"grid\">")).await;
for c in 0..=8 { for c in 0..=8 {
let picked_by = if board & 2_u32.pow(c) != 0 { let picked_by = if board & 2_u32.pow(c) != 0 {
Some(Team::Zero) Some(Team::Zero)
@ -61,7 +113,7 @@ impl GameClient {
t.color() t.color()
)).await; )).await;
} }
None => if self.team == turn.into() { None => if self.team == turn.into() && self.end.is_none() {
unwrap(write!( unwrap(write!(
self.res_buf, self.res_buf,
"<button class=\"cell\" hx-post=\"/ttt/cell{}\" hx-trigger=\"click\" hx-target=\"#game\" hx-swap=\"innerHTML\"></button>", "<button class=\"cell\" hx-post=\"/ttt/cell{}\" hx-trigger=\"click\" hx-target=\"#game\" hx-swap=\"innerHTML\"></button>",
@ -105,6 +157,7 @@ impl GameClient {
BOARD.store(board, Ordering::Release); BOARD.store(board, Ordering::Release);
TURN.store(turn, Ordering::Release); TURN.store(turn, Ordering::Release);
} }
self.update_end_state(&mut board);
if self.last_board != board { if self.last_board != board {
self.last_board = board; self.last_board = board;
(HttpResCode::Ok, "html", self.generate_board_res(board, turn.into(), false).await) (HttpResCode::Ok, "html", self.generate_board_res(board, turn.into(), false).await)