Код:
;;; 2048 game for CHIP-8
;;;
;;; The board is stored as 16 consecutive bytes, each with a value between 0 and 11
;;; 0 is an empty tile
;;; 1..10 is a tile with values 2..1024
;;; 11 is the target tile: as soon as we get an 11 tile, the user has won
;;;
START:
call NEWGAME
call DRAW_GRID
call PLACE_RANDOM_TILE
call PLACE_RANDOM_TILE
;; call SLIDE_UP
;; call BLIT
;; call DRAW
LOOP:
call DRAW
key va
call DRAW
ld vd, 0
skne va, 6
call SLIDE_RIGHT
skne va, 4
call SLIDE_LEFT
skne va, 8
call SLIDE_DOWN
skne va, 2
call SLIDE_UP
skeq vd, 0
call PLACE_RANDOM_TILE
jmp LOOP
DRAW_GRID:
mvi GRID
ld v1, 0 ; K := 0
ld v2, 15 ; X := 15
ld v3, 0 ; Y := 0
DRAW_GRID_LOOP:
skne v1, 16 ; while (K != 16)
ret
drw v2, v3, 8
add v1, 1 ; K += 1
add v2, 8 ; X += 8
skeq v2, 47
jmp DRAW_GRID_LOOP
;; Start new row
mvi GRID_RIGHT
drw v2, v3, 8
ld v2, 15 ; X := 15
add v3, 8 ; Y += 8
mvi GRID
skne v3, 24 ; for bottommost row, use special sprite
mvi GRID_BOTTOM
jmp DRAW_GRID_LOOP
BLIT:
ld v1, 0
BLIT_LOOP:
skne v1, 16
ret
mvi NEW_BOARD
adi v1
ldr v0
mvi BOARD
adi v1
str v0
ld v0, 0
mvi NEW_BOARD
adi v1
str v0
add v1, 1
jmp BLIT_LOOP
;;; ROTATE
;;;
;;; Maps
;;;
;;; 0123
;;; 4567
;;; 89ab
;;; cdef
;;;
;;; to
;;;
;;; c840
;;; d951
;;; ea62
;;; fd73
;;;
;;; Use: V0: TMP
;;; V1: K
;;; V2: K'
;;; V3: ROW
;;; V4: NEW_ROW
ROTATE:
call ROTATE_INT
call BLIT
ret
ROTATE_INT:
ld v1, 0
ld v2, 3
ld v3, 3
ROTATE_LOOP:
skne v1, 16
ret
mvi BOARD ; TMP := BOARD[K]
adi v1
ldr v0
mvi NEW_BOARD ; NEW_BOARD[K'] := TMP
adi v2
str v0
add v1, 1 ; K += 1
add v2, 4 ; K' += 4
ld v4, $11 ; New row?
and v4, v1
skeq v4, 0
jmp ROTATE_LOOP
sub v3, 1 ; ROW -= 1
ld v2, v3 ; K' := ROW
jmp ROTATE_LOOP
;;; SLIDE_LEFT
;;; Vars: V0: TMP
;;; V1: K
;;; V2: K'
;;; V3: LAST
;;; V4: END_ROW
;;; V5: ROW
;;; V6: MATCH
SLIDE_LEFT:
call SLIDE_LEFT_INT
call BLIT
ret
SLIDE_LEFT_INT:
ld v1, 0 ; K := 0
ld v2, 0 ; K' := 0
ld v3, 0 ; LAST := 0
ld vf, 0 ; WIN := 0
ld v5, 0 ; ROW := 0
SLIDE_LEFT_ROW:
skne v1, 16
ret
mvi BOARD ; TMP := BOARD[K]
adi v1
ldr v0
skne v0, 0
jmp SLIDE_LEFT_NEXT
ld v6, 0
skne v0, v3
ld v6, 1
skne v6, 1 ; IF TMP == LAST then MERGE_LEFT
call MERGE_LEFT
skeq v6, 1
ld v3, v0
mvi NEW_BOARD ; NEW_BOARD[K'] := TMP'
adi v2
str v0
skeq v1, v2 ; vd |= v1 == v2
ld vd, 1
add v2, 1 ; K' += 1
SLIDE_LEFT_NEXT:
add v1, 1 ; K += 1
ld v4, $11 ; New row?
and v4, v1
skeq v4, 0
jmp SLIDE_LEFT_ROW
add v5, 1 ; ROW += 1
ld v3, 0 ; LAST := 0
ld v2, 0 ; K' := ROW * 4
skne v5, 1
ld v2, 4
skne v5, 2
ld v2, 8
skne v5, 3
ld v2, 12
jmp SLIDE_LEFT_ROW
SLIDE_DOWN:
call ROTATE
call SLIDE_LEFT
call ROTATE
call ROTATE
call ROTATE
ret
SLIDE_RIGHT:
call ROTATE
call ROTATE
call SLIDE_LEFT
call ROTATE
call ROTATE
ret
SLIDE_UP:
call ROTATE
call ROTATE
call ROTATE
call SLIDE_LEFT
call ROTATE
ret
;;; MERGE
;;; InOut: V0: TMP
;;; V2: K'
;;; V3: LAST
MERGE_LEFT:
add v0, 1
ld v3, 0
sub v2, 1
ret
;;; DRAW_TILE
;;; In: V1: K
;;; V2: X
;;; V3: Y
;;; Use: V0: TMP
DRAW_TILE:
mvi BOARD ; TMP := BOARD[K]
adi V1
ldr V0
skne v0, 0 ; if TMP == 0 then done
ret
sub v0, 1 ; drw digit for TMP-1 at (X, Y)
font v0
drw v2, v3, 5
ret
DRAW:
ld v1, 0 ; K := 0
ld v2, 15+3 ; X := 15+3
ld v3, 0+2 ; Y := 0+2
DRAW_LOOP:
skne v1, 16 ; while (K /= 16)
ret
call DRAW_TILE
add v1, 1 ; K += 1
add v2, 8 ; X += 8
skeq v2, (3*16-1)+3 ; Start new row?
jmp DRAW_LOOP
ld v2, 15+3 ; X := 15+3
add v3, 8 ; Y += 8
jmp DRAW_LOOP
;;; PLACE_RANDOM_TILE
PLACE_RANDOM_TILE:
rnd v2, 7 ; Place a 1 tile with prob 1/8 and a 0 tile with prob 7/8
ld vb, 1
skne v2, 0
ld vb, 2
call PLACE_TILE
ret
;;; PLACE_TILE
;;; Input: VB: TILE
;;; Use: V0: TMP
;;; V1 : K
;;; V2 : TARGET
PLACE_TILE:
rnd v2, 15
;; Pick TARGET'th empty square
ld v1, -1
PLACE_TILE_SCAN:
add v1, 1
skne v1, 16
ld v1, 0
mvi BOARD ; TMP := BOARD[K]
adi v1
ldr V0
skeq V0, 0 ; If TMP == 0 then next
jmp PLACE_TILE_SCAN
sub v2, 1 ; Is this the TARGET'th empty square?
skeq v2, 0
jmp PLACE_TILE_SCAN
ld v0, vb ; BOARD[K] := TILE
str v0
ret
;;; NEWGAME: fill BOARD with zeroes
NEWGAME:
ld v1, 0
ld v0, 0
NEWGAME_LOOP:
skne v1, 16
ret
mvi BOARD
adi v1
str v0
add v1, 1
jmp NEWGAME_LOOP
BOARD:
.ds 16
NEW_BOARD:
.ds 16
GRID: defb %11111111
defb %10000000
defb %10000000
defb %10000000
defb %10000000
defb %10000000
defb %10000000
defb %10000000
GRID_BOTTOM:
defb %11111111
defb %10000000
defb %10000000
defb %10000000
defb %10000000
defb %10000000
defb %10000000
defb %11111111
GRID_RIGHT:
defb %10000000
defb %10000000
defb %10000000
defb %10000000
defb %10000000
defb %10000000
defb %10000000
defb %10000000