BootChess by Red Sector Inc. [web]
;----------RED-SECTOR-INC.-proudly-presents-a-33-year-old-record-:---------- ; ___ _ ; / / _____ _ _ _____ _ _ ___ _ ; .::. / / / / / / / / / / ; :::: / / ____ .-/ _ ___/-. .-/ _ ___/-. / /__ ; :: / \ | | . | | | . | / / ; :: __ _ \ l | | | l | | / ___/ ; .::. / / / / | l |_| l | |__/ / ____ ; .::::. / __/ `--' `--' / | ; :::::::: / / | ; ___ __ Cl! ___ ___ / ___ _ _ __| ; ___ _ _ / __/_ __ _ _/ _/_ _ /_ / / ___ /__ ; /_/ / / / / / / _____/ / / / __/ _ / / / ; .-/ ___/ / /______ / ___\ \___ / / __/ ; | / / / | __/ ___ | \ | ___\ \___ ; | / ____ | / | | _/ | | \ | ; | /--/ | ___/ | | | | | _/ | ; | | / / :: | ____/ :: | | :: \_____| | | ; |_____/ :: | __/ /_______| /_______| |_______\ | :: \_____| ; /_______| /___ _ /___ _ _ ___\ |_______\ ; /___ _ _ ___\ ; BootChess is the smallest computer implementation of chess on any platform ; Chess in a 512-byte x86 boot sector for Windows / Linux / OS X / DOS / BSD ; Coded by Olivier "Baudsurfer/RSi" Poudade with extra help of Peter "QKumba" ; Ferrie. Logo by Frederic "Cleaner/Break" Cambus. (c)2015 WTFPL v2 license. ; "Fasm BootChess.asm" + "partcopy BootChess.bin 0 200 -f0" = PC floppy boot ;-BootChess.asm-------------------;----------------------------------------- x86 equ 1 ; x86=1 PC/emu vs. win32b/(DOS)Box saf equ 0 ; saf=0 +queening -exotic failsafe _b equ byte ; DEFAULTS=PC FLOPPY BOOT+QUEENING _w equ word ; x86=1 saf=0 512b inc. queening _d equ dword ; x86=1 saf=1 500b+ excl. queening* _s equ short ; x86=0 saf=1 506b inc. queening _n equ near ; x86=0 saf=0 487b excl. queening _f equ far ; *only working version in Bochs if x86 ; beg of boot vs .com preprocessing org 7c00h ; std start of bootsector after post if saf ; beg clear any start ambiguous segment jmp _f 0:fix ; 7c0:0000 vs. 0:7c000 cs para fix-up end if ; end clear any start ambiguous segment fix:push cs ; if post int 19h isr bootsrap loader pop ds ; left any bda or shadow segment values push cs ; then enforce ds=cs=0 pop es ; then enforce es=ds=cs=0 mov aX,13h ; function set vga mode 320x200x256 else ; else if 16-bit binary assume ah=0 org 100h ; start of com binary program ip mov aL,13h ; function set vga mode 320x200x256 end if ; end of boot vs .com preprocessing int 10h ; standard bios video api brd equ bf1+16 ; chess board at end of sector mov di,brd ; set physical board index mov bp,12 ; set 6x8+8 empty sqr mid board lines call in2 ; pass#1 black "rnbqkbnr" low-caps push word opn ; pass#2 hi-caps whites & fall-through rle:lodsb ; al='.'/al=null (fixed length rle) mov cl,8 ; empty sqr mid board line length rep stosb ; set one empty sqr mid board line dec bp ; all empty sqr mid brd lines inited ? jnz rle ; if not repeat init else bp=0 assumed mov ah,'A'-'a' ; fall-through pass#2 white hi-caps in2:mov si,br0 ; si points to endrank "rnbqkbnr" str if x86=0 ; if .com binary environment ch=0 mov cL,8 ; "rnbqkbnr" endrank str length else ; assume nothing although tempting mov cX,8 ; "rnbqkbnr" endrank str length end if ; end of register ch startup value in3:lodsb ; read physical board str car add al,ah ; hi-caps rank 1 / low-caps rank 8 stosb ; write physical board str car loop in3 ; all "rnbqkbnr" str car written ? mov cl,8 ; si-;equiv piece vals di-;0x88 brd rep movsb ; write logical 0x88 board str vals retn ; return to callers ge0:mov bx,di ; physical board idx (bx=brd) mov dh,'1' ; beg white move src rank ge1:mov dl,'h' ; beg white move src file ge2:mov [si],dx ; beg white move src str mov ch,'1' ; beg white move dst rank ge3:mov cl,'h' ; beg white move dst file ge4:mov [si+2],cx ; beg white move dst str pusha ; save all values call idx ; passive chess coords to linear indexes jbe mis ; white move src color not conforming push bx ; save white move dst idx call ver ; white move legal chess ? pop bx ; restore white move dst idx jc mis ; white move not legal chess mov di,num+3 ; compare move destination rank in 7dfeh inc si ; with move source rank in 7dfch cmpsb ; is taxi distance to topmost bettered ? jnc wor ; else not getting closer to black king cmp _b [di],'?' ; does any fallback move exist yet ? jz lkj ; no, then last valid move good enough wor:mov aL,_b[si+bx+brd-num-'a'+6]; yes, previous valid legal exist so dec aL ; only override if it's a capture js mis ; no, don't want worse taxi distance mov bx,fs ; it's a capture with piece value=al cmp bL,aL ; but hightest capture value yet ? jnc mis ; no, less important opponent piece max:mov fs,bx ; fs=best move yet in taxi half-ply lkj:dec si ; realign source index dec si ; to copy dword bst=dword idx movsd ; after 4096 tries : move=dword bst mis:popa ; restore all values cmp cl,'a' ; end white move dst file ? loopnz ge4 ; dec white move else next dst file inc ch ; inc white move dst rank cmp ch,'9' ; end white move dst rank ? jnz ge3 ; else next move dst rank cpx:inc bx ; inc physical board index dec dx ; dec white move src file cmp dl,'`' ; end white move src file ? jnz ge2 ; else next move src file inc dh ; inc white move src rank cmp dh,ch ; end white move src rank ? ch=9 jnz ge1 ; else next move src rank push _d [si+4] ; get best white move found pop _d [si] ; set it as final white move val:mov cl,'.' ; valid : empty sqr replaces src piece call act ; active chess coords to linear indexes xor bp,3 ; player turn and pawn unidir. delta jz ge0 ; white turn to play (case best=0) bla:mov al,'?' ; input str clear pattern mov di,si ; input str clear pattern (di=num) mov cx,8 ; input str clear pattern rep stosb ; input str clear pattern (di=brd) call key ; get user keyboard input jbe bla ; black move src color not conforming opn:call ver ; di=brd, black move legal chess ? jc bla ; white move not legal chess jmp _s val ; validate black move ver:call idx ; get lin indexes /w implicit passive xchg bx,dx ; switch bx=dst idx dx=src idx mov ah,[si+bx+brd-num-'a'+8] ; get piece logical 0x88 brd val... mov dh,bl ; dh=src idx dl=dst idx sub dx,"aa" ; get move file zero-based indexes bsr bx,ax ; scan for 1st bit set (si=idx+10) movsx bx,[si+bx-10-num+tab] ; bl=moved piece type idx (bh=0) mov cx,_w [si+bx-num+tab] ; piece type deltas cl=repeats ch=num sahf ; set piece logical 0x88 brd val jnp sp1 ; branch if piece not pawn (bit#4!=1) jc sp2 ; branch if pawn prev moved (bit#0=1) sp1:jns sp3 ; branch if piece not king (bit#7!=1) sp2:mov cl,1 ; override repeat if piece pawn or king sp3:jnp sp4 ; branch if piece not pawn (bit#4!=1) add bx,bp ; pawn player turn unidirection mutex sp4:inc bx ; advance piece type struct field ptr and ah,11111100b ; isolate piece bitmask only vl1:push cx ; save piece type deltas mov al,dh ; load start dst idx val inc bx ; advance piece type struct field ptr vl2:add al,[si+bx-num+tab] ; add this piece delta to dst idx val xchg aL,bL ; base reg=dst idx val and preserved mov ch,[si+bx+brd-num+8] ; read projected dst square val xchg aL,bL ; base reg=piece type struct field ptr cmp al,dl ; wanted move found (src+delta(s)=dst) ? jnz dif ; different than requested move sam:sahf ; get piece logical 0x88 brd val in flgs jnp yes ; branch if piece is not pawn (bit#2=0) test [si+bx-num+tab],1 ; pawn piece delta parity=diag vs. vert jz ord ; branch if pawn piece moving vert test ch,ch ; pawn piece vert move=;eating ? jnz yes ; capturing verify dst sqr not empty jmp _s bad ; else illegal chess move is a miss ord:test ch,ch ; pawn piece vert move=;no eating ? jz yes ; no eating=;empty dst sqr else illegal dif:sahf ; store piece nature in flags register jnp skp ; not pawn piece so skip direction test test [si+bx-num+tab],1 ; pawn piece delta parity=diag vs. vert jnz bad ; diagonal pawn move is illegal skp:test ch,ch ; else skipping over dst square val ? jnz bad ; projected dst sqr val is not empty sahf ; get piece logical 0x88 brd val in flgs jz x88 ; branch if piece is queen (bit#6=1) jna bad ; branch if piece is not knight(bit#4=0) x88:test al,88h ; ch=0 dst out of physical board limits? loopz vl2 ; else cont if delta repeats remain bad:pop cx ; restore piece type deltas dec ch ; all possible delta nums verified ? jnz vl1 ; if not then cont next delta type nok:stc ; else return /w no match flg set retn ; return to caller yes:pop cx ; correct entry sp and disregard count retn ; return to caller(s) key:call prt ; refresh screen to account input echo xor bx,bx ; bx=str idx=odd/even/alpha/num mutex kbd:cbw ; fun blocking wait for keystroke (ah=0) int 16h ; std bios keybd api (ah=scan al=ascii) esc:dec ah ; was esc key pressed to quit ? jnz car ; else default process key input xit:if x86 ; if x86 boot context environment int 19h ; exit through bootstrap to reboot cpu else ; else if .com 16-bit binary int 20h ; dos 1+ - terminate program end if ; end of exit methods (os load or shell) car:mov [bx+si],al ; sav ascii val to move string (si=num) prt:pusha ; save game state snapshot cwd ; curs location dx=(0,0)=(row,column) mov ax,1301h ; function ega write str write mode 1 mov bl,7 ; page 0 grey car attrib matching tty mov cl,8 ; src str lngth (curs updated horiz) mov bp,bf1 ; es:bp is "abcdefgh" ptr lns:int 10h ; standard bios video api add bp,16 ; bp=para step siz separating strings push ax ; save old bios video api func params mov ax,0e39h ; function teletype outp car=rank '9' sub al,dh ; decrement right handside rank value int 10h ; standard bios video api pop ax ; restore old bios video api fx params cmp dh,cl ; src str total (curs updated vert) inc dh ; preemptive off-by-one allows 9 verts jc lns ; all 9 brd gui row strings printed ? mov bp,si ; 10th row tail bp=move coords, cl=8 int 10h ; standard bios video api popa ; restore game state snapshot inc bx ; test if any more keys ? cmp bl,4 ; frFR format input string jc kbd ; else continue input idx:loop idx ; ch=0 passive call load src/dst lin idx act:mov si,num ; reinit si to point to coord input str. mov bx,[si] ; bx=src coord (pass#1) cbw ; empty sqr val in logical 0x88 board call put ; place param passed as fun pass#1 mov dx,[si+2] ; bx=dst idx dx=src idx xchg bx,dx ; fall-through for second pass push word mat ; test for checkmate and conforming put:xchg ax,bx ; bx|dx=[num+di]+16*((8-'0')-[num+di+1]) aad -10h ; shl ah,4/sub al,ah/xor ah,ah add al,80h ; bx|dx=al-640%256-16*ah xchg ax,bx ; bx|dx=al+128-16*ah jcxz sim ; active call request or simulation ? if saf=0 ; standard non-failsafe queening cmp _b [si+3],'8' ; validated dst rank is top-most ? jz qq ; if so then promote pawn to queen cmp _b [si+3],'1' ; validated dst rank is bottom-most ? jnz prm ; if not no pawn queening promotion qq: sahf ; store piece nature in flag register jnp prm ; no pawn queening promotion xor ah,01000110b ; transform p to promoted queen inc cx ; queen promotion p2q or P2Q end if ; end of conditional queening prm:xchg ah,[si+bx+brd-num-'a'+8] ; update piece logical 0x88 board val xchg cl,[si+bx+brd-num-'a'] ; update piece physical board ascii val or ah,1 ; update piece moved once (bit#0) sim:retn ; return to caller(s) mat:sahf ; catured piece king and mate ? js xit ; if piece is king then game is over call chk ; move src color conforming ? jnz nok ; move src color not conforming chk:xchg bx,dx ; src idx <- dst idx mov al,[si+bx+brd-num-'a'] ; pass#1:src idx pass#2:dst idx di=brd xor _b [si+len-num],8 ; self-modif 8/26 val=[1;8]/[a(A);z(Z)] mov cl,-'a' ; assert black piece car interval test bp,bp ; test whose turn it is to play jnz lim ; assert white piece car interval mov cl,-'A' ; al=ascii value cl=-(lower boundery) lim:xadd al,cl ; tmp=al+cl cl=al al=tmp +fall-trough db 0d4h ; aam <self-modified value> len:db 12h ; ah=al/8 al%=8 mov al,cl ; al=restored ascii value test ah,ah ; set/clear zf=0 success zf=1 failure retn ; return to caller(s) nb: destroys ah tab db p-tab,r-tab,n-tab,b-tab ; piece type mov offset array db q-tab,q-tab ; note original 1K ZX Chess q=k trick br0 db "rnbqkbnr",8,16,32,64,128 ; end rank pattern + beg piece values db 32,16,8,'p',4,'.',0,'.',0 ; end piece values + beg mid board reps db '.',0,'.',0,'P',4 ; ... end mid board reps p db 2,3,-10h,-15,-17,10h,15 ; bit#2 pf=04 p[6]=r[0] overlay r db 17,4,10h,-1h,-10h ; bit#3 ??=08 r[5]=n[0] overlay n db 1,8,1fh,21h,12h,-0eh,-1fh ; bit#4 af=16 n[9]=b[0] overlay db -21h,-12h ; ... end of knight moves list b db 0eh,4,-0fh,11h,-11h ; bit#5 ??=32 b[5]=q[0] overlay q db 0fh,8,10h,11h,0fh,1h,-10h ; bit#6 zf=64 k=q except k[0]=1 db -11h,-0fh,-1h ; ... end of queen/king moves list bf1 db "abcdefgh" ; gui file index string num db "e2e4" ; hardcoded Ruy Lopez opening if saf and x86 ; x86 failsafe exotic boot environment times 510-($-$$) db 0 ; nul padding if necessary org 7df0h ; boot signature vbr/mbr standard offset sig db 55h,0aah ; magic number no-endian boot signature end if ; end of conditional failsafe signature ;-BootChess.asm-------------------;----------------------------------------- ; Greets to Abrasax/Quartex, Alk/Titan, Alpha Flight, Astrofra/Mandarine, ; Carbon/Atari Active, Calsoft/Psycho Hacking Force, CiH/Alive Team, Codex, ; Cronos/Amazing Cracking Conspiracy, Cyg/BlaBla, D-Bug,Dbug/Defence Force, ; Dma-Sc/M4nkind, Defjam/Checkpoint, Den/Top Right Bottom Left,Felice/Alive ; Team, Feust/Red Sector Inc., Floyd/Surprise productions, Flure/Popsy Team ; FroST/Red Sector Inc., Gengis/Bomb, GGN/KUA Soft, Grazey/Psycho Hacking ; Force, Havoc/LineOut, HellMood/Desire, Hitch Hikr/Skidrow, Hotshot/Dark ; Bit Factory, Imerso/Red Sector Inc., Irokos/Titan, KiNG1/Red Sector Inc., ; Kirl/Dark Bit Factory, Leon Bli/Red Sector Inc., Lexomil/Red Sector Inc., ; Lotek Style/tSCc, Made/Bomb, MMyErs/Red Sector Inc., Okkie/Accession, P01 ; /Ribbon, P0ky/Flush, Pasy/Rebels, Photon/Scoopex, Principal/American ; Cracking Association, Ramon B5/Desire, Raizor/fnuque, Rez/Razor 1911, ; RiOT, Sam/Debian, ShockWave/Dark Bit factory, Sim/Resistance, Skamp ; /Vacuum, Skeleton/The Pirate Ship, Skywalker/Paradox, SnC/Red Sector Inc. ; Stingray/Scoopex, Thorin/Melon Dezign., Tinker/LineOut, TomoAlien/Bon ; Squared, t0my/Live!, Troy/Sensensthal, Ttemper/Red Sector Inc., UkkO ; /Live!, Val/@party, Wullon/adinpsz, Wietze/#atariscne, Xeu/EXA, XiA ; /Checkpoint, XXX/Haujobb, Zerkman/Sector One... And all assembly coders !
[ back to the prod ]