vibe coding is the best

This commit is contained in:
KeshavAnandCode
2026-03-20 18:22:15 -05:00
parent 1075b59d2d
commit 8854e13671
6 changed files with 1988 additions and 1960 deletions

View File

@@ -2,7 +2,7 @@ import type { ServerWebSocket } from "bun";
import {
rooms, wsToPlayer,
Room, Player,
genId, sanitize, freshBuzzer, publicRoom, broadcast, toMod,
genId, greekName, sanitize, freshBuzzer, publicRoom, broadcast, toMod,
} from "./rooms";
type WS = ServerWebSocket<unknown>;
@@ -18,11 +18,10 @@ export function handleMessage(ws: WS, raw: string) {
/* ── CREATE ROOM ── */
if (type === "create_room") {
const s = msg.settings ?? {};
const numTeams = Math.min(8, Math.max(2, (s.numTeams ?? 2) | 0));
const defaultNames = ["ALPHA","BETA","GAMMA","DELTA","EPSILON","ZETA","ETA","THETA"];
const numTeams = Math.max(2, Math.min(64, (s.numTeams ?? 2) | 0));
const teamNames: string[] = [];
for (let i = 0; i < numTeams; i++)
teamNames.push(sanitize(s.teamNames?.[i] ?? defaultNames[i], 32));
teamNames.push(s.teamNames?.[i] ? sanitize(s.teamNames[i], 32) : greekName(i));
const room: Room = {
id: genId(6),
@@ -35,7 +34,7 @@ export function handleMessage(ws: WS, raw: string) {
playerPickTeam: s.playerPickTeam === true,
showBuzzOrder: s.showBuzzOrder !== false,
buzzerLockout: s.buzzerLockout !== false,
timerSeconds: Math.min(300, Math.max(0, (s.timerSeconds ?? 0) | 0)),
timerSeconds: Math.min(600, Math.max(0, (s.timerSeconds ?? 0) | 0)),
},
players: new Map(),
buzzerState: freshBuzzer(),
@@ -84,7 +83,7 @@ export function handleMessage(ws: WS, raw: string) {
return;
}
/* ── PICK TEAM (player) ── */
/* ── PICK TEAM ── */
if (type === "pick_team") {
const ctx = wsToPlayer.get(ws);
if (!ctx) return;
@@ -109,15 +108,9 @@ export function handleMessage(ws: WS, raw: string) {
if (!room) return;
const bz = room.buzzerState;
if (!bz.roundOpen) {
tx(ws, { type: "buzz_rejected", reason: "Round not open" }); return;
}
if (bz.buzzOrder.includes(ctx.playerId)) {
tx(ws, { type: "buzz_rejected", reason: "Already buzzed" }); return;
}
if (room.settings.buzzerLockout && bz.buzzOrder.length > 0) {
tx(ws, { type: "buzz_rejected", reason: "Locked out" }); return;
}
if (!bz.roundOpen) { tx(ws, { type: "buzz_rejected", reason: "Round not open" }); return; }
if (bz.buzzOrder.includes(ctx.playerId)) { tx(ws, { type: "buzz_rejected", reason: "Already buzzed" }); return; }
if (room.settings.buzzerLockout && bz.buzzOrder.length > 0) { tx(ws, { type: "buzz_rejected", reason: "Locked out" }); return; }
bz.buzzOrder.push(ctx.playerId);
bz.buzzTimes.set(ctx.playerId, Date.now());
@@ -125,23 +118,8 @@ export function handleMessage(ws: WS, raw: string) {
const p = room.players.get(ctx.playerId)!;
const pubOrder = room.settings.showBuzzOrder ? bz.buzzOrder : [bz.buzzOrder[0]];
broadcast(room, {
type: "buzz_event",
playerId: ctx.playerId,
playerName: p.name,
teamIndex: p.teamIndex,
buzzOrder: pubOrder,
room: publicRoom(room),
});
toMod(room, {
type: "buzz_event",
playerId: ctx.playerId,
playerName: p.name,
teamIndex: p.teamIndex,
buzzOrder: bz.buzzOrder,
buzzTimes: Object.fromEntries(bz.buzzTimes),
room: publicRoom(room),
});
broadcast(room, { type: "buzz_event", playerId: ctx.playerId, playerName: p.name, teamIndex: p.teamIndex, buzzOrder: pubOrder, room: publicRoom(room) });
toMod(room, { type: "buzz_event", playerId: ctx.playerId, playerName: p.name, teamIndex: p.teamIndex, buzzOrder: bz.buzzOrder, buzzTimes: Object.fromEntries(bz.buzzTimes), room: publicRoom(room) });
return;
}
@@ -155,71 +133,53 @@ export function handleMessage(ws: WS, raw: string) {
room.buzzerState.roundOpen = true;
broadcast(room, { type: "round_open", room: publicRoom(room) });
break;
case "close_round":
room.buzzerState.roundOpen = false;
broadcast(room, { type: "round_closed", room: publicRoom(room) });
break;
case "reset_buzzer":
room.buzzerState = freshBuzzer();
broadcast(room, { type: "buzzer_reset", room: publicRoom(room) });
break;
case "update_settings": {
const s = msg.settings ?? {};
const st = room.settings;
if (s.mode === "individual" || s.mode === "teams") st.mode = s.mode;
if (typeof s.numTeams === "number") st.numTeams = Math.min(8, Math.max(2, s.numTeams | 0));
if (Array.isArray(s.teamNames)) st.teamNames = s.teamNames.slice(0, 8).map((n: unknown) => sanitize(n, 32));
if (typeof s.numTeams === "number") {
const newN = Math.max(2, Math.min(64, s.numTeams | 0));
// grow team names with greek names if needed
while (st.teamNames.length < newN) st.teamNames.push(greekName(st.teamNames.length));
st.numTeams = newN;
}
if (Array.isArray(s.teamNames)) st.teamNames = s.teamNames.slice(0, st.numTeams).map((n: unknown) => sanitize(n, 32));
if (typeof s.playerPickTeam === "boolean") st.playerPickTeam = s.playerPickTeam;
if (typeof s.showBuzzOrder === "boolean") st.showBuzzOrder = s.showBuzzOrder;
if (typeof s.buzzerLockout === "boolean") st.buzzerLockout = s.buzzerLockout;
if (typeof s.timerSeconds === "number") st.timerSeconds = Math.min(300, Math.max(0, s.timerSeconds | 0));
if (typeof s.timerSeconds === "number") st.timerSeconds = Math.min(600, Math.max(0, s.timerSeconds | 0));
broadcast(room, { type: "room_update", room: publicRoom(room) });
tx(ws, { type: "settings_updated", room: publicRoom(room) });
break;
}
case "assign_team": {
const p = room.players.get(sanitize(msg.playerId, 12));
if (p) {
p.teamIndex = typeof msg.teamIndex === "number"
? Math.max(0, Math.min(7, msg.teamIndex | 0))
: null;
p.teamIndex = typeof msg.teamIndex === "number" ? Math.max(0, Math.min(room.settings.numTeams - 1, msg.teamIndex | 0)) : null;
broadcast(room, { type: "room_update", room: publicRoom(room) });
}
break;
}
case "kick_player": {
const p = room.players.get(sanitize(msg.playerId, 12));
if (p) {
if (p.ws) {
try { p.ws.send(JSON.stringify({ type: "kicked" })); } catch {}
wsToPlayer.delete(p.ws);
}
if (p.ws) { try { p.ws.send(JSON.stringify({ type: "kicked" })); } catch {} wsToPlayer.delete(p.ws); }
room.players.delete(p.id);
broadcast(room, { type: "room_update", room: publicRoom(room) });
}
break;
}
case "lock_room":
room.locked = msg.locked === true;
broadcast(room, { type: "room_update", room: publicRoom(room) });
break;
case "lock_teams":
room.teamLocked = msg.locked === true;
broadcast(room, { type: "room_update", room: publicRoom(room) });
break;
case "reset_teams":
for (const p of room.players.values()) p.teamIndex = null;
broadcast(room, { type: "room_update", room: publicRoom(room) });
break;
case "lock_room": room.locked = msg.locked === true; broadcast(room, { type: "room_update", room: publicRoom(room) }); break;
case "lock_teams": room.teamLocked = msg.locked === true; broadcast(room, { type: "room_update", room: publicRoom(room) }); break;
case "reset_teams": for (const p of room.players.values()) p.teamIndex = null; broadcast(room, { type: "room_update", room: publicRoom(room) }); break;
case "end_room":
broadcast(room, { type: "room_ended" });
for (const p of room.players.values()) if (p.ws) wsToPlayer.delete(p.ws);
@@ -230,7 +190,6 @@ export function handleMessage(ws: WS, raw: string) {
}
export function handleClose(ws: WS) {
// mod disconnect
for (const room of rooms.values()) {
if (room.modWs === ws) {
room.modWs = null;
@@ -238,7 +197,6 @@ export function handleClose(ws: WS) {
return;
}
}
// player disconnect
const ctx = wsToPlayer.get(ws);
if (ctx) {
wsToPlayer.delete(ws);