gigatron/rom/Contrib/tbraun-de/gasm/maze.gasm
2025-01-28 19:17:01 +03:00

414 lines
14 KiB
Plaintext

%include ../../at67/gasm/macros/gigatron.i
%include ../../at67/gasm/macros/macros.i
vram EQU 0x0800
vpc EQU 0x16
rand_x1 EQU 0x06
rand_y1 EQU 0x07
rand_x2 EQU 0x08
rand_y2 EQU 0x0b
rand EQU 0x06
base EQU 0x30
xypos EQU 0x32
x EQU 0x32
y EQU 0x33
tryxypos EQU 0x34
tryx EQU 0x34
tryy EQU 0x35
visited_pix EQU 0x36
direction EQU 0x38 ; 0 = right, 1 = down, 2 = left, 3 = top
dir_count EQU 0x39
RIGHT EQU 0x00
DOWN EQU 0x01
LEFT EQU 0x02
TOP EQU 0x03
CLEAR EQU 0x00
VISITED EQU 0x0F
BACKTRACKED EQU 0x0C
WALL EQU 0x3F
MAZE_WIDTH EQU 79
MAZE_HEIGHT EQU 59
WAY_LEN EQU 0x03
_startAddress_ EQU 0x0200 ; entry point for the code, if this is missing defaults to 0x0200
_callTable_ EQU 0x007E ; call addresses are automatically stored here by the assembler, it grows downwards,
; make sure it doesn't crash into anything important
_singleStepWatch_ EQU vpc ; the single step debugger watches this variable location to decide when to step,
; choose a variable that is updated often
start EQU 0x0200
init_startpixel EQU 0x0300
find_visited EQU 0x0400
ii EQU 0x30
jj EQU 0x31
kk EQU 0x32
ll EQU 0x33
xx EQU 0x34
yy EQU 0x35
; clears the viewable screen
; created by at67, see https://github.com/kervinck/gigatron-rom/blob/master/Contrib/at67/gasm/clearscreen.gasm
clearScreen LDWI SYS_Draw4_30 ; setup 4 pixel SYS routine
STW giga_sysFn
LDWI 0x0000 ; 4 y of colour
STW giga_sysArg0
STW giga_sysArg2
LDI giga_yres / 2 ; counters
ST jj
LDI giga_xres / 4
ST ii
LDWI 0x0800 ; top line
STW xx
LDWI 0x7F00 ; bottom line
STW kk
clearS_loop LDW xx
STW giga_sysArg4 ; top line
SYS 0xFF ; SYS_Draw4_30, 270 - 30/2 = 0xFF
LDW kk
STW giga_sysArg4 ; bottom line
SYS 0xFF ; SYS_Draw4_30, 270 - 30/2 = 0xFF
LD xx ; 4 horizontal y
ADDI 0x04
ST xx
LD kk ; 4 horizontal y
ADDI 0x04
ST kk
LoopCounterTo1 ii clearS_loop
INC yy ; next top line
LD ll ; next bottom line
SUBI 0x01
ST ll
LDI 0x00 ; reset xx, kk and ii
ST xx
ST kk
LDI giga_xres / 4
ST ii
LoopCounterTo1 jj clearS_loop
; initialize the maze walls and starting point
CALL init_walls
CALL init_startpixel
step_maze LDW xypos ; detect if at least one neighboring pixel is still CLEAR
STW tryxypos ; if so: continue drawing a path
; if not: mark the current pixel as BACKTRACKED
; continue backtracking with the neighbouring pixel with state VISITED
CALL find_clear ; vAC will be "0" if we found a clear pixel
BEQ cont_drawing ; if so, continue with drawing the next step
; if not:
LDW xypos ; detect if at least one neighboring pixel is VISITED and try backtracking one step
STW tryxypos
CALL find_visited ; try to find a visited pixel next to the current one. when no VISITED pixel is found, the labyrinth is done!
BEQ clearScreen ; if so (when find_visited returns with 0 in vAC): restart from scratch
LDW tryxypos
STW xypos
BRA step_maze
cont_drawing LD dir_count ; test if we should change the preferred direction
BNE cont_right
CALL rand_dir
cont_right LDW xypos
STW tryxypos
LD direction
BNE cont_with_down ; direction = 0?
CALL try_right ; --> right
BRA step_maze
cont_with_down LD direction
SUBI 1
BNE cont_with_left ; direction = 1?
CALL try_down ; --> down
BRA step_maze
cont_with_left LD direction
SUBI 2
BNE cont_with_up ; direction = 2?
CALL try_left ; --> left
BRA step_maze
cont_with_up CALL try_up ; else --> up
BRA step_maze
; -- 0x0300 initialization and drawing forward --
; Initialize the maze walls and the start position
init_walls LDWI vram
STW xypos
horiz_walls LDI WALL
POKE xypos
LD y
ADDI MAZE_HEIGHT * 2
ST y
LDI WALL
POKE xypos
LD y
SUBI MAZE_HEIGHT * 2
ST y
INC x
LD x
SUBI MAZE_WIDTH * 2
BEQ init_vert_walls
BRA horiz_walls
init_vert_walls LDWI vram
STW xypos
vert_walls LDI WALL
POKE xypos
LD x
ADDI MAZE_WIDTH * 2
ST x
LDI WALL
POKE xypos
LD x
SUBI MAZE_WIDTH * 2
ST x
INC y
LD y
SUBI MAZE_HEIGHT * 2 + 9
BNE vert_walls
RET
init_startpixel LDWI vram ; mark the start pixel as visited
STW xypos
INC x
INC x
INC y
INC y
LDI VISITED
POKE xypos
LDI 0x00
ST direction ; initialize direction and counter for times a certain direction was chosen
LDI WAY_LEN
ST dir_count
RET
# maze calculation functions
rand_dir LDWI SYS_Random_34 ; randomize a new direction
STW 0x22
SYS 253
LD rand
ANDI 0x03
ST direction
LDI WAY_LEN
ST dir_count
RET
try_right INC tryx ; test if the pixel is still clear
INC tryx
LDW tryxypos
PEEK
BEQ mark_right ; if the pixel is clear: draw a way to this pixel
BRA rand_dir ; if not: try a new random direction and return
mark_right INC x
LDI VISITED
POKE xypos
INC x
POKE xypos
BRA ret_after_mark
try_down INC tryy ; test if the pixel is still clear
INC tryy
LDW tryxypos
PEEK
BEQ mark_down ; if the pixel is clear: draw a way to this pixel
BRA rand_dir ; if not: try a new random direction and return
mark_down INC y
LDI VISITED
POKE xypos
INC y
POKE xypos
BRA ret_after_mark
try_left LD tryx ; test if the pixel is still clear
SUBI 2
ST tryx
LDW tryxypos
PEEK
BEQ mark_left ; if the pixel is clear: draw a way to this pixel
BRA rand_dir ; if not: try a new random direction and return
mark_left LD x
SUBI 1
ST x
LDI VISITED
POKE xypos
LD x
SUBI 1
ST x
LDI VISITED
POKE xypos
BRA ret_after_mark
try_up LD tryy ; test if the pixel is still clear
SUBI 2
ST tryy
LDW tryxypos
PEEK
BEQ mark_up ; if the pixel is clear: draw a way to this pixel
BRA rand_dir ; if not: try a new random direction and return
RET
mark_up LD y
SUBI 1
ST y
LDI VISITED
POKE xypos
LD y
SUBI 1
ST y
LDI VISITED
POKE xypos
ret_after_mark LD dir_count
SUBI 1
ST dir_count
RET
; find a clear pixel around tryxypos
find_clear LD tryx ; is left pixel clear?
SUBI 2
ST tryx
LDW tryxypos
PEEK
BEQ ret_clear_found
LD tryx ; is right pixel clear?
ADDI 4
ST tryx
LDW tryxypos
PEEK
BEQ ret_clear_found
LD tryx ; is upper pixel clear
SUBI 2
ST tryx
LD tryy
SUBI 2
ST tryy
LDW tryxypos
PEEK
BEQ ret_clear_found
LD tryy ; is lower pixel clear
ADDI 4
ST tryy
LDW tryxypos
PEEK
BEQ ret_clear_found
LDI 1 ; We didn't find a clear pixel, return with 1 in vAC
RET
ret_clear_found LDI 0 ; indicate that we found a clear pixel and don't need to backtrack
RET
; 0x400
; find a visited pixel around tryxypos
find_visited LD tryx ; is left pixel VISITED?
SUBI 1
ST tryx
LDW tryxypos
PEEK
SUBI VISITED
BEQ left_visited
LD tryx ; is right pixel VISITED?
ADDI 2
ST tryx
LDW tryxypos
PEEK
SUBI VISITED
BEQ right_visited
LD tryx ; is upper pixel VISITED
SUBI 1
ST tryx
LD tryy
SUBI 1
ST tryy
LDW tryxypos
PEEK
SUBI VISITED
BEQ up_visited
LD tryy ; is lower pixel VISITED
ADDI 2
ST tryy
LDW tryxypos
PEEK
SUBI VISITED
BEQ down_visited
; no pixel was visited!
LD tryy
SUBI 1
ST tryy
LDI 0 ; return with 0 in vAC
RET
left_visited INC tryx
LDI BACKTRACKED
POKE tryxypos
LD tryx
SUBI 1
ST tryx
LDI BACKTRACKED
POKE tryxypos
LD tryx
SUBI 1
ST tryx
LDI 1 ; return with 1 in vAC
RET
right_visited LD tryx
SUBI 1
ST tryx
LDI BACKTRACKED
POKE tryxypos
INC tryx
LDI BACKTRACKED
POKE tryxypos
INC tryx
LDI 1 ; return with 1 in vAC
RET
up_visited INC tryy
LDI BACKTRACKED
POKE tryxypos
LD tryy
SUBI 1
ST tryy
LDI BACKTRACKED
POKE tryxypos
LD tryy
SUBI 1
ST tryy
LDI 1 ; return with 1 in vAC
RET
down_visited LD tryy
SUBI 1
ST tryy
LDI BACKTRACKED
POKE tryxypos
INC tryy
LDI BACKTRACKED
POKE tryxypos
INC tryy
LDI 1 ; return with 1 in vAC
RET