連珠ルール

五目並べの国際規格として使われる連珠ルールは、先に打つ黒が有利だと見て、黒にだけ禁じ手を課します。黒は三三、四四、長連(6つ以上)を打てず、白には何の制限もありません。長連も白にとっては勝ちです。

最初にエンジンを連珠ルールで作ったところ、白がほぼ無敵になりました。黒は攻められる形が禁じ手で封じられ、白は同じ形で思う存分勝てるからです。

黒と白に同じ禁じ手

そこで、黒と白の差がなくなるようにルールを直しました。

  • 三三: 黒・白ともに禁じ手。飛び三(●_●●、●●_●)も三として数えます。
  • 長連: 黒・白ともに禁じ手で、6つ以上は勝ちとしません。ちょうど5つだけが勝ちです。
  • 四四: 黒・白ともに許可します。
  • 五を作る手は、禁じ手の検査より先に見ます。勝つ手はいつでも打てます。
禁じ手の形。三三(連続した三+連続した三)、三三(飛び三+連続した三)、長連は黒・白ともに禁じ手、四四は許可
禁じ手の形。三三(連続した三+連続した三)、三三(飛び三+連続した三)、長連は黒・白ともに禁じ手、四四は許可

変えた後も白が勝った

ルールを変えた時期は記録に残っていないため、エンジンのファイルが最後に変わった自動対局の5日目を基準に分けてみました。それより前の445局では白が419局(94%)を、その後の42局では38局(90%)を勝ちました。

学習対局では、白はいつも VLM、黒はいつもローカルAIでした。そのため、白が勝ったのがルールのせいなのか、黒を担当したローカルAIが弱かったからなのかは、この記録だけでは区別できません。同じAIが黒と白を交互に持つ対局をもう一度打ってみる必要があります。

この段階の実際のコード

Webエンジンの禁じ手の検査です。勝つ手かどうかを先に見て、長連と三三だけを止めます。

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」です。