A seat's view carries its own move in waiting and its move in the last round it played
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
927e49cf79
commit
8e35d3a3a6
@@ -63,4 +63,17 @@ describe('rooms', () => {
|
||||
rooms.submit(room, bo, { pick: 1, final: true }, 1);
|
||||
expect(() => rooms.submit(room, bo, { pick: 2 }, 1)).toThrow(/not your move/);
|
||||
});
|
||||
|
||||
it("shows a seat its own move in waiting and its last move played, and nobody else's", () => {
|
||||
const { rooms, room, ann, bo } = table();
|
||||
rooms.submit(room, ann, { pick: 5 }, 0);
|
||||
expect(rooms.view(room, 'A').yourInput).toEqual({ pick: 5 });
|
||||
expect(rooms.view(room, 'B').yourInput).toBeNull();
|
||||
expect(rooms.view(room, '').yourInput).toBeNull();
|
||||
rooms.submit(room, bo, { pick: 2 }, 0);
|
||||
expect(rooms.view(room, 'A').yourInput).toBeNull();
|
||||
expect(rooms.view(room, 'A').yourLastInput).toEqual({ pick: 5 });
|
||||
expect(rooms.view(room, 'B').yourLastInput).toEqual({ pick: 2 });
|
||||
expect(rooms.view(room, '').yourLastInput).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -48,6 +48,8 @@ export interface Room<State> {
|
||||
state: State | null;
|
||||
/** Inputs received for the round in progress, by seat. */
|
||||
pending: Record<SeatId, unknown>;
|
||||
/** Each seat's input in the last round it played, kept through rounds it had no part in; each seat is shown only its own. */
|
||||
played: Record<SeatId, unknown>;
|
||||
chat: ChatLine[];
|
||||
/** Rounds played so far; a move names the count it was made against. */
|
||||
resolved: number;
|
||||
@@ -192,7 +194,7 @@ export class Rooms<State, Input> {
|
||||
|
||||
/** A table with nobody seated yet. */
|
||||
private blank(id: string, size: number, createdAt: number, rematchOf: string | null, expected: string[], options: TableOptions, seq = 0): Room<State> {
|
||||
return { id, size, createdAt, seats: [], galleryTalk: false, challenge: null, expected, rematch: null, rematchOf, options, over: false, state: null, pending: {}, chat: [], resolved: 0, seq, updatedAt: createdAt };
|
||||
return { id, size, createdAt, seats: [], galleryTalk: false, challenge: null, expected, rematch: null, rematchOf, options, over: false, state: null, pending: {}, played: {}, chat: [], resolved: 0, seq, updatedAt: createdAt };
|
||||
}
|
||||
|
||||
/** Open a table with its first seat taken; a rematch names the table it follows and holds seats for its players. */
|
||||
@@ -418,6 +420,7 @@ export class Rooms<State, Input> {
|
||||
|
||||
/** The view for a seat, or for the gallery when the seat is SPECTATOR. */
|
||||
view(room: Room<State>, seatId: SeatId): RoomView<State> {
|
||||
const seated = seatId !== SPECTATOR;
|
||||
return {
|
||||
roomId: room.id,
|
||||
seq: room.seq,
|
||||
@@ -430,6 +433,8 @@ export class Rooms<State, Input> {
|
||||
resolved: room.resolved,
|
||||
over: room.state ? this.game.over(room.state) : null,
|
||||
state: room.state ? this.game.view(room.state, seatId) : null,
|
||||
yourInput: seated && seatId in room.pending ? room.pending[seatId] : null,
|
||||
yourLastInput: seated && seatId in room.played ? room.played[seatId] : null,
|
||||
chat: room.chat,
|
||||
audience: this.gallery.get(room.id) ?? 0,
|
||||
galleryTalk: room.galleryTalk,
|
||||
@@ -512,6 +517,7 @@ export class Rooms<State, Input> {
|
||||
case 'turn':
|
||||
if (!room.state) return;
|
||||
room.state = this.game.resolve(room.state, line.inputs as Record<SeatId, Input>);
|
||||
room.played = { ...room.played, ...(line.inputs as Record<SeatId, unknown>) };
|
||||
room.pending = {};
|
||||
room.resolved += 1;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user