summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Hafskjold Thoresen <martin@vind.ai>2025-01-04 22:43:08 +0100
committerMartin Hafskjold Thoresen <martin@vind.ai>2025-01-04 22:43:08 +0100
commitc5fce19c22ec32129a8b8135c35798e430c5fc53 (patch)
tree885e8bca1c70d65eb4945aa0ba1277fa2232a043
parentfc991e417d0b8ebc87557b9c0817c1f9ed6e7a1b (diff)
downloadmusicgame-c5fce19c22ec32129a8b8135c35798e430c5fc53.tar.gz
musicgame-c5fce19c22ec32129a8b8135c35798e430c5fc53.zip
Working end-to-end game logic
Just need the sound playing now
-rw-r--r--src/main.rs74
-rw-r--r--static/style.css13
2 files changed, 79 insertions, 8 deletions
diff --git a/src/main.rs b/src/main.rs
index a4224d7..92bda43 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -65,7 +65,6 @@ struct Notes {
struct Round {
author: UserId,
- notes: Notes,
guesses: HashMap<UserId, String>,
/// [true] means the judge has accepted it. Missing means they haven't done anything
correct: HashMap<UserId, bool>,
@@ -76,6 +75,7 @@ struct Game {
// If we've started or not
is_started: bool,
+ is_finished: bool,
/// All users that are in the game.
active_users: HashSet<UserId>,
@@ -137,12 +137,6 @@ impl Game {
};
self.rounds.push(Round {
author: uid,
- notes: self
- .submissions
- .get(&uid)
- .context("get users submission")
- .unwrap()
- .clone(),
guesses: HashMap::new(),
correct: HashMap::new(),
});
@@ -189,6 +183,13 @@ impl Game {
r.correct.insert(uid, mark);
}
+ fn scoring(&mut self) {
+ self.broadcast_screen(self.screen_scoring())
+ .context("broadcast scoring screen")
+ .unwrap();
+ self.is_finished = true;
+ }
+
fn screen_submitted(&self) -> Markup {
html! {
h1 { "Submitted!" }
@@ -290,7 +291,40 @@ impl Game {
(self.guess_li(u))
}
}
- button { "Done" }
+ button hx-post=(format!("/game/{}/judge", self.id)) { "Done" }
+ }
+ }
+
+ fn screen_scoring(&self) -> Markup {
+ let mut scores = HashMap::new();
+
+ for u in &self.active_users {
+ scores.insert(u, 0);
+ }
+
+ for r in &self.rounds {
+ for (u, yes) in r.correct.iter() {
+ if *yes {
+ if let Some(n) = scores.get_mut(u) {
+ *n += 1;
+ } else {
+ warn!(u=?u, "Tried to give points to inactive user");
+ }
+ }
+ }
+ }
+ let mut v = scores.into_iter().collect::<Vec<_>>();
+ v.sort_by_key(|t| -t.1);
+
+ html! {
+ h1 { "Leaderboard" }
+ ol {
+ @for (uid, score) in v {
+ li { span { (uid.0) ": " (score) " points" } }
+ }
+ }
+
+ a href="/" { "Back" }
}
}
@@ -332,6 +366,7 @@ impl ServerState {
let g = Game {
id: gid,
is_started: false,
+ is_finished: false,
active_users: HashSet::new(),
submissions: HashMap::new(),
next_rounds: Vec::new(),
@@ -436,6 +471,8 @@ async fn get_game(
let g = game.lock().await;
if !g.is_started {
g.screen_lobby()
+ } else if g.is_finished {
+ g.screen_scoring()
} else if g.rounds.len() == 0 {
if g.submissions.contains_key(&uid) {
g.screen_submitted()
@@ -556,6 +593,26 @@ async fn mark_guess(
g.guess_li(guess_id).into_string().into_response()
}
+/// Judge is done judging all submissions
+async fn submit_judge(Path(gid): Path<u64>, State(st): State<Server>) -> Response {
+ let glock = {
+ if let Some(g) = st.lock().await.games.get(&gid) {
+ g.clone()
+ } else {
+ return (StatusCode::NOT_FOUND).into_response();
+ }
+ };
+ let mut g = glock.lock().await;
+
+ if g.next_rounds.is_empty() {
+ g.scoring();
+ } else {
+ g.new_round();
+ }
+
+ StatusCode::OK.into_response()
+}
+
async fn game_ws(
ws: WebSocketUpgrade,
Path(gid): Path<u64>,
@@ -677,6 +734,7 @@ async fn main() -> Result<()> {
.route("/game/{gid}/guess", post(guess_tune))
.route("/game/{gid}/submit", post(submit_game))
.route("/game/{gid}/mark/{uid}/{status}", post(mark_guess))
+ .route("/game/{gid}/judge", post(submit_judge))
.route("/game/{gid}/ws", get(game_ws))
.nest_service("/static", ServeDir::new("static"))
.layer(CatchPanicLayer::custom(handle_panic))
diff --git a/static/style.css b/static/style.css
index e61cc02..3b9ba9d 100644
--- a/static/style.css
+++ b/static/style.css
@@ -3,3 +3,16 @@
body {
}
+
+#guesslist {
+ list-style: none;
+ [data-accept="none"] {
+ background: #aaa;
+ }
+ [data-accept="true"] {
+ background: #00ff00;
+ }
+ [data-accept="false"] {
+ background: #ff0000;
+ }
+}