Pachi 12.88#172
Merged
lemonsqueeze merged 112 commits intopasky:masterfrom Dec 11, 2025
Merged
Conversation
bin/interleaved_logfile: older gogui-twogtp versions capture programs' stderr and depending on java threads scheduling don't always preserve ordering so their output sometimes get mixed up, leading to interleaved log files (end of player's debug output appears in the middle of the other). this can be a problem if you want to process game logs with some tool. this script can be used to check twogtp logs, see if that's the case (only works for pachi self-play games). Used to happen about 1 in 10 games. if you care about this grab gogui-1.4.11 from my repo which is fixed: https://github.com/lemonsqueeze/gogui
Show gamma changes history for given feature/spatial
show stats on game moves features, highlight features with very few matches. can be problematic for good move features: features with very few hits can't be rated accurately. bad move features it's the opposite: shouldn't show up often in game moves otherwise might indicate a problem.
…seki groups unclear save initial ownermap before starting mcts: u->initial_ownermap initial ownermap (mcowner playouts only) u->ownermap global ownermap (initial ownermap + mcts playouts) added t-regress/fixed/pass_is_safe
makes no sense to look at search state if it's not ready yet. fixes weird race condition situation where main thread checks whether to stop search while workers haven't finished pre-search setup and there aren't enough mcowner playouts. main thread used to get around this by doing the missing playouts itself in pass_is_safe() which is insane. just wait until it's ready.
even if patterns are disabled, needed for pass_is_safe() calculations
usage: pachi-external_engine_mode q1 q2 q3 q4
external_engine_mode q1 q2 q3 q4
set external joseki engine mode (one number per quadrant = number of moves left)
for debugging, allows to restore josekifix state when trying to reproduce bugs.
…ding overrides sgfdump: warning if name missing
test:
A B C D E F G H J K L M N O P Q R S T A B C D E F G H J K L M N O P Q R S T
+---------------------------------------+ +---------------------------------------+
19 | . . . . . . . . . . . . . . . . . . . | 19 | : : : : : : : : : : : : : : : : : : : |
18 | . . . . . . . . . . . . . . . . . . . | 18 | : : : : : : : : : : : : : : : : : : : |
17 | . . . . . . . . . . . . . . . . . . . | 17 | : : : : : : : : : : : : : : : : : : : |
16 | . . . . . . . . . . . . . . . . . . . | 16 | : : : : : : : : : : : : : : : : : : : |
15 | . . . . . . . . . . . . . . . . . . . | 15 | : : : : : : : : : : : : : : : : : : : |
14 | . . . . . . . . . . . . . . . . . . . | 14 | : : : : : : : : : : : : : : : : : : : |
13 | . . . . . . . . . . . . . . . . . . . | 13 | : : : : : : : : : : : : : : : : : : : |
12 | . . . . . . . . . . . . . . . . . . . | 12 | : : : : : : : : : : : : : : : : : : : |
11 | . . . . . . . . . . . . . . . . . . . | 11 | : : : : : : : : : : : : : : : : : : : |
10 | . . . . . . . . . . . . . . . . . . . | 10 | : : : : : : : : : : : : : : : : : : : |
9 | . . . . . . . . . . . . . . . . . . . | 9 | : : : : : : : : : : : : : : : : : : : |
8 | . . . . . . . . . . . . . . . . . . . | 8 | : : : : : : : : : : : : : : : : : : : |
7 | . . . . . . . . . . . . . . . . . . . | 7 | : : : : : : : : : : : : : : : : : : : |
6 | . . X . . . . . . . . . . . . . . . . | 6 | : : : : : : : : : : : : : : : : : : : |
5 | . . . . . . . . . . . . . . . . . . . | 5 | : : : : : : : : : : : : : : : : : : : |
4 | . . . X . . . . . O . . . . . . . . . | 4 | : : : : : : : : : : : : : : : : : : : |
3 | . . X O . O . X . . . . . . . . . . . | 3 | : : : : : : : : : : : : : : : : : : : |
2 | . . O). . . . . . . . . . . . . . . . | 2 | : : : : : : : : : : : : : : : : : : : |
1 | . . . . . . . . . . . . . . . . . . . | 1 | : : : : : : : : : : : : : : : : : : : |
+---------------------------------------+ +---------------------------------------+
matches both "4-4 keima keima tsuke" and "4-4 keima pincer tsuke" with new joseki fixes.
IN: genmove b
external joseki engine move: E3 (12.0s)
joseki_override (move 8): E3 (4-4 keima keima tsuke)
joseki_override (move 8): E3 (4-4 keima pincer tsuke, 2) (prio 2)
katago sometimes passes when super winning under japanese rules, which we really don't want here. plus it was causing crashes as we didn't handle pass correctly. Ex: CarolEdan pachipachi 2025-10-15 18:47 sometimes crashes after w K5 (set_external_engine_mode 5 5 5 5, genmove b) switching to chinese rules seems to prevent passes. fixed crash, in the worst case we genmove if we get a pass.
…ded) removed auto adjacent quadrant logic for external engine overrides: until now if last move was close to quadrant boundary we would enable both quadrants automatically, which was useful when there was no way to set quadrants explicitly but is more of a pain now (often overshoots and clobbers explicit settings). warn about overrides with ambiguous (or near ambiguous) quadrants instead: they should all have explicit settings so behavior relies only on data: external_engine = lower_left lower_right for example in sgf. fixing override data to go along with this (in joseki_fixes branch, not here).
…nts in canonical order with no other quadrant setting given
updated README
make proper struct for best moves handling: - makes parameter passing a lot nicer - allow pass among best moves keep track of number of moves stored so we don't have to rely on hacks like pass/null move list terminator.
…ves_t)
- before: coord_t best_c[] best coords array was initialized with passes,
which meant we couldn't handle actual pass moves (when reading array,
finding pass meant end of array).
read loop was:
for (int i = 0; i < nbest && !is_pass(best_c[i]); i++) {
printf("%s ", coord2sstr(best_c[i]))
- now: best->n gives number of stored moves
best->size is array total capacity
read loop:
for (int i = 0; i < best->n; i++) {
printf("%s ", coord2sstr(best->c[i]))
best->c and best->r are initialized with zeros so this is valid shortcut
for fixed width output:
for (int i = 0; i < best->size; i++)
printf("%.1f ", best->r[i]);
gogui: fixed some hardcoded boardsize
replay best_moves(): add only played moves
mq.h: simple move queue gmq.h: gamma move queue (each move has a gamma) mtmq.h: multiple tags move queue (max 32 tags per move, 32 possible tags) mq.h: renamed: move_queue_t -> mq_t added mq_add_nodup() = mq_add() + mq_nodup() print functions pass q first
type renaming after mq.h change. mq_print*() functions take q first.
- type renaming after mq.h change (move_queue_t -> mq_t) use gmq_t for patterns (gamma move queue) use mtmq_t for fullchoose() - refactoring: tag handling in moggy fullchoose(), not in tactics code. tagged move queues are only used by moggy, and only in fullchoose() which is not used by default. handle tags in fullchoose() instead of cluttering tactics functions. - fullchoose(): no need to handle duplicate moves in mq_tagged_choose(), already taken care of (each move is added with mtmq_add_nodup()).
was used for priors long time ago when patterns were not available
was only working over gtp, allow from test file as well
run pachi in build directory
toggle showing/hiding debugging analyze commands within gogui. select "Show Debugging Commands" action also shown by default with pachi -d4
group must be 1lib
…p_lib() simplify group liberties api: before after board_group_info(b, g).libs group_libs(b, g) board_group_info(b, g).lib[i] group_lib(b, g, i) gi = &board_group_info(b, g) gi = group_info(b, g) so much nicer to write, also makes it easy to add automated checks in the future. for example can check that all group liberty accesses are valid by changing group_lib() macro.
…lib() simplify group liberties api: before after board_group_info(b, g).libs group_libs(b, g) board_group_info(b, g).lib[i] group_lib(b, g, i) gi = &board_group_info(b, g) gi = group_info(b, g)
EXTRA_CHECKS enables board extra sanity checks: try to catch invalid coord / group / color arguments in low-level functions. these are used extensively so helps ensure the whole codebase is sane. this will catch errors that the compiler can't find like swapping coord_t and enum stone arguments to a function for example. also turn on board undo checks. foreach_free_point() check not quick board foreach_in_group() check sane group foreach*_neighbor() check sane coord, not OFFBOARD group functions check sane group group_lib() check sane group and liberty board_is_eyelike() check sane args and empty coord board_is_valid_play*() check sane args board_play*() check sane args with_move() check not uct engine main board stone_other() check player color (black or white)
can't foreach_free_point() inside with_move(): quick board doesn't maintain board empty spots. found by EXTRA_CHECKS
wasn't updating board with each move in the sequence, so board and tree passed to policy choose() were out of sync. went unnoticed for so long as uctp_generic_choose() only uses board when best move is pass. this was messing up pass logic in reported best sequence. best move reply is also used to check when to stop search and was affected as well. found by playing games with EXTRA_CHECKS on (pachipachi SEV2023 2025-12-08 19:42) gogui: handle pass in best sequence best sequence cleanup
suprisingly not included in -Wall: -Winit-self warns about self-referencing initialization like this which can easily happen with macros defining variables: (undefined behavior) int x = x; -Wimplicit-fallthrough catches undeclared fallthrough in switch statements
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Looks like 12.88 release is getting closer.
No big changes in this release but some fixes, board speedup and infrastructure work.
Board speedup
Ended up revisiting parts of the board play code and surprisingly in the end it's quite a bit faster, even with is_bad_selfatari() changes which are more expensive. Getting an extra 50 raw playouts/s on Raspberry Pi (!)
Tactics
Found some snapback, throw-in and nakade issues while hacking around. This is the biggest engine change in this release. It fixes a lot of misclassified moves and is slightly more expensive.
Play-testing against Pachi 12.86 appears beneficial (winrate 54.3% ±4% for 700 15x15 nodcnn games).
Debugging
Enables tons of extra sanity checks in low-level and engine code. Good complement to ASAN to harden codebase, and pretty fast too. It does some pretty cool stuff like check every group and liberty access is valid, check invalid quick board uses inside
with_move(), check neighbor iterators don't get called on OFFBOARD coordinate, check uct main board remains thread-safe ... Can also act as runtime type checker for errors the compiler can't flag like swapped coord_t and enum stone arguments.No big surprises in the end, low-level code is pretty sound by now. However it's already found 2 hard to find bugs in higher level code I wasn't aware of.
Reworked debug logs so
pachi -d6shows playout logic, including random / permit logic.(Need to add
#define DEBUGto playout.c and moggy.c, debugging disabled by default).Added
moggy movestest so we can have playout unit tests in the future (todo).Cleanup
mq.h = simple move queue, gmq.h = gamma move queue, mtmq.h = tagged move queue
Should be slightly more efficient, and we don't have to fill dummy tags all over the place.
Tagged queues are only needed by moggy fullchoose() which we don't use by default. Handle tags in fullchoose() and let tactics code use simple move queues.
group_base()board_group_info()macro by shorter, specialized ones.Nicer to use and makes it easy to add automated checks.
Josekifix