HN 日本語サマリー

← 一覧へ戻る
プログラミング

AttoChess、278バイトで実現した16ビットx86 DOS向けの完全でプレイ可能なチェスプログラム

AttoChess, a complete, playable chess program for 16-bit x86 DOS in 278 bytes (nicholas-afk.github.io)

13 pointsby SeenNotHeard4 コメント

要約

AttoChessは、16ビットx86 DOS環境で動作する、わずか278バイトの非常にコンパクトなチェスプログラムです。このプログラムは、従来のチェスプログラムが使用していたレンダリングバッファ、BIOSモード設定、複雑な入力デコーダー、スタックからの深さ再読み込み、複雑な駒の移動ロジックなどを排除または簡略化することで、驚異的なコードサイズを実現しています。特に、画面描画を直接コンソールに出力する高速化や、ポインタ演算による入力処理の統合が特徴です。

全文翻訳

01 · ディスプレイ ボードは自己描画します。レンダリングバッファなし、int 21h/09hなし。 これが最大の節約につながっています。元のプログラムは、位置情報を別のバッファにレンダリングします。ボードをウォークし、各マスを印刷可能な文字に変換し、それを格納し、終端文字($)を追加し、DOS関数09h(int 21h)で文字列全体を印刷します。このパスは、バッファポインタの設定、コピーループの格納、終端文字の書き込み、そしてバッファがボードの後に配置されるため、イメージ内に予約されたボード配列を必要とします。AttoChessはこれらすべてを削除します。 ボードの境界列は、以前の08hフィラーの代わりに、CR、LF、CR、LF(0Dh、0Ah、0Dh、0Ah)として配置されます。CRとLFはどちらもビット3がセットされているため、既存のすべての境界/カラーマスクテストは以前とまったく同じように機能しますが、生のボードバイトはすでに印刷可能なフレームとなっています。 表示ループは、各バイトをint 29h(DOS高速コンソール出力)を介して直接コンソールにストリームします。境界は改行になり、空のマスはNULになり、実際の駒のみがASCII変換を受け取ります。 main_loop: mov si, offset board_db + 24 ; 行2(黒の後列)、列0 mov cl, 98 ; 8ランク行 + 最終CR,LF (CH=0) disp_loop: lodsb ; マス内容を読み込む test al, 30h ; 駒か? jz disp_cont ; いいえ: 生の(CR / LF / NUL)を出力 inc ax ; キングをゼロアラインし、al, 27h ; 駒タイプ + 黒/小文字ビットを分離 add al, 4Bh ; K, N, B, P, Q, R(色による大文字/小文字) disp_cont: int 29h ; ALの高速コンソール出力 loop disp_loop 削除されたもの:レンダリングバッファ、そのポインタ設定、$終端文字、int 21h/09h文字列印刷、ファイルイメージ内の予約済みボード配列。 02 · スタートアップ BIOSモード設定なし。決定論的なスタートアップ。 元のプログラムは、BIOS表示モード0を強制するためにint 10hで開始します。AttoChessはそれを省略し、代わりに2つの実際の起動前提条件を明示的にします。これは全体として小さく、プログラムがどのように起動されても正しいです。 start: cld ; DFはエントリ時にクリアされているとは保証されない mov cx, 13 ; 行数(エントリCXは保証されない) int 29hを介したストリーミングは特別なビデオモードを必要としないため、モード設定は不要です。 03 · 入力 入力デコーダーはすべての定数を1つのベースアドレスに折り込みます。 移動の読み取りは、2つの入力文字(ファイルとランク)をボードアドレスに変換することを意味します。元のプログラムはこれを段階的に行います。ファイル文字を読み取り、それを追加し、ランク文字を読み取り、0Fhでマスクダウンし、12をahにロードし、乗算して行オフセットを取得し、減算します。AttoChessは、ASCIIバイアスの定数を直接ベースアドレスに事前に折り込み、16ビットポインタ演算が64Kでラップアラウンドするようにして、算術演算を圧縮します。正規化ステップと個別の乗算設定は両方とも削除されます。 read_sub: mov bp, di mov di, offset board_db + 123 + 0CE0h ; ベースがASCIIオフセットを事前に折り込む mov ah, 01h int 21h ; ファイル文字を読み取る add di, ax ; AX = 0100h + ファイル文字 int 21h ; ランク文字を読み取る imul ax, 12 ; AX = 12 * (0130h + ランク数字) sub di, ax ; 対象マスに着地 imul ax, 12(80186の即値形式乗算)は、mov ah,12 + mul ahのペアを置き換え、ラップアラウンドベースは明示的なand al, 0Fh入力を不要にします。 04 · 探索 ソースループはCXを解放するため、深さは再ロードされない。 再帰的な探索内で、元のプログラムはカウントされたループ(mov cl, 92 ... loop src_loop)で候補ソースマスをスキャンします。これはCXをループカウンターとして再利用するため、スタック上の深さ情報を上書きします。そのため、各再帰呼び出しで、深さをデクリメントする前に、スタックフレームから深さを再度読み込む必要があります(mov cx, [si + 32])。AttoChessは、ボードの終端へのポインタと比較することでソースマスをウォークします。 src_cont: inc bp cmp bp, offset board_db + 120 ; 最後のマスの先か? jnz src_loop CXは決して触られないため、スキャン全体のライブ深さカウンターとしてそのまま保持されます。再帰呼び出しサイトは直接dec cxを実行し、深さのスタックリロードは完全に不要になります。 05 · ポーン ポーンの方向がカラービットに折り込まれる。 元のプログラムのポーンロジックは、ベクトルの符号ビットを分離し、カラービットに合わせるようにシフトし、サイドトゥムーブとXORし、パリティで分岐するという、ビットシャッフリングのいくつかの命令を実行します。AttoChessは、フォワード/バックワードテストを単一のxor al, dhでカラービット5に直接折り込み、ベクトルのパリティ(奇数オフセット=斜め)を再利用してキャプチャとプッシュを区別します。 pawn: push ax xor al, dh ; ビット5 := ベクトル符号 XOR サイドトゥムーブ test al, 20h ; 移動カラーにとって前方か? pop ax ; POPはフラグをそのままにする jz vec_cont ; 後方:拒否 test al, 1 ; 奇数オフセット(+/-11、+/-13)=斜めか? jnz pawn_cont ; 斜め:キャプチャが必要 xor ah, 30h ; 直線(+/-12):空きマスチェックのためにデスティネーションカラーを反転 pawn_cont: test ah, dl jz vec_cont 方向テストが絶対符号ではなくサイドトゥムーブカラーに依存するようになったため、ポーンは単一のコードパスから両方のカラーで正しく移動します。