Skip to content

Instantly share code, notes, and snippets.

@rmmh
Forked from anonymous/options.json
Last active October 6, 2015 01:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmmh/c660fd132433a947a88e to your computer and use it in GitHub Desktop.
Save rmmh/c660fd132433a947a88e to your computer and use it in GitHub Desktop.
{"tickrate":15,"fillColor":"#222","backgroundColor":"#CC8","buzzColor":"#FFAA00","quietColor":"#000000","shiftQuirks":false,"loadStoreQuirks":false}
# Chip8 Chess
# Ryan Hitchman, Dec 2014
:alias selectedpos vA
:alias cursorpos vB
:alias piecepos vC
:alias piece vD
:alias undopos v9
:alias rayoff v6
:alias rayind v7
:alias scanpos v8
: main
hires
cursorpos := 0x46
selectedpos := -1
clear
draw-board
draw-pieces
loop
draw-cursor
handle-keys
again
: draw-pos # (pos:v0 image:i -- x:v0 y:v1)
v1 := 0b01110000
v1 &= v0
v1 >>= v1
v0 <<= v0
v0 <<= v0
v0 <<= v0
v0 <<= v0 v0 >>= v0 # strip MSB
v0 += 32
sprite v0 v1 8
;
: draw-cursor
i := cursor
v0 := cursorpos
draw-pos
v0 += -1
i := line
sprite v0 v1 8
;
: draw-board
# draw guidelines on left/right
v0 := 0 # y
v1 := 30 # left
v2 := 96 # right
i := line
loop
sprite v1 v0 8
sprite v2 v0 8
v0 += 8
if v0 != 64 then again
# now draw grid pixels
v0 := 7 # y
v1 := 31 # x
loop
loop
sprite v1 v0 1
v1 += 8
if v1 != 103 then
again
v1 := 31
v0 += 8
if v0 != 71 then
again
;
: draw-piece # (piecepos -- v0:x v1:y)
i := board
i += piecepos
load v0
if v0 != 0 begin
i := board-sprites
# i := board-sprites[piece/2]
v0 >>= v0
i += v0
v0 := piecepos
draw-pos
end
;
: draw-pieces
piecepos := 0
loop
draw-piece
# deep magic
# pos is 0b0YYY0XXX, so if XXX overflows
# it will cascade into incrementing Y
piecepos += 0b00001001
v0 := 0b11110111
piecepos &= v0
# if Y overflowed into the MSB, we're done
v0 <<= piecepos
if vF == 0 then again
;
: handle-keys
v3 := key
draw-cursor
v0 <<= v3
v1 := 0b01110111 # mask for keys
jump0 key-handlers
: key-handlers
; ; ; ; # x 1 2 3
; jump move-up jump select-piece # q w e
jump move-left jump move-down jump move-right # a s d
jump undo-move ; ; # z c 4
; ; ; # r f v
# use 3-bit two's complement to overflow instead of borrowing
: move-left cursorpos += 0b00000111 cursorpos &= v1 ;
: move-right cursorpos += 0b00000001 cursorpos &= v1 ;
: move-up cursorpos += 0b01110000 cursorpos &= v1 ;
: move-down cursorpos += 0b00010000 cursorpos &= v1 ;
: select-piece
# is this a position we can move to?
i := cursor-probe
v0 := cursorpos
draw-pos
v2 := vF
v0 := cursorpos
draw-pos # erase probe
if v2 == 1 begin
move-piece
selectedpos := -1
else
if selectedpos != -1 then gen-moves
if cursorpos == selectedpos begin
# unselect piece
selectedpos := -1
return
end
piecepos := cursorpos
selectedpos := cursorpos
gen-moves
end
;
: move-piece # move piece (selectedpos => cursorpos)
piecepos := cursorpos
v3 := 0
v1 := -1
draw-piece # (maybe) erase captured piece
if v1 != -1 begin
# capturing a piece; push undo info
# LITERAL: AAAAAAA0 BBBBBBBM
v3 := 1 # remember that we're capturing
v1 <<= piecepos
i := board
i += piecepos
load v0
undo-push
end
# moving a piece; push undo info
# MOVE: AAAAAAA1 BBBBBBBM
v1 := 1
v0 <<= cursorpos
v0 |= v1 # A...A1 for move
v1 <<= selectedpos
# if we're capturing, there's a previous command
v1 |= v3
undo-push
#:breakpoint capture-erased
piecepos := selectedpos
gen-moves # erase threats
#:breakpoint threats-erased
draw-piece # erase moving piece
i := board
i += selectedpos
load v0
v1 := v0
i := board
i += selectedpos
v0 := 0
save v0
#:breakpoint moving-erased
v0 := v1
i := board
i += cursorpos
save v0
piecepos := cursorpos
draw-piece # draw new piece
;
: maybe-test-scanpos
# check for out-of-bounds
v0 := 0b10001000
v0 &= scanpos
if v0 == 0 then jump test-scanpos
v0 := 0
v1 := 0
return
: test-scanpos # (scanpos -- v0:empty, v1:capture)
i := board
i += scanpos
load v0
if v0 == 0 begin
v0 := 1
v1 := 0
else
# there's a piece here. is it an opponent's piece that we can capture?
v1 := v0
v1 ^= piece
v1 <<= v1
v1 := vF
v0 := 0
end
;
: gen-moves
i := board
i += piecepos
load v0
piece := v0
# TODO: side check
if piece == 0 then return
rayind := 0b01111111
rayind &= piece
if rayind == 0x40 begin # is it a pawn?
# move up or down based on side
rayoff := -16
v0 <<= piece
if vF == 1 then rayoff := 16
scanpos := piecepos
scanpos += rayoff
test-scanpos
if v0 == 1 begin
emit-move
# are we at the starting rank for the pawn?
v0 := 0b01110000
v0 &= piecepos
v1 := 0x60
if rayoff == 16 then v1 := 0x10
if v0 == v1 begin
scanpos += rayoff
test-scanpos
if v0 == 1 then emit-move
end
end
# TODO: en-passant
scanpos := piecepos
scanpos += rayoff
scanpos += -1
maybe-test-scanpos
if v1 == 1 then emit-move
scanpos += 2
maybe-test-scanpos
if v1 == 1 then emit-move
return
end
# TODO: castling
loop # foreach ray directions
i := offset-base
i += rayind
load v0
while v0 != 0 # end of ray table
rayoff := v0
rayind += 1
scanpos := piecepos
loop # slide along
scanpos += rayoff
# piece offset is 0rrr0fff, so moving off the board can be detected
# by testing for overflow/underflow into side bits
v0 := 0b10001000
v0 &= scanpos
while v0 == 0
test-scanpos
if v1 == 1 then emit-move
if v0 == 1 begin
emit-move
# knights (5) and kings (6) only move once
v0 := 0b01000000
v0 &= piece
if v0 == 0 then
again
end
# check if we've already done 8 rays
v0 := 0b1000
v0 &= rayind
if v0 == 0 then
again
;
: emit-move
i := cursor-threat
v0 := scanpos
draw-pos
;
# The undo stack allows reverting any change in the board state.
# It supports two commands:
# Place value A*2 at B: AAAAAAA0 BBBBBBBM
# Move byte from A to B: AAAAAAA1 BBBBBBBM
# Positions are indexes into the board.
# M is set if there is another command in this move.
# Note that 0x0 0x0 is a harmless no-op!
: undo-move
loop
undo-pop
v3 >>= v1
v4 := vF # last command?
v2 >>= v0
if vF == 1 begin # move byte
i := board
i += v2
load v0
piecepos := v2
v2 := v0
draw-piece # trashes v0, v1
v0 := 0
i := board
i += piecepos
save v0
v0 := v2
end
# else case: literal value
# v0 already holds the correct value
i := board
i += v3
save v0
piecepos := v3
draw-piece
if v4 == 1 then again
;
: undo-push # (v0 v1 -- )
i := undo-stack
i += undopos
save v1
undopos += 2
;
: undo-pop # ( -- v0 v1 )
undopos += -2
i := undo-stack
i += undopos
load v1
;
# piece is: SPPP0000, where S is 0/1 for white/black, and P is piece number [1-6]
# board is 8x16, with piece index 0rrr0fff
# this allows the 0x88 optimization, where invalid positions can be detected
# by checking for overflow into the 0 bits
# (and we can stuff some useful data on the side)
: board
0x90 0xD0 0xA0 0xB0 0xE0 0xA0 0xD0 0x90
: offset-base 0 0 0 0 0 0 0 0
0xC0 0xC0 0xC0 0xC0 0xC0 0xC0 0xC0 0xC0
: rook-offset -16 -1 1 16 0 0 0 0
0 0 0 0 0 0 0 0
: bishop-offset -17 -15 15 17 0 0 0 0
0 0 0 0 0 0 0 0
: queen-offset -17 -16 -15 -1 1 15 16 17
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 # pawn-offset, special-cased
0 0 0 0 0 0 0 0
: knight-offset -33 -31 -18 -14 14 18 31 33
0x40 0x40 0x40 0x40 0x40 0x40 0x40 0x40
: king-offset -17 -16 -15 -1 1 15 16 17
0x10 0x50 0x20 0x30 0x60 0x20 0x50 0x10
: board-sprites # this is indexed by piece/2, but 0x00, 0x70, and 0x80 are invalid pieces
: line 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 # invalid piece 0x00
: white-rook 0xaa 0xd6 0x82 0x44 0x44 0x82 0xfe 0x00
: white-bishop 0x7c 0x92 0xba 0x92 0x54 0x82 0xfe 0x00
: white-queen 0xaa 0xaa 0xaa 0x7c 0x44 0x82 0xfe 0x00
: white-pawn 0x38 0x44 0x44 0x28 0x44 0x82 0xfe 0x00
: white-knight 0x14 0x68 0x94 0xc4 0x22 0x42 0xfe 0x00
: white-king 0x10 0x38 0x92 0xee 0x44 0x82 0xfe 0x00
: cursor 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff # invalid piece 0x70
: cursor-threat 0x00 0x00 0x3A 0x28 0xB8 0x00 0x00 0x00 # invalid piece 0x80
: black-rook 0xaa 0xfe 0xfe 0x7c 0x7c 0xfe 0xfe 0x00
: black-bishop 0x7c 0xee 0xc6 0xee 0x6c 0xfe 0xfe 0x00
: black-queen 0xaa 0xaa 0xaa 0x7c 0x7c 0xfe 0xfe 0x00
: black-pawn 0x38 0x7c 0x7c 0x38 0x7c 0xfe 0xfe 0x00
: black-knight 0x14 0xe8 0xf8 0x38 0x7c 0xfe 0xfe 0x00
: black-king 0x10 0x38 0x92 0xfe 0x7c 0xfe 0xfe 0x00
# this bit is set by cursor-threat, but not by any of the pieces
: cursor-probe 0x00 0x00 0x00 0x00 0x80 0x00 0x00 0x00
: undo-stack # use the rest of memory
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment