Illegal ko move?

Please look at this puzzle:

This question is not about the puzzle, it’s about the rules (or is it a bug?). The puzzles rotate, so position the puzzle so it is around the point A1 (with a white stone at A9), white to move.

For first move, white goes to B1. Then Black goes to A1, taking white at A2. Now have white play back at A2, taking black at A1. Shouldn’t that be an illegal ko move?! The computer ALLOWS that move.

I don’t understand. Someone please explain how that is not an illegal ko move. (Or, verify that it is a bug.)

Thank you!


What a coincidence that you posted this right now, I actually fixed it last week and it got merged earlier today:

It should be live on the site in the next few days.


Does this mean that you could have the same problem in the first three moves of a forked game? (separate from the issue that forked game doesn’t remember captures or earlier positions)

The “move_number > 2” check seems really strange to me, is there any point in having it at all?


@le_4TC Good point, that is a problem. I have a minimal repro here on the beta site:

If you fork that game ko rules aren’t properly enforced.

The introducing commit to the goban repo doesn’t add context since it was just pulled out of the repo:

And unfortunately the introducing commit to the repo isn’t helpful either since it was already present when the client was open sourced:

@anoek do you have more context for the move_number > 2 check? I assume that there is some edge case that this handles, but maybe it was just trying to “be safe”? This forked game issue seems pretty serious so it would be good to drop the check if it’s not strictly necessary.

1 Like

That is some very old code. I can’t think of a reason why it’s there, unless I was protecting some bounds somewhere - but even then it seems like it should be > 0 not > 2, and otherwise I should be handling the case elsewhere. I think I’d be comfortable removing it providing folks did a good amount of testing around those cases to make sure nothing explodes.


From testing it out it doesn’t seem like anything goes wrong (or explodes), but I haven’t tried too many edge cases (not sure what they would be). This logic seems do the “correct” thing (return false) when evaluated on the first move (i.e. there is no previous move): this.boardStatesAreTheSame(current_state, this.cur_move.index(-1).state)

However, this doesn’t fully solve the forked game issue. As we check for ko by determining if the previous board state is the same, a game without an earlier move tree will never find a ko on the first move even though this is possible in a forked game (e.g. forking this game:

If we copied move history, then removing move_number > 2 should be enough to solve the problem. Seems like adding captures/history is blocked on an API change though, so not something I can push through on the client side:

Still, even though this isn’t fully solved the behavior is better with move_number > 2 removed since it will now detect if a ko occurs on the second or third move which it wouldn’t before (and also it simplifies the code). I’ve published a PR (, but we might want to test on beta for a bit before pushing live (or feel free to send me more test cases and I’ll be happy to try them out on dev).

1 Like