73 lines
3.8 KiB
TypeScript
73 lines
3.8 KiB
TypeScript
import { expect, test } from 'bun:test';
|
|
import { applyAction, setupGame, usersOf } from '../help-kit.test-util';
|
|
import { GAMES } from '@bg/games';
|
|
import { helpNow } from './help';
|
|
|
|
const users = usersOf(['A', 'B']);
|
|
const view = (s: unknown, who: string | null) => GAMES.janggi!.view(s, who) as any;
|
|
const mv = (f1: number, r1: number, f2: number, r2: number) => ({ type: 'move', from: { f: f1, r: r1 }, to: { f: f2, r: r2 } });
|
|
|
|
/** A = 초, B = 한; both 상차림 chosen (한 first), 초 to move. */
|
|
function started(o: Record<string, unknown> = {}) {
|
|
const { state } = setupGame('janggi', 2, { sideAssignment: 'hostCho', setupOrder: 'hanFirst', ...o });
|
|
const s = applyAction('janggi', state, 'B', { type: 'chooseSetup', arrangement: 'MSSM' });
|
|
return applyAction('janggi', s, 'A', { type: 'chooseSetup', arrangement: 'SMMS' });
|
|
}
|
|
|
|
/** Custom position in play (kept consistent with the rule module: 장군 flag from the real board). */
|
|
function custom(pieces: [string, string, number, number][], turn: 'cho' | 'han', inCheck: 'cho' | 'han' | null) {
|
|
const s = started();
|
|
s.board = new Array(90).fill(null);
|
|
for (const [side, kind, f, r] of pieces) s.board[r * 9 + f] = { side, kind };
|
|
s.startBoard = s.board.slice();
|
|
s.turn = turn;
|
|
s.inCheck = inCheck;
|
|
s.positionCounts = {};
|
|
return s;
|
|
}
|
|
|
|
test('장기: 상차림 단계 (한 먼저 고르기)', () => {
|
|
const { state } = setupGame('janggi', 2, { sideAssignment: 'hostCho', setupOrder: 'hanFirst' });
|
|
expect(helpNow(view(state, 'B'), 'B', users)).toContain('상차림을 골라 주세요(나는 한)');
|
|
const cho = helpNow(view(state, 'A'), 'A', users);
|
|
expect(cho).toContain('한이 먼저 상차림을 골라요');
|
|
expect(cho).toContain('고양이님이 상차림을 고르는 중');
|
|
expect(helpNow(view(state, null), null, users)).toContain('고양이님이 상차림');
|
|
const s = applyAction('janggi', state, 'B', { type: 'chooseSetup', arrangement: 'MSSM' });
|
|
expect(helpNow(view(s, 'A'), 'A', users)).toContain('한이 안상차림을 골랐어요');
|
|
});
|
|
|
|
test('장기: 내 차례 / 상대 차례 / 관전 (점수 포함)', () => {
|
|
const s = started();
|
|
const mine = helpNow(view(s, 'A'), 'A', users);
|
|
expect(mine).toContain('내 차례예요(초)');
|
|
expect(mine).toContain('초록 점');
|
|
expect(mine).toContain('[⏸ 한수쉼]');
|
|
expect(mine).toContain('초 72점, 한 73.5점');
|
|
expect(helpNow(view(s, 'B'), 'B', users)).toContain('나는 한이에요');
|
|
expect(helpNow(view(s, null), null, users)).toContain('호랑이님(초) 차례예요');
|
|
});
|
|
|
|
test('장기: 장군을 받으면 한수쉼 없이 궁을 지키라고 안내', () => {
|
|
const s = custom([['cho', 'king', 3, 0], ['han', 'king', 4, 9], ['cho', 'cha', 0, 9]], 'han', 'han');
|
|
const t = helpNow(view(s, 'B'), 'B', users);
|
|
expect(t).toContain('장군이에요!');
|
|
expect(t).not.toContain('[⏸ 한수쉼]');
|
|
expect(helpNow(view(s, 'A'), 'A', users)).toContain('내가 장군을 불렀어요');
|
|
expect(helpNow(view(s, null), null, users)).toContain('한 궁이 장군을 받았어요');
|
|
});
|
|
|
|
test('장기: 빅장을 받은 쪽 안내 (점수제/비점수제)', () => {
|
|
for (const scoring of [true, false]) {
|
|
const s0 = started({ bikjang: 'kja30', scoring });
|
|
const s = custom([['cho', 'king', 4, 1], ['cho', 'jol', 4, 4], ['cho', 'cha', 0, 0], ['han', 'king', 4, 8], ['han', 'jol', 0, 6], ['han', 'cha', 8, 5], ['han', 'sa', 3, 9]], 'cho', null);
|
|
s.options = s0.options;
|
|
const after = applyAction('janggi', s, 'A', mv(4, 4, 3, 4));
|
|
expect(after.bikjang?.calledBy).toBe('cho');
|
|
const t = helpNow(view(after, 'B'), 'B', users);
|
|
expect(t).toContain('빅장이에요!');
|
|
expect(t).toContain(scoring ? '점수로 승부를 가려요' : '무승부로 끝나요');
|
|
expect(helpNow(view(after, null), null, users)).toContain('초가 빅장을 불렀어요');
|
|
}
|
|
});
|