Skip to content

various fixes - #1

Open
dcolazin wants to merge 2 commits into
Isarhamster:mainfrom
dcolazin:linux-issues
Open

various fixes#1
dcolazin wants to merge 2 commits into
Isarhamster:mainfrom
dcolazin:linux-issues

Conversation

@dcolazin

Copy link
Copy Markdown

In this PR I collected several fixes required for my usage on Linux.

Bug 1 — No bestmove output when there is no mate solution

Problem: The UCI protocol requires that every go command be answered with exactly one bestmove line. When chest reported No Solution, extract_bestmove() printed nothing, hanging the GUI.

Root cause: The bestmove buffer stayed empty because the move-parsing loop was guarded by if (mate > 0) and the final print was conditional on bestmove[0] being non-null.

Resolution:

  • Added a parse_refu_move() helper that extracts the first legal move from chest's refu (refutation) lines — the moves that refute the mate attempt are valid legal moves.
  • When check_no_solution() triggers, the code now scans all lines for a refu entry and uses the first refutation move as the bestmove.
  • The final output is now unconditional: if a bestmove was found (either from the solution or from a refutation) it is printed; otherwise the code emits bestmove 0000 (the UCI null-move), guaranteeing a response in all cases.
  • If the output file cannot be opened at all, bestmove 0000 is emitted immediately.

Bug 2 — backend setoption truncates the last character of the path

Problem: Setting the backend path via setoption name backend value ./dchest corrupted the path. Two separate defects combined to eat characters: v += 7 skipped one character too many (should have been v += 6), and an unconditional dchest[strlen(dchest) - 1] = '\0' stripped a valid trailing character under the incorrect assumption that a " quote was present.

Resolution:

  • The entire setoption handling block was rewritten into a unified parser that accepts both the full UCI form (setoption name <key> value <val>) and a short form (setoption <key> <val>).
  • The value keyword offset is now correct (exactly 6 characters consumed after detection).
  • Quote stripping is now conditional: a trailing " is removed only if one is actually present, and a leading " is removed only if one is present. Unquoted values (the normal UCI case) pass through untouched.

Bug 3 — position startpos is not handled

Problem: The adapter only handled position fen .... When a GUI sent position startpos or position startpos moves ..., the internal FEN buffer was left empty, producing garbage output from chest.

Resolution:

  • Added a START_FEN constant (rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1).
  • A new handler (!strncmp(line, "position startpos", 17)) sets current_fen to START_FEN before the existing position fen handler, so the standard starting position is used.

Bug 4 — parse_chest_move produces malformed UCI moves

Problem: The original parser naively stripped the first uppercase letter and kept every remaining alphanumeric character. This mangled captures (Qxg6xg6), promotions (e8=Qe8Q), and castling (O-OO). The only formats that happened to work were the spaced/colon-separated notations (Ra1 - a8, Rf6 : f7).

Resolution:
The function was completely rewritten with a multi-step pipeline:

  1. Normalization — The entire line is copied into a buffer with all whitespace, separators (-, :), and check/mate suffixes (+, #) removed.
  2. Castling — If the token starts with O or 0, the O-count determines kingside (OOe1g1) or queenside (OOOe1c1).
  3. Piece-letter stripping — A single leading uppercase piece letter (non-O) is skipped.
  4. Promotion — If = is found, the following piece letter is captured and lowercased as a UCI promotion suffix.
  5. Capture cleanup — Any x or X characters are removed.
  6. Assembly — The remaining clean token is assembled into UCI coordinate notation, appending the promotion suffix when applicable.

Bug 5 — go without depth is not handled

Problem: Only go depth N was recognised. Any other go variant (go movetime 1000, go wtime 5000 btime 5000, bare go) was silently ignored, hanging the GUI.

Resolution:

  • The handler now matches any line starting with go.
  • It searches for a depth substring; if found, the depth value is extracted as before.
  • If no depth is specified, a default depth of 3 is used.
  • In both cases write_chest_input() and run_chest() are called, so the engine always responds.

Bug 6 — Dead variable bestmove in main()

Problem: A char bestmove[32] local in main() was never used (the real best-move logic lives in extract_bestmove()). It generated a compiler warning under -Wall -Wextra.

Resolution: The declaration was removed.


Bug 7 — Fragile fpos_t file positioning

Problem: The original two-pass approach used fpos_t / fgetpos / fsetpos to save and restore the file stream position. This was fragile: fpos_t is an opaque type, the initial = 0 initializer caused a compilation error on glibc (see Bug 8 below), and fsetpos was called unconditionally — potentially on an uninitialized setPoint when no mate solution was found.

Resolution:

  • The entire output file is now read into an in-memory array of line strings (lines_buf) using strdup().
  • Both passes iterate over the in-memory array, eliminating all fpos_t / fgetpos / fsetpos usage.
  • The file is closed immediately after reading.
  • All allocated line buffers are freed at the end of extract_bestmove().

Bug 8 — Compilation error: invalid fpos_t initializer

Problem: fpos_t setPoint = 0; failed to compile with gcc -O2 because fpos_t is an opaque type (a struct under glibc with large-file support) and cannot be initialized with an integer literal.

Resolution: As part of the Bug 7 refactor, the fpos_t variable and all associated calls were removed entirely, resolving the compilation error at its source.


Bug 9 — Unchecked system() return value

Problem: system(cmd) discarded its return value, triggering a warn_unused_result warning on glibc and making it impossible to detect a failed backend launch.

Resolution: The return value is now checked; on failure a Warning: failed to run chest command message is printed to stderr.


Additional Improvement — stdin redirection for dchest

Change: The run_chest() command was changed from "%s %s > %s" to "%s %s < /dev/null > %s".

Rationale: Redirecting stdin from /dev/null prevents dchest from accidentally reading from the UCI adapter's input stream, which could consume UCI protocol commands intended for chest_uci.


Additional Improvement — Selfmate / helpmate score negation

Change: When job_type is s (selfmate) or h (helpmate), the score mate value reported in the info line is negated.

Rationale: In these problem types the side to move is the one being mated, not delivering mate. Without negation, GUIs like ChessX would display a selfmate solution as if it were a direct mate. A negative mate score correctly communicates "the side to move will be mated in N."


Additional Improvement — Default job_type

Change: job_type was changed from an empty string ("") to "o" (orthodox).

Rationale: Ensures a sane default when no setoption name job command has been received, so dchest operates in standard direct-mate mode out of the box.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant