diff --git a/src/kbo/schedule.ts b/src/kbo/schedule.ts index 7d0a780..9bf4bac 100644 --- a/src/kbo/schedule.ts +++ b/src/kbo/schedule.ts @@ -131,12 +131,14 @@ function parsePlayCell(html: string): { const homeTeamCode = toTeamCode(teamMatch[3]); const emContent = teamMatch[2]; - // Check for scores inside - const scoreRegex = /(\d+)<\/span>/g; - const scores: { cls: string; val: number }[] = []; + // Check for scores inside . 무승부 시 KBO는 `class="draw"`(또는 win/lose가 아닌 다른 값)을 + // 쓰므로 win/lose만 매칭하면 점수가 0건으로 잡혀 scheduled로 분류된다. 클래스 값과 무관하게 + // span 안의 숫자만 추출한다. + const scoreRegex = /(\d+)<\/span>/g; + const scores: number[] = []; let sm: RegExpExecArray | null; while ((sm = scoreRegex.exec(emContent)) !== null) { - scores.push({ cls: sm[1], val: parseInt(sm[2], 10) }); + scores.push(parseInt(sm[1], 10)); } if (scores.length === 2) { @@ -144,8 +146,8 @@ function parsePlayCell(html: string): { return { awayTeamCode, homeTeamCode, - awayScore: scores[0].val, - homeScore: scores[1].val, + awayScore: scores[0], + homeScore: scores[1], status: "completed", }; } diff --git a/src/scheduled/dailyArchive.ts b/src/scheduled/dailyArchive.ts index c98bfef..996a1b9 100644 --- a/src/scheduled/dailyArchive.ts +++ b/src/scheduled/dailyArchive.ts @@ -50,12 +50,15 @@ async function reconcileDayVotes( } // 트리거가 실패/유실되었거나 배포 전 상태 전이가 일어난 경우의 자가치유 경로. - if (game.status === "completed" && game.winningTeamCode) { + // `winningTeamCode`가 없으면 무승부 — `processGameEndWithGame`이 양 팀 투표 모두 + // result=true로 처리한다. + if (game.status === "completed") { try { await processGameEndWithGame(gameId, game); + const isDraw = !game.winningTeamCode; result[gameId] = { team: vote.team, - result: vote.team === game.winningTeamCode, + result: isDraw ? true : vote.team === game.winningTeamCode, }; logger.info(`reconcile: judged ${gameId} on the fly (uid=${uid})`); } catch (err) { diff --git a/src/services/gameResultService.ts b/src/services/gameResultService.ts index 5c7dc64..37cdf3a 100644 --- a/src/services/gameResultService.ts +++ b/src/services/gameResultService.ts @@ -18,17 +18,18 @@ export async function processGameEndWithGame( gameId: string, game: Game ): Promise<{ processed: number }> { - if (!game.winningTeamCode) throw new HttpError(400, "winningTeamCode not set"); if (game.status !== "completed") throw new HttpError(409, `game status must be completed, got ${game.status}`); const date = fromTimestamp(game.time); const votes = await getAllUserVotes(gameId); const uids = Object.keys(votes); + // 무승부(`winningTeamCode` 없음): 양 팀 투표 모두 적중(`result: true`)으로 처리. + const isDraw = !game.winningTeamCode; const rtdbUpdates: Record = {}; for (const uid of uids) { const voted = votes[uid].team; - const result = voted === game.winningTeamCode; + const result = isDraw ? true : voted === game.winningTeamCode; rtdbUpdates[`/userVotes/${uid}/${date}/${gameId}/team`] = voted; rtdbUpdates[`/userVotes/${uid}/${date}/${gameId}/result`] = result; }