렌주 규칙

오목의 국제 규격으로 쓰는 렌주(連珠) 규칙은 먼저 두는 흑이 유리하다고 보고 흑에게만 금수를 둡니다. 흑은 삼삼, 사사, 장목(6목 이상)을 둘 수 없고, 백은 아무 제한이 없습니다. 장목도 백에게는 승리입니다.

처음 엔진을 렌주 규칙으로 만들었더니 백이 거의 무적이 되었습니다. 흑은 공격할 수 있는 모양이 금수로 막히고, 백은 같은 모양으로 마음껏 이길 수 있기 때문입니다.

흑과 백에 같은 금수

그래서 흑과 백의 차이가 없게 규칙을 고쳤습니다.

  • 삼삼: 흑·백 모두 금수. 떨어진 삼(●_●●, ●●_●)도 삼으로 셉니다.
  • 장목: 흑·백 모두 금수이고, 6목 이상은 승리로 치지 않습니다. 정확히 5목만 이깁니다.
  • 사사: 흑·백 모두 허용합니다.
  • 다섯을 만드는 수는 금수 검사보다 먼저 봅니다. 이기는 수는 언제나 둘 수 있습니다.
금수 모양. 삼삼(붙은 삼+붙은 삼), 삼삼(떨어진 삼+붙은 삼), 장목은 흑·백 모두 금수, 사사는 허용
금수 모양. 삼삼(붙은 삼+붙은 삼), 삼삼(떨어진 삼+붙은 삼), 장목은 흑·백 모두 금수, 사사는 허용

바꾼 뒤에도 백이 이겼다

규칙을 바꾼 때는 기록에 남아 있지 않아, 엔진 파일이 마지막으로 바뀐 자동 대국 다섯째 날을 기준으로 나눠 봤습니다. 그 전 445판에서는 백이 419판(94%)을, 그 뒤 42판에서는 38판(90%)을 이겼습니다.

학습 대국에서는 백이 늘 VLM, 흑이 늘 로컬 AI였습니다. 그래서 백이 이긴 것이 규칙 때문인지, 흑을 맡은 로컬 AI가 약해서인지는 이 기록만으로 가를 수 없습니다. 같은 AI가 흑과 백을 번갈아 쥐는 대국을 다시 둬 봐야 합니다.

이 단계의 실제 코드

웹 엔진의 금수 검사입니다. 이기는 수인지 먼저 보고, 장목과 삼삼만 막습니다.

omook-web/lib/board.tstypescript · 16줄
export function hasKyungsuBan(
  board: Stone[],
  row: number,
  col: number,
  stone: Stone,
  size: number,
): RejectReason | null {
  if (!inBounds(row, col, size)) return "out_of_bounds";
  if (cell(board, row, col, size) !== EMPTY) return "occupied";
  if (wouldWinIfPlaced(board, row, col, stone, size)) return null;

  const g = withStone(board, row, col, stone, size);
  if (hasOverline(g, row, col, stone, size)) return "changmok";
  if (countOpenThreeAxes(g, row, col, stone, size) >= 2) return "sansan";
  return null;
}

다음 글은 ‘3. 떨어진 사로 이기는 수를 못 보는 AI’입니다.