
The winning shape
○_○○○, with one empty cell inside, becomes five as soon as that cell is filled. In Gomoku terms this is a broken four. If one move creates this broken four together with a solid three (○○○) on another line, you win. The opponent must block the four first, and meanwhile you turn the three into an open four, which cannot be stopped. This is a four-three.
People find this spot easily. But the current AI does not play it even when it can make this shape with its own stones.

In real games
We replayed 24 web games and looked for moments when the AI (White) could have made a four-three in one move. There were 7 such moments, and the AI played the spot only once. It missed both chances to win through a broken four.
People, on the other hand, won with the same shape. Of the 22 games people won, 11 ended with a four-three.

Below is one of those games. When Black played on the dotted spot, a diagonal broken four (●●_●●) and a horizontal broken three (●●_●) appeared at the same time.

Testing the local AI
We ported the web's local AI code as is and tested it on a 15×15 board, randomly changing the orientation. It found its own four-three spot 29% of the time with a solid four (○○○○) plus a three, and 27% with a broken four (○_○○○) plus a three. It blocked the spot where the opponent could make a four-three on the next move only 33% of the time. Blocking a single three succeeded 67% of the time for a solid three and 100% for a broken three.

Why it cannot see it
The local AI scores each empty cell separately in four directions and adds them up. But for each direction, it counts five cells only forward from that cell, such as to the right or downward, and never looks backward. If the stones of the four and the three lie to the left of and above the four-three spot, as in the picture above, not a single stone is visible from that spot. Instead, looking right from the left end of the line shows three stones, so it picks that spot.
It also just adds up the score of each line and never checks separately whether two lines meet at one point to form a four-three. The code that looks for winning moves only checks moves that make five immediately. So it plays a four-three only when the direction happens to line up.
The forbidden-move check is done separately by the engine, and the engine correctly catches double-threes that include a broken three. The rules are being seen correctly; it is the player's judgement that falls short.
The actual code for this step
This is the part where the local AI scores a single empty cell. You can see that it counts only the five cells ahead.
omook-web/lib/ai.ts
function linePotential(
board: Stone[],
r: number,
c: number,
dr: number,
dc: number,
color: Stone,
size: number,
): number {
let streak = 0;
let blockedNear = false;
const rr0 = r - dr;
const cc0 = c - dc;
if (inBounds(rr0, cc0, size)) {
const oc = board[idx(rr0, cc0, size)];
if (oc !== EMPTY && oc !== color) blockedNear = true;
}
let rr = r;
let cc = c;
for (let k = 0; k < 5 && inBounds(rr, cc, size); k++, rr += dr, cc += dc) {
const v = board[idx(rr, cc, size)];
if (v === color) streak++;
else if (v === EMPTY) {
/* open */
} else break;
}
let score = streak * streak * 120;
if (streak >= 4) score += 50000;
if (blockedNear && streak >= 4) score = Math.floor(score / 8);
return score;
}
function scorePlacement(board: Stone[], r: number, c: number, who: Stone, size: number): number {
let s = 0;
for (const [dr, dc] of DIRS) s += linePotential(board, r, c, dr, dc, who, size);
return s;
}The next post is "4. A plan for the VLM to learn the heuristic, and for the heuristic to become the teacher again".
COMMENTS · CHAPTER 03
An AI that cannot see wins through a broken four 0 comments
No comments yet. Leave a question or anything you would like to add.
To post a comment, continue with Google and register a nickname and email address.
Continue with Google