AttoChess,一个专为 16 位 x86 DOS 设计、仅 278 字节的完整可玩国际象棋程序。
AttoChess, a complete, playable chess program for 16-bit x86 DOS in 278 bytes

原始链接: https://nicholas-afk.github.io/AttoChess/

AttoChess 通过优化原始引擎的四个关键领域,在不改变核心搜索逻辑的前提下,将代码体积缩减了十个字节: * **显示:** 移除了渲染缓冲区和字符串打印功能。通过使用专门的棋盘边界字符 (CR/LF),棋盘自身即作为显示框架。引擎现在使用 `int 29h` 直接流式传输至控制台,无需缓冲区管理和额外内存。 * **启动:** 舍弃了冗余的 BIOS 模式设置 (`int 10h`),改用 `int 29h` 流进行输出,该方式独立于视频模式运行。 * **输入解码:** 通过将 ASCII 偏移常量直接折叠进基地址来简化走法解码器,利用 16 位回绕运算消除了显式的归一化和掩码步骤。 * **搜索与逻辑:** 将搜索循环重写为使用指针比较而非计数器,从而释放了 `CX` 寄存器用于深度跟踪。此外,通过将方向检查合并进颜色位,精简了兵的逻辑,使得单条路径即可处理双方的移动。 这些精细化的调整去除了缓冲区开销、冗余指令以及不必要的状态管理。

抱歉。
相关文章

原文

AttoChess keeps the original's core search verbatim. All ten bytes come from rethinking the two things around the search, how the board is drawn and how the move is decoded, plus one change inside the search loop that frees a register.

01 · Display

The board draws itself: no render buffer, no int 21h/09h

This accounts for the largest saving.

The original renders the position into a separate buffer: it walks the board, transforms each square into a printable character, stores it, appends a $ terminator, and prints the whole string with DOS function 09h (int 21h). That path costs a buffer pointer setup, the copy loop's store, the terminator write, and, because the buffer lives after the board, a reserved board array in the image.

AttoChess deletes all of it. The board's border columns are laid out as CR, LF, CR, LF (0Dh, 0Ah, 0Dh, 0Ah) instead of the previous 08h filler. Both CR and LF still have bit 3 set, so every existing border/color mask test fires exactly as before, but now the raw board bytes are already a printable frame. The display loop streams each byte straight to the console with int 29h (DOS fast console output): borders become newlines, empty squares become NULs, and only real pieces take the ASCII transform.

main_loop:
    mov si, offset board_db + 24   ; row 2 (black back rank), col 0
    mov cl, 98                     ; 8 rank rows + final CR,LF (CH=0)
disp_loop:
    lodsb                          ; read square contents
    test al, 30h                   ; piece?
    jz disp_cont                   ;   no: emit raw (CR / LF / NUL)
    inc ax                         ; zero-align king
    and al, 27h                    ; isolate piece type + black/lowercase bit
    add al, 4Bh                    ; K, N, B, P, Q, R (upper/lower by color)
disp_cont:
    int 29h                        ; fast console output of AL
    loop disp_loop

Removed in one move: the render buffer, its pointer setup, the $ terminator, the int 21h/09h string print, and the reserved board array in the file image.

02 · Startup

No BIOS mode-set; deterministic startup instead

The original opens with int 10h to force BIOS display mode 0. AttoChess drops it and instead makes its two genuine entry assumptions explicit, which is both smaller overall and correct regardless of how the program is launched:

start:
    cld                            ; DF is not guaranteed clear at entry
    mov cx, 13                     ; row count (entry CX is not guaranteed)

Streaming through int 29h needs no particular video mode, so the mode-set is not required.

03 · Input

The input decoder folds every constant into one base address

Reading a move means turning two typed characters (a file and a rank) into a board address. The original does this in stages: read the file char, add it, read the rank char, mask it down with and al, 0Fh, load 12 into ah, mul to get the row offset, and subtract.

AttoChess collapses the arithmetic by pre-folding the ASCII bias constants directly into the base address and letting 16-bit pointer math wrap around mod 64K. The normalization step and the separate multiply setup both disappear:

read_sub:
    mov bp, di
    mov di, offset board_db + 123 + 0CE0h  ; base pre-folds the ASCII offsets
    mov ah, 01h
    int 21h                                ; read file char
    add di, ax                             ; AX = 0100h + file char
    int 21h                                ; read rank char
    imul ax, 12                            ; AX = 12 * (0130h + rank digit)
    sub di, ax                             ; land on the target square

imul ax, 12 (an 80186 immediate-form multiply) replaces the mov ah,12 + mul ah pair, and the wrap-around base makes the explicit and al, 0Fh input mask unnecessary.

04 · Search

The source loop frees CX, so depth is never reloaded

Inside the recursive search, the original scans candidate source squares with a counted loop (mov cl, 92 ... loop src_loop). That reuses CX as the loop counter, which clobbers the search depth living in CX, so on every recursive call it must re-read the depth back off the stack frame (mov cx, [si + 32]) before decrementing it.

AttoChess walks the source squares by comparing the pointer to the end of the board instead:

src_cont:
    inc bp
    cmp bp, offset board_db + 120  ; past the last square?
    jnz src_loop

CX is never touched, so it stays as the live depth counter for the whole scan. The recursive call site then does dec cx directly, and the stack reload of depth is gone entirely.

05 · Pawns

Pawn direction folded into the color bit

The original's pawn logic isolates the vector's sign bit, shifts it into alignment with the color bit, XORs against the side-to-move, and branches on parity, several instructions of bit-shuffling. AttoChess folds the forward/backward test straight into color bit 5 with a single xor al, dh, and reuses vector parity (odd offset = diagonal) to tell captures from pushes:

pawn:
    push ax
    xor al, dh          ; bit 5 := vector sign XOR side to move
    test al, 20h        ; forward for the moving color?
    pop ax              ; POP leaves flags intact
    jz vec_cont         ;   backward: reject
    test al, 1          ; odd offset (+/-11, +/-13) = diagonal?
    jnz pawn_cont       ;   diagonal: must capture
    xor ah, 30h         ; straight (+/-12): invert dest color for the empty test
pawn_cont:
    test ah, dl
    jz vec_cont

Because the direction test now keys off the side-to-move color rather than an absolute sign, pawns move correctly for both colors from the one code path.

联系我们 contact @ memedata.com