위협 가이드 제거: 오목 위험 자리, 체스·장기 위험 기물 경고, 바둑 단수 경고
- 오목: 상대 3·4를 막으라는 빨간 동그라미·노란 점선(hints 옵션, view.hints, threatHints) 삭제 - 체스·장기: hints 'movesAndThreats'(주황 점선 위험 기물) 삭제 → 'off' / 'moves'만 남김 - 바둑: atariWarning 옵션과 atariWarnings(깜빡이는 단수 돌) 삭제 - 도움말 문구·설정 화면·docs 정리, 테스트는 "어떤 view에도 위협 표시 없음"으로 바꿈 - 갈 수 있는 칸 점, 금수 ×, 둘 수 없는 점 같은 규칙 표시는 그대로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,10 +3,8 @@ import { z } from 'zod';
|
||||
import { fail, ok, type GameDefinition, type GameEvent, type GameResult, type PlayerId, type Rng } from '@bg/engine';
|
||||
import {
|
||||
Board,
|
||||
candidateCells,
|
||||
forbiddenCells,
|
||||
forbiddenKind,
|
||||
straightFourCount,
|
||||
winningLine,
|
||||
type Cell,
|
||||
type RuleConfig,
|
||||
@@ -64,10 +62,6 @@ export const omokOptionsSchema = z.object({
|
||||
drawOffer: z.boolean().default(true).meta({ title: '무승부 제안 허용' }),
|
||||
drawReofferMoves: z.number().int().min(0).max(50).default(3).meta({ title: '무승부 다시 제안까지 둬야 하는 수' }),
|
||||
showForbidden: z.boolean().default(true).meta({ title: '금수 자리 표시' }),
|
||||
hints: z
|
||||
.enum(['off', 'warn'])
|
||||
.default('warn')
|
||||
.meta({ title: '위험한 자리 알려 주기', labels: { off: '끄기', warn: '켜기' } }),
|
||||
});
|
||||
export type OmokOptions = z.infer<typeof omokOptionsSchema>;
|
||||
|
||||
@@ -126,7 +120,6 @@ export interface OmokView {
|
||||
undo: { allowed: boolean; remaining: Record<Color, number | null>; pending: { by: Color; plies: number } | null };
|
||||
draw: { allowed: boolean; pendingBy: Color | null };
|
||||
forbidden: Pt[];
|
||||
hints: { urgent: Pt[]; warn: Pt[] } | null;
|
||||
result: OmokState['result'];
|
||||
}
|
||||
|
||||
@@ -253,22 +246,6 @@ function chooseAutoMove(s: OmokState, rng: Rng): Pt {
|
||||
return pick(near.length ? near : legal);
|
||||
}
|
||||
|
||||
function threatHints(s: OmokState): { urgent: Pt[]; warn: Pt[] } {
|
||||
const b = boardOf(s);
|
||||
const opp = STONE[other(s.turn)];
|
||||
const r = rule(s.options);
|
||||
const urgent: Pt[] = [];
|
||||
const warn: Pt[] = [];
|
||||
for (const i of candidateCells(b, opp, 2)) {
|
||||
const { x, y } = toPt(i, s.size);
|
||||
b.set(x, y, opp);
|
||||
if (winningLine(b, x, y, opp, r)) urgent.push({ x, y });
|
||||
else if (straightFourCount(b, x, y, opp, r) > 0) warn.push({ x, y });
|
||||
b.set(x, y, 0);
|
||||
}
|
||||
return { urgent, warn };
|
||||
}
|
||||
|
||||
function pendingResponder(s: OmokState): Color | null {
|
||||
if (s.undo.pending) return other(s.undo.pending.by);
|
||||
if (s.draw.pendingBy) return other(s.draw.pendingBy);
|
||||
@@ -460,7 +437,6 @@ export const omok: GameDefinition<OmokState, OmokAction, OmokView, OmokOptions>
|
||||
const myColor = viewer ? colorOf(s, viewer) : null;
|
||||
const limit = undoLimit(s.options);
|
||||
const showForbidden = s.options.showForbidden && s.phase === 'playing' && (myColor === null || myColor === s.turn);
|
||||
const showHints = s.options.hints === 'warn' && s.phase === 'playing' && myColor !== null && myColor === s.turn;
|
||||
return {
|
||||
size: s.size,
|
||||
board: s.board,
|
||||
@@ -487,7 +463,6 @@ export const omok: GameDefinition<OmokState, OmokAction, OmokView, OmokOptions>
|
||||
},
|
||||
draw: { allowed: s.options.drawOffer, pendingBy: s.draw.pendingBy },
|
||||
forbidden: showForbidden ? s.forbidden.map((i) => toPt(i, s.size)) : [],
|
||||
hints: showHints ? threatHints(s) : null,
|
||||
result: s.result,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -259,11 +259,9 @@ describe('time', () => {
|
||||
});
|
||||
|
||||
describe('views and playouts', () => {
|
||||
test('hints are only for the player to move', () => {
|
||||
const s = make({}, { black: ['F8', 'G8', 'H8'], white: ['A1', 'A3'] }, 'white');
|
||||
expect(omok.view(s, 'B').hints?.warn.length).toBeGreaterThan(0);
|
||||
expect(omok.view(s, 'A').hints).toBeNull();
|
||||
expect(omok.view(s, null).hints).toBeNull();
|
||||
test('no threat guide (where to block) in any view', () => {
|
||||
const s = make({}, { black: ['F8', 'G8', 'H8', 'I8'], white: ['A1', 'A3', 'A5'] }, 'white');
|
||||
for (const viewer of ['A', 'B', null]) expect(omok.view(s, viewer)).not.toHaveProperty('hints');
|
||||
});
|
||||
|
||||
test('random playouts finish, are deterministic and fast', () => {
|
||||
|
||||
Reference in New Issue
Block a user