添加赛马实时进度播报

将比赛循环从race_engine移到commands中,每回合发送进度条:
  马匹名  |████████░░░░░░| 45.2m
race_engine改为提供tick/determine_champion/format_progress方法

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 01:32:42 +08:00
parent 1dd247ab4b
commit adccbfebb5
2 changed files with 64 additions and 50 deletions

View File

@@ -11,37 +11,23 @@ class RaceEngine:
self.config = config
self.active_tasks: dict[str, asyncio.Task] = {}
async def start_race(self, room: Room) -> asyncio.Task:
"""Start race progression loop."""
task = asyncio.create_task(self._race_loop(room))
self.active_tasks[room.scope] = task
return task
def tick(self, room: Room):
"""Advance race by one tick. Returns list of finished horses."""
room.tick_count += 1
async def _race_loop(self, room: Room):
"""Main race progression loop."""
room.state = RoomState.RUNNING
for horse in room.horses.values():
if horse.state == HorseState.RACING:
distance = max(0, random.gauss(10, 3))
horse.position += distance
while room.state == RoomState.RUNNING:
await asyncio.sleep(self.config.RACE_TICK_INTERVAL)
room.tick_count += 1
finished_horses = [
h for h in room.horses.values()
if h.position >= self.config.RACE_DISTANCE
]
for horse in room.horses.values():
if horse.state == HorseState.RACING:
distance = max(0, random.gauss(10, 3))
horse.position += distance
return finished_horses
finished_horses = [
h for h in room.horses.values()
if h.position >= self.config.RACE_DISTANCE
]
if finished_horses:
champion = self._determine_champion(finished_horses)
room.champion_name = champion.name
room.state = RoomState.FINISHED
break
def _determine_champion(self, horses: list[Horse]) -> Horse:
def determine_champion(self, horses: list[Horse]) -> Horse:
"""Determine champion from tied horses."""
if len(horses) == 1:
return horses[0]
@@ -53,6 +39,10 @@ class RaceEngine:
return horses[0]
def register_task(self, scope: str, task: asyncio.Task):
"""Register an active race task."""
self.active_tasks[scope] = task
def stop_race(self, scope: str):
"""Stop race and cancel task."""
if scope in self.active_tasks:
@@ -60,3 +50,19 @@ class RaceEngine:
if not task.done():
task.cancel()
del self.active_tasks[scope]
def format_progress(self, room: Room) -> str:
"""Format race progress as visual bar for each horse."""
distance = self.config.RACE_DISTANCE
bar_width = 20
lines = [f"【第{room.tick_count}回合】"]
# Sort by position descending for readability
sorted_horses = sorted(room.horses.values(), key=lambda h: h.position, reverse=True)
for horse in sorted_horses:
progress = min(horse.position / distance, 1.0)
filled = int(progress * bar_width)
bar = "" * filled + "" * (bar_width - filled)
lines.append(f" {horse.name:<6} |{bar}| {horse.position:.1f}m")
return "\n".join(lines)