Ledgers close with an over line, so the digest can say who won
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141G6xqLeNRYEtviLWSB5Up
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
107e1893bc
commit
79947e31ba
+8
-3
@@ -81,19 +81,23 @@ for f in glob.glob("/var/lib/waving-hands/rooms/*.jsonl"):
|
|||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
created = datetime.datetime.fromtimestamp(meta["createdAt"] / 1000, datetime.timezone.utc)
|
created = datetime.datetime.fromtimestamp(meta["createdAt"] / 1000, datetime.timezone.utc)
|
||||||
humans, bots_seated, started, turns, last = [], [], False, 0, created
|
humans, bots_seated, started, turns, last, over = [], [], False, 0, created, None
|
||||||
|
names = {}
|
||||||
for x in lines[1:]:
|
for x in lines[1:]:
|
||||||
if x["t"] == "seat":
|
if x["t"] == "seat":
|
||||||
(bots_seated if x["bot"] else humans).append(x["name"])
|
(bots_seated if x["bot"] else humans).append(x["name"])
|
||||||
|
names[x["id"]] = x["name"]
|
||||||
elif x["t"] == "start":
|
elif x["t"] == "start":
|
||||||
started = True
|
started = True
|
||||||
elif x["t"] == "turn":
|
elif x["t"] == "turn":
|
||||||
turns += 1
|
turns += 1
|
||||||
last = datetime.datetime.fromtimestamp(x["at"] / 1000, datetime.timezone.utc)
|
last = datetime.datetime.fromtimestamp(x["at"] / 1000, datetime.timezone.utc)
|
||||||
|
elif x["t"] == "over":
|
||||||
|
over = "a draw" if x["winner"] is None else "%s won" % names.get(x["winner"], x["winner"])
|
||||||
for h in humans:
|
for h in humans:
|
||||||
if h not in first_seen or created < first_seen[h]:
|
if h not in first_seen or created < first_seen[h]:
|
||||||
first_seen[h] = created
|
first_seen[h] = created
|
||||||
rooms.append(dict(id=meta["id"], size=meta["seats"], created=created, humans=humans, bots=bots_seated, started=started, turns=turns, last=last))
|
rooms.append(dict(id=meta["id"], size=meta["seats"], created=created, humans=humans, bots=bots_seated, started=started, turns=turns, last=last, over=over))
|
||||||
|
|
||||||
today = sorted([r for r in rooms if r["created"].strftime("%F") == day], key=lambda r: r["created"])
|
today = sorted([r for r in rooms if r["created"].strftime("%F") == day], key=lambda r: r["created"])
|
||||||
names = sorted({h for r in today for h in r["humans"]})
|
names = sorted({h for r in today for h in r["humans"]})
|
||||||
@@ -101,7 +105,8 @@ new = [n for n in names if first_seen[n].strftime("%F") == day]
|
|||||||
print("players today: %s | NEW today: %s" % (", ".join(names) or "none", ", ".join(new) or "none"))
|
print("players today: %s | NEW today: %s" % (", ".join(names) or "none", ", ".join(new) or "none"))
|
||||||
print("rooms today: %d (of %d ever)" % (len(today), len(rooms)))
|
print("rooms today: %d (of %d ever)" % (len(today), len(rooms)))
|
||||||
for r in today:
|
for r in today:
|
||||||
state = "lobby only" if not r["started"] else ("started, no turns" if not r["turns"] else "in play")
|
idle_h = (now - r["last"]).total_seconds() / 3600
|
||||||
|
state = "lobby only" if not r["started"] else ("started, no turns" if not r["turns"] else (r["over"] or ("abandoned" if idle_h > 12 else "in play")))
|
||||||
span = ("%d min" % round((r["last"] - r["created"]).total_seconds() / 60)) if r["turns"] else ""
|
span = ("%d min" % round((r["last"] - r["created"]).total_seconds() / 60)) if r["turns"] else ""
|
||||||
seated = "+".join(r["humans"]) + ((" vs %d bot%s" % (len(r["bots"]), "" if len(r["bots"]) == 1 else "s")) if r["bots"] else "")
|
seated = "+".join(r["humans"]) + ((" vs %d bot%s" % (len(r["bots"]), "" if len(r["bots"]) == 1 else "s")) if r["bots"] else "")
|
||||||
empty = r["size"] - len(r["humans"]) - len(r["bots"])
|
empty = r["size"] - len(r["humans"]) - len(r["bots"])
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ export class Rooms {
|
|||||||
const actor = room.state.timeStops[0];
|
const actor = room.state.timeStops[0];
|
||||||
this.commit(room, { t: 'turn', at: Date.now(), inputs: { [actor]: chooseBotTurn(room.state, actor) } });
|
this.commit(room, { t: 'turn', at: Date.now(), inputs: { [actor]: chooseBotTurn(room.state, actor) } });
|
||||||
}
|
}
|
||||||
|
if (room.state?.over) this.commit(room, { t: 'over', at: Date.now(), winner: room.state.over.winner, reason: room.state.over.reason });
|
||||||
}
|
}
|
||||||
|
|
||||||
view(room: Room, seatId: WizardId): RoomView {
|
view(room: Room, seatId: WizardId): RoomView {
|
||||||
@@ -228,6 +229,8 @@ function apply(room: Room, line: LedgerLine): void {
|
|||||||
room.state = resolveTurn(room.state, line.inputs);
|
room.state = resolveTurn(room.state, line.inputs);
|
||||||
room.pending = {};
|
room.pending = {};
|
||||||
break;
|
break;
|
||||||
|
case 'over':
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -10,7 +10,9 @@ export type LedgerLine =
|
|||||||
| { t: 'room'; id: string; seats: number; createdAt: number }
|
| { t: 'room'; id: string; seats: number; createdAt: number }
|
||||||
| { t: 'seat'; id: WizardId; name: string; token: string; bot: boolean }
|
| { t: 'seat'; id: WizardId; name: string; token: string; bot: boolean }
|
||||||
| { t: 'start'; seed: number }
|
| { t: 'start'; seed: number }
|
||||||
| { t: 'turn'; at: number; inputs: Record<WizardId, TurnInput> };
|
| { t: 'turn'; at: number; inputs: Record<WizardId, TurnInput> }
|
||||||
|
/** Written after the turn that ends the duel, for anything that reads ledgers without the engine. */
|
||||||
|
| { t: 'over'; at: number; winner: WizardId | null; reason: string };
|
||||||
|
|
||||||
export class Store {
|
export class Store {
|
||||||
constructor(private dir: string) {
|
constructor(private dir: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user