Skip to content

Commit

Permalink
Merge pull request #20 from gabeklavans/feature/live-score-update
Browse files Browse the repository at this point in the history
Feature/live score update
  • Loading branch information
gabeklavans authored Dec 26, 2023
2 parents 590c3ad + c354b2c commit 354f087
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 20 deletions.
44 changes: 29 additions & 15 deletions src/server/routes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FastifyInstance, FastifyReply } from "fastify";
import { Api, InlineKeyboard } from "grammy";
import { Api, GrammyError, InlineKeyboard } from "grammy";
import httpError from "http-errors";
import { bot } from "../bot";
import { GAME_START_BUTTON_TEXT, Game, TURN_MAX } from "../constants";
Expand Down Expand Up @@ -84,6 +84,7 @@ export default (fastify: FastifyInstance, opts: any, done: (err?: Error | undefi
body: {
type: "object",
properties: {
partial: { type: "boolean" }, // support for mid-turn updates
score: { type: "number" },
words: { type: "array", items: { type: "string" } },
},
Expand All @@ -109,27 +110,32 @@ export default (fastify: FastifyInstance, opts: any, done: (err?: Error | undefi
fastify.log.error(`User ${userId} did not join this game.`);
return reply.status(500).send();
}
if (gameSession.players[userId].score) {
fastify.log.error(`User ${userId} already submitted a score of ${gameSession.players[userId]}.`);

const player = gameSession.players[userId];

if (player.done) {
fastify.log.error(`User ${userId} already submitted a final score of ${player}.`);
return reply.status(500).send();
}
if (score < 0) {
fastify.log.error(`Score of ${score} is less than 0.`);
return reply.status(500).send();
}

gameSession.turnCount++;

handleNewScore(gameSession, userId, score).catch(console.error);
player.score = score;

gameSession.players[userId].score = score;
if (!body.partial) {
handleNewScore(gameSession, userId, score).catch(console.error);
player.done = true;
}

updateInlineKeyboard(gameSession);

// set game-specific values here
// perform game-specific actions here
// this includes turn-increment logic
switch (gameSession.game) {
case Game.WORD_HUNT:
gameSession.players[userId].words = body.words;
player.words = body.words;
break;
}

Expand All @@ -147,16 +153,24 @@ export default (fastify: FastifyInstance, opts: any, done: (err?: Error | undefi
function updateInlineKeyboard(gameSession: GameSession) {
const inlineKeyboard = new InlineKeyboard().game(GAME_START_BUTTON_TEXT).row();
Object.values(gameSession.players).forEach((player, idx) => {
inlineKeyboard.text(`${player.name}: ${player.score ?? "..."}`);
inlineKeyboard.text(`${player.name}: ${player.done ? player.score : "..."}`);
if (idx % 2 == 1) inlineKeyboard.row();
});

function handleEditErr(err: GrammyError) {
if (err.description.includes("exactly the same")) {
fastify.log.debug("inline button unchanged")
} else {
fastify.log.error(err);
}
}

if (gameSession.inlineId) {
bot.api.editMessageReplyMarkupInline(gameSession.inlineId, { reply_markup: inlineKeyboard });
bot.api.editMessageReplyMarkupInline(gameSession.inlineId, { reply_markup: inlineKeyboard })
.catch(handleEditErr);
} else if (gameSession.chatId && gameSession.messageId) {
bot.api.editMessageReplyMarkup(gameSession.chatId, parseInt(gameSession.messageId), {
reply_markup: inlineKeyboard,
});
bot.api.editMessageReplyMarkup(gameSession.chatId, parseInt(gameSession.messageId), { reply_markup: inlineKeyboard })
.catch(handleEditErr);
} else {
fastify.log.error(`updateInlineKeyboard: game session doesn't have an associated message`);
}
Expand All @@ -166,7 +180,7 @@ async function handleNewScore(gameSession: GameSession, scoringPlayerId: string,
const botApi = new Api(process.env.BOT_API_KEY!);

const oldScoredPlayers = Object.entries(gameSession.players)
.filter((scoredPlayer) => scoredPlayer[1].score != undefined)
.filter((scoredPlayer) => scoredPlayer[1].done)
.map((scoredPlayer) => {
return {
id: scoredPlayer[0],
Expand Down
1 change: 1 addition & 0 deletions src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export type GameSession = {
words?: string[];
name: string;
started: boolean;
done: boolean; // attempt to prevent post-game score changing
};
};
winnerIds: string[]; // state used for score-keeping
Expand Down
9 changes: 4 additions & 5 deletions src/server/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,29 +97,28 @@ export async function handleJoinSession(
// add player to session if possible
// NOTE: this probably isn't a race condition? Node is single-threaded right?
if (!session.players[userId] && Object.keys(session.players).length < PLAYER_MAX[session.game]) {
const session = gameSessions[sessionId];
session.players[userId] = {
words: [],
name: userName,
started: false,
done: false
};
}

// determine where to redirect the browser
if (session.players[userId] && !session.players[userId].started) {
switch (gameSessions[sessionId].game) {
switch (session.game) {
case Game.WORD_HUNT:
res.redirect(`${GAME_URL[Game.WORD_HUNT]}?session=${sessionId}&user=${userId}`);
break;
}
} else {
switch (gameSessions[sessionId].game) {
switch (session.game) {
case Game.WORD_HUNT:
res.redirect(`${GAME_URL[Game.WORD_HUNT]}?session=${sessionId}&user=${userId}&spectate=true`);
break;
}
// TODO: implement spectator mode
// Gabe, later: I'm not sure what I meant by this...
// TODO: implement spectator mode (doesn't matter for word hunt)
}
}

Expand Down
1 change: 1 addition & 0 deletions src/typings/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type ChatInfo = {
};

type ResultsBody = {
partial: boolean;
score: number;
words: string[];
};
Expand Down

0 comments on commit 354f087

Please sign in to comment.