# Scoring seki in the game of go

I’m building a web-based version of the game of go called Tenuki. You can read more about it and try out the live examples over at the Tenuki GitHub repo. The general idea is to provide a complete, mobile-friendly, self-contained go board with enough logic to start and end a game, but which is easy for others to build on top of.

One of the features I’ve been working on is correctly scoring seki at the end of a game. I thought I’d write up how my solution works, along with some of the machinery used in implementing it.

The core ideas here aren’t really new. Other people have discussed far more intelligent and general go analysis using ideas I’ve totally borrowed. See the list at the end for more. The approach itself is a variation of one Bill Shubert (“wms”) gave back in 1996 — one difference is that instead of using virtual “grey stones”, I fill points in with an alternating checkered pattern on a grid.

I’d like to be able to give some measure of the algorithm’s accuracy, but I haven’t run it against a large enough testing dataset.

## Basics

This post is long enough as it is, so I won’t go over how to actually play go. If you’ve never played or don’t know the rules, I recommend The Interactive Way to Go — you can learn the basics in all of 10-15 minutes.

For a quick explanation on the relevance of “eyes”, Wikipedia’s page on life and death is quite good. One main thing to understand is territory versus neutral points.

## The Setup

Tenuki supports dead stone marking at the end of a game. Both players toggle stones as dead (shown as semi-transparent) which effectively removes them from the board.

In the general case — say, in the middle of a game — correctly analysing the life and death status of stones is very difficult. It requires a sufficient approximation of perfect play from an unsettled position.

But at the *end* of the game like this, the players have said which stones are dead. Since we already know that stones on the board are alive in some form, score calculation is simplified a bit: add up all the empty intersections surrounded by stones of a single colour.

Sadly, seki ruins it.

## Seki

Seki is a state of mutual coexistence where neither side can capture the other.

If black plays at the marked □ point, white immediately captures black. Similarly, if white plays there, black immediately captures white. Neither wants to play that point, so nothing is captured and both players are alive in the corner — it’s a seki.

What makes this interesting is that each player locally has only 1 eye, less than the 2 eyes you usually need to permanently avoid capture. (Black’s eye is in the very top left corner, if it’s not clear.)

Ordinarily, eyes count as points of territory during scoring, so black and white would each have 1 point in the corner. However, in Japanese-styling rules, *eyes in seki are not scored* and instead both sides have 0 points.

To score the game correctly, we need to discount eyes in seki. To discount eyes in seki, we obviously have to first know there even *is* a seki.

Can we easily detect seki and score the game correctly, given that we know the stones are alive in *some* form?

## A Strict Rule

The 1989 Japanese rules don’t treat eyes in seki as territory. The definition is based on neutral points (or *dame*).

Empty points surrounded by the live stones of just one player are called “eye points.” Other empty points are called “dame.” Stones which are alive but possess dame are said to be in “seki.” Eye points surrounded by stones that are alive but not in seki are called “territory,” each eye point counting as one point of territory.

Seki is unambiguous under this rule. For each neutral point on the board, find all neighbouring stones (which are now treated as alive in seki), and then find all supposed-territory surrounded by those stones. Discount all supposed-territory points you find.

In a formal setting like an official tournament, it’s not unreasonable to have players play all neutral points they possibly can. Then, the only remaining neutral points will be part of a seki, and the strict algorithm will work just fine. You can see this by looking back at the starting example of the corner seki:

The marked point is neutral, so the neighboring black and white stones are in seki. Done.

For informal settings, however, things break down quite quickly. In an online game, some neutral points will be on the board simply because neither player wants to spend the time making literally pointless moves.

On this board, the top left point is neutral. Should the white group be treated as seki? The strict algorithm says “yes” and ignores all white territory during scoring, despite there being *3* eyes, more than enough for unconditional life. Something more relaxed would be good.

## Assumptions and Outline

So we’ve got 3 assumptions to start:

- All dead stones have been marked by players as part of the scoring phase and are not considered part of the board.
- There may be some neutral points left on the board.
- Scoring is
*not the same as perfect, optimal play*.

The goal is to try and correctly detect seki so we can ignore points that aren’t actually territory.

The gist of the algorithm is:

- Fill in all neutral points.
- Fill in false eyes.
- If a group can’t make 2 eyes, then it’s in seki and any points it surrounds are not counted as territory.

To flesh this out, we need some tooling in order to get a good idea of what it means to, say, count a group’s eyes.

## Definitions

A *stone* is a non-empty intersection. It’s either *black* or *white*.

A *block* is a maximal connected set of stones. “Connected” means there is a path through adjacent intersections such that all intersections on that path are the same colour. (A collection of blocks of one colour are sometimes referred to as a *group*.)

For example, this 5×5 board has 4 blocks (3 white, 1 black):

A *region*, similar to a block, is a maximal connected set of *empty* intersections.

The *boundary stones* of a region *R* is the set of stones which are adjacent to *R* but which are not themselves in *R*. In other words, the stones at the edge of the region.

A region is *controlled* if all boundary stones of the region are a single colour. A controlled region is *white* if its boundary stones are all white. (Similarly for a region being *black*.) This is the idea of “surrounded” intersections: intersections that would be scored as territory before analysing seki. If a region is not controlled, then it’s *neutral*. (We can also say a single intersection is controlled or neutral if it’s in a controlled or neutral region, respectively.)

In the above board, there are two regions, one black and one white. The boundary stones of the white region on the left is the set of all white stones: all white stones are adjacent to some point in the region. (Note that the boundary stones may be composed of multiple blocks.)

To determine the boundary stones of a region, you can pick any point in the region and start following all empty neighbours along all paths, stopping at stones. Whichever stones you hit, those are the boundary stones.

Two regions are *directly related* if they share a common block of boundary stones. (This is along the lines of [2] in the references.)

Here there are 3 white regions, shown with *A*, *B*, and *C*.

Note that any two pairs of the *A*-region, *B*-region and *C*-region are directly related. For example, the *A*-region and *B*-region are directly related because they share the top-most white block.

Similarly, on this board, there are two directly related white regions, because they share a common block in the center.

Related regions will obviously come in handy for determining eye count.

The *expansion* of a region is defined as the recursive merger of all directly related regions (again, as in [2]). Consider the three controlled regions shown by , , on this board:

is directly related to , and is directly related to , but is not directly related to by the definition. By following the related-ness of to , then to , we can “expand” into , forming the transitive closure of the “is-directly-related” property.

(Note that the expansion here technically includes neutral regions. You could restrict the expansion to cover only *controlled* regions of the same colour, but since we’re going to fill in neutral points, it’s irrelevant here.)

Accounting for this expansion, we can say that is *related* to , meaning that there is some sequence of directly-related associations between and .

Following the definition of Ext() in [3], the *boundary length* of a region is the number of grid points containing , plus the number of boundary stones of . For a non-corner, non-side region, this is exactly the same as the number of boundary stones. At the edge of the board, the boundary length is calculated as if stones were present “on the outside” of the board.

So the boundary length of the top left empty region is 8:

- 4 intersections occupied by white, adjacent to the region, forming part of the boundary stones.
- 2 “grid points” for the top side of the board.
- 2 “grid points” for the left side of the board.

Basically, the boundary length accounts for the boundary of the board itself.

## Eye Counting with the Boundary Length

By enumerating possible cases, you can get the *eye count* (or *number of eyes*) for a region based solely on boundary length and recognition of a few shapes. For a more complete explanation, see [3], but the calculation leads to:

Boundary Length | Number of Eyes |
---|---|

≤ 6 | 1 |

7 | 1.5 |

8 (square four) | 1 |

8 (curved four) | 2 |

8 (any other shape) | 1.5 |

9 (containing a square four) | 1.5 |

9 (not containing a square four) | 2 |

≥ 10 | 2 |

A non-integer value like 1.5 means that if the player controlling the region plays first, then the eye count is 2. If the opponent plays first, the eye count is 1.

The white region on the above board has a boundary length of 8 and doesn’t contain a square-four or curved-four shape. Following the table, it has an eye count of 1.5: if black plays in middle, white has 1 eye; if white plays in the middle, then white has 2.

## Main Seki Detection

We’ve now got enough to build up an initial version of a seki detection algorithm.

To determine if a controlled region should be ignored due to seki:

- Expand into .
- Find the eye counts for each region: .
- Sum all of the eye counts, making sure to
`Math.ceil()`

each of them to always get the highest value: . - If the sum is < 2, then the group surrounding all regions in the expansion can’t make 2 eyes. Since the board is assumed to be alive (otherwise a player would have marked it dead), then the group is alive in seki.
- If the group is in seki from the previous step, then remove from the set of scored controlled points any point which is in one of the regions .

After all the removals in step (5), the remaining controlled points are territory.

## Problems Due to False Eyes and Neutral Points

This main way of detecting seki works quite well, but has a few pitfalls. Consider this board:

Running the algorithm over the white regions on this board will lead to the wrong conclusion that the white has 2 eyes, which is definitely not the case. The 2 “eyes” for white are false, but because of the black stones they can also never be filled.

We need a way to refine things so that this corner position is correctly treated as seki. We can do so with two preliminary steps:

- Fill in neutral points.
- Fill in false eyes.

## Filling Neutral Points

To fill in all neutral points, simply change them from empty to some other colour.

This leaves an interesting question though: *what colour do you fill the neutral points with?* For now, let’s say they’re all arbitrarily filled by one fixed colour. This will cause problems in other situations, but it’s a start.

## Filling False Eyes

When counting eyes we need to be sure to ignore false eyes. In this case, we’re going to look at very specific false eyes: those that are points of “obvious capture” — a false eye which would be filled, if, after filling all neutral points, it’s a direct point of capture of some neighboring block. For a simple example:

No player would count the marked □ point as a point of territory. It’s an obvious false eye because filling in the neutral point in the top left corner leaves stones that can be immediately captured by playing at □:

Let’s say an intersection is “false-ish” if it meets all these requirements:

- It is empty.
- It has at least one non-empty (“occupied”) neighbor.
- For an intersection on the edge of the board (the “first line”), it has 2 occupied neighbours with a colour opposite of any occupied neighbour. Anywhere else, it has 3 occupied opposing diagonals.
- On the edge of the board, it has at least 1 occupied opposing diagonal. Anywhere else, then at least 2 occupied opposing diagonals.

Note that *all neutral points have already been filled*. All remaining empty points are by definition controlled, and so we don’t need to worry about neighbours of different colours.

So here’s a simple false-ish eye:

The top left point is controlled because it’s fully surrounded by white stones. But the black stone on its diagonal means that, eventually, it must be filled in by one of the players. (Since this is the end of the game, the assumption is that all other stones are alive, so there’s no question of an outside group being captured.)

Why the “-ish” in “false-ish”? Because it’s not enough to blindly check diagonals. Take this position:

Both *A* and *B* are false-ish because of the shared diagonal black stone. But because of the 2 full eyes elsewhere, neither *A* nor *B* should ever be filled.

If, however, the empty bottom-right intersection were filled, then it becomes more clear that *B* should definitely not be a point of territory:

The reason is because now the 5-stone block next to *B* is 1 move away from capture at *B*.

This gives us a way of filling in (and defining, really) the obvious false eyes we care about:

- If there are no more false-ish points on the board, then stop.
- Otherwise, take the next false-ish point, call it
*F*. - If a neighbour of
*F*can be captured in one move, then fill*F*with the same colour as any occupied neighbour. (*F*is the capture point.) - Start again at (1).

Again, the only reason this is well-defined (e.g., for step (3)’s choice of colour) is that we’ve already filled in neutral points.

Let’s see what happens locally with the above board after running through this loop. We start with this board:

Then, *B* is filled:

Then *A* is neighbouring a 7-stone white block that can be immediately captured, so it too is filled:

And now, we’re done.

Since *A* and *B* were filled in, they’re not scored as territory.

Moreover, note that the seki detection algorithm will count the eyes of the white group as less than 2 (because it has only 1 eye). The 1 eye will be treated as non-territory. A player would likely then mark this entire white group dead, which effectively removes it from the board.

So as a total side-effect of filling in points to get a correct *seki* algorithm, *certain points that would have been territory are ignored*, potentially before any stones have been marked as dead.

## Filling is not Smart

That last point is worth a bit more thought. Note one of the original assumptions:

Scoring is

not the same as perfect, optimal play.

Filling in neutral points and false eyes in this way can’t detect certain situations, and isn’t intended to. Take this, for example:

There’s a snapback for black at *B*. If an algorithm fully read this sequence out with perfect play, it would decide that *B* is actually not a point of territory, then fill in *B*, then treat *A* as non-territory and fill that in too. *The algorithm doesn’t do this.* The snapback play at *B* is not detected. If both players leave the stones on the board like this, then all white regions are counted as territory. The scorer defers to player judgement here, it does not play perfectly.

## Seki Detection with Points Filled

The algorithm we now have is:

- Fill neutral points.
- Fill obvious false eyes.
- Treat remaining controlled regions as potential territory.
- Counting eyes of each expanded region, exclude a controlled region if it’s part of a seki.

With the addition of steps (1) and (2) we can see what the previous edge-case board looked like:

First, fill the neutral points:

Then fill the false-ish eyes neighbouring capturable groups:

(Note that the stones added aren’t played as if they were regular moves. Actually capturing stones by removing them doesn’t happen!)

Since no eyes are left, the original white regions will be ignored as part of the calculation.

## Example with Two 1-Eyed Groups in Seki

Take this example:

*A* is neutral. *B* is an eye controlled by black, *C* is an eye controlled by white.

First, fill *A*.

Each empty region (after expansion) sums to only 1 eye each, so the surrounding stones are alive in seki, and *B* and *C* are discounted as territory.

## Which Colour for Filling Neutral Points?

There’s one remaining question around filling neutral points: which colour do you use?

Using a fixed colour doesn’t work, because some neutral points don’t affect connections between groups, and others do. Take a board like this:

The two 1-eyed white groups are effectively connected. There are 3 ways to connect, and white only needs 1 of them. Ideally this should be treated as white territory, not a seki. Since filling in neutral points is needed to detect seki, the 3 neutral points in the middle will be filled with *some* colour, but which one?

If the choice of fill colour is white, then it’s all fine because the groups connect:

If the choice is black, then it doesn’t work, because now the groups are fully separated and are treated as non-scoring:

(Note that black and white could reverse roles. A single fixed colour will always have this problem.)

One workaround is to use a colour which acts as if it is *both* black and white. This is the approach taken in [6]: “grey” stones acting as simultaneously black *and* white. The two 1-eyed white groups connect, and are counted as territory.

Use of grey stones in this way suffers from the problem in [6]. Consider this board, which contains a seki in the lower left:

The marked points form bamboo joint connections. Consider the *A* points: white should be able to connect with at least one of the *A* points, which will also cut off the lower left black group. Since black has a similar position with the *B* points, the two 1-eye groups are in seki because of the neutral point between them.

But with grey stones, all *A* and *B* points are filled such that both 1-eye groups connect out. The eye calculation comes out as ≥ 2 and the eyes end up counting in territory.

## Avoiding False Negatives with Alternate Play

It seems like the use of grey stones introduces problems because it creates board states that can’t actually exist under any normal sequence of moves. A board state is being evaluated where some points are simultaneously two colours. Is there a way to fill in neutral points in a way that reflects playing regular moves?

Instead of using grey stones, the idea is to more accurately simulate real play by using alternate colours. Black, white, black, and so on. This leads to a few design questions:

- Are regions filled independently? That is, if a region is filled with black, white, black, does the next region start with black, or white?
- In which order do you fill in the points?

The first question is concerned with play dependence across regions. It seems reasonable to say that all regions are independent and to always choose black for the first move in each region.

Running with that idea, the previous board (which is seki if detected correctly) changes from this:

To, say, this, after playing *A* points and *B* points with alternate colours:

This is now correctly detected as seki by counting eyes. Note that the choice of which of the *A* and *B* points to start with has no change on the outcome.

The second question — which order to fill in the points — is an issue for groups that are “loosely” connected. To get a better understanding, let’s say a group is one intersection away from being separated:

If we score this board, what happens with the white stones? If the players really did end the game with this board position unresolved, then the answer depends on which colour is chosen. Critically, without “grey” stones in the scoring algorithm, this can *never work reliably*.

If *A* is filled with white, white connects and has 2 points. If *A* is filled with black, white is separated and has only 1-eye groups adding up to 0 points.

By flipping the colour of all stones, any initial colour choice in this case will break. If the initial colour choice is not always fixed to, say, black, and is instead based on the last stone played in the previous region, then correctly scoring this will depend on the parity (odd or even) of the number of previously played neutral points before filling in this neutral region.

So scoring this without grey stones is inherently broken. However, it’s actually unlikely that the board would be left in this unresolved state by the time scoring starts: both sides will *really* want to play *A*. As such, *it isn’t a goal to score this properly*.

Consider a board like this, as a simpler version of the more complicated board above:

Then expand the neutral region to the right so its gap is bigger:

In what order should the 4 points be filled in? Following a top-down, left-to-right pattern (again, starting with black) means the white groups stay disconnected. Fill *A*, *C*, *B*, *D*:

However, following the transposed path *A*, *B*, *C*, *D* leads to a different outcome:

With grey stones, the white group is alive with 2 eyes. Without grey stones, the life status depends on the order.

Similar regions of neutral points lead to similar outcomes. For example, this is also order-dependent:

It seems that we’d like two things:

- Groups separated by a gap of 1 should be treated as connected. For example, the bamboo joint.
- Anything with a bigger gap should be treated as disconnected.

## Using a Checkered Pattern

A filling strategy which seems to work is using a checkered pattern: fill the neutral intersections such that an intersection will have a colour different from its neighbors, forming a checkered grid.

By checking subsets of a 2×2 neutral region, you can see that, with this filling method, groups are always left disconnected if they’re separated by a gap of 2, no matter which colour or intersection you start with:

## References & Other Work

- “Recognizing Seki in Computer Go.” Niu, Kishimoto, Müller.
- “An Improved Safety Solver for Computer Go.” Niu, Müller.
- “Static analysis of life and death in the game of Go.” Chen, Chen.
- “Life in the Game of Go.” Benson.
- “When One Eye is Sufficient: A Static Classification.” Vilà, Cazenave.
- A rec.games.go post by Bill Shubert (“wms”).