_TITLE "Escape from Monster Maze" 'B+ 2019-09-03 ' 2019-08-31 attempt a better, smoother mouser
' 2019-09-03 Maze geneartion, nice mouse and arrow key action,
' momentum removed, just cant turn corners that fast.
' 2019-09-03 Troubles
' I either have to loose arrow keys or deactivate mouse or something
' so arrow key presses are defeated by mouse presence. :-P
' and still not 100% happy with mouse action. ;(
' I kicked out walls randomly several for each new monster but not effective for creating
' alternate paths when dang monsters are ganging up at upper left corner, yikes! no escape!!!
' to fix that
' 1. lay out another generated maze over top of current that will create meaningfull alternate route
' 2. relocate monsters when my guy gets back to start!
' Ok I fixed it so if you start using arrow keys the mouse is disabled for 3 seconds from last arrow press
' using Luke's time stamp. This way the mouse position wont counteract arrow key presses.
' HEY I think XOR smoothed out the mouse action a tiny bit!!! and so did opening up angles
' directions from mouse to full 90 degrees around 0, 90, 180, 270.
CONST xmax
= 700, ymax
= 700 'screen CONST W
= 15, H
= 15, border
= 50 'maze cells wide and high CONST mazeClr
= &HFFFF8800
DIM SHARED stopTime&
'disable mouse influence of player position for 3 sec from last arrow key cellW = (xmax - 2 * border) / W
cellH = (ymax - 2 * border) / H
' Locals for Main module code
DIM px
, py
, mx
, my
, k$
, d
, a
, start
, i
, j
, nMonsters
, test
AS cell
, tmp
AS LONG, wayt
nMonsters = 3
init_walls
generate_maze
'open gate a bottom right corner to esacpe
h_walls(W - 1, H) = 0
nMonsters = nMonsters + 1
m
(i
).x
= RND * 7 * W
/ 8 + W
/ 8 - 1: m
(i
).y
= RND * 7 * H
/ 8 + H
/ 8 - 1 FOR j
= 1 TO 2 'for every monster make 4 escape hatches test.x
= INT(RND * (W
- 2)) + 1: test.y
= INT(RND * (H
- 2)) + 1 WHILE h_walls
(test.x
, test.y
) = 0 test.x
= INT(RND * (W
- 2)) + 1: test.y
= INT(RND * (H
- 2)) + 1 h_walls(test.x, test.y) = 0
test.x
= INT(RND * (W
- 2)) + 1: test.y
= INT(RND * (H
- 2)) + 1 WHILE v_walls
(test.x
, test.y
) = 0 test.x
= INT(RND * (W
- 2)) + 1: test.y
= INT(RND * (H
- 2)) + 1 v_walls(test.x, test.y) = 0
px
= 0: py
= 0: start
= TIMER show_maze
'fcirc (m(i).x + .5) * cellW + border, (m(i).y + .5) * cellH + border, cellH / 3, &HFFFF0000
monster1 (m(i).x + .5) * cellW + border, (m(i).y + .5) * cellH + border
monster2 (m(i).x + .5) * cellW + border, (m(i).y + .5) * cellH + border
IF h_walls
(m
(i
).x
, m
(i
).y
) = 0 THEN m
(i
).y
= m
(i
).y
- 1 IF h_walls
(m
(i
).x
, m
(i
).y
+ 1) = 0 THEN m
(i
).y
= m
(i
).y
+ 1 IF v_walls
(m
(i
).x
+ 1, m
(i
).y
) = 0 THEN m
(i
).x
= m
(i
).x
+ 1 IF v_walls
(m
(i
).x
, m
(i
).y
) = 0 THEN m
(i
).x
= m
(i
).x
- 1 'fcirc (px + .5) * cellW + border, (py + .5) * cellH + border, cellH / 3, &HFFFFFFFF 'draw player
makeFace (px + .5) * cellW + border, (py + .5) * cellH + border, 1
px = 0: py = 0
d = 0
'if the mouse is near the player then it will act as magnet drawing player to it unless wall in way
IF ABS(mx
- px
) <> 0 XOR ABS(my
- py
) <> 0 THEN 'ah ha XOR smooths it out a bit d = 0
'debug
'LOCATE 1, 1: PRINT SPACE$(100)
'LOCATE 1, 1: PRINT px, py, mx, my, mouseOK(0), timestamp&, stopTime&
k$
= INKEY$ 'key press takes precedence over mouse SELECT CASE ASC(k$
, 2) 'turn off mouse control for 3 secs after arrow press CASE 72: d
= 1: tmp
= mouseOK
(1) 'up CASE 80: d
= 2: tmp
= mouseOK
(1) 'down CASE 77: d
= 3: tmp
= mouseOK
(1) 'right CASE 75: d
= 4: tmp
= mouseOK
(1) 'left ' _____ ________
' |x, y |x+1, y the walls of the cell x, y are at right and above,
' ________ x+1 has the next wall and y+1 is the next horizontal separator
' |x, y+1
IF h_walls
(px
, py
) = 0 THEN py
= py
- 1 IF h_walls
(px
, py
+ 1) = 0 THEN py
= py
+ 1 IF v_walls
(px
+ 1, py
) = 0 THEN px
= px
+ 1 IF v_walls
(px
, py
) = 0 THEN px
= px
- 1 'fcirc (px + .5) * cellW + border, (py + .5) * cellH + border, cellH / 3, &HFF0000FF 'draw player
makeFace (px + .5) * cellW + border, (py + .5) * cellH + border, 0
_PRINTSTRING (xmax
- 580, ymax
- 20), "You escaped in" + STR$((TIMER - start
) \
1) + " secs, press any to continue" wayt = 1
FUNCTION mouseOK%
(mode%
) '1 set, 0 checks if time is up yes -1, no 0 stopTime& = timestamp& + 3 '3 secs before mouse access
IF timestamp&
- stopTime&
> 0 THEN mouseOK%
= -1 ELSE mouseOK%
= 0
FUNCTION timestamp&
'try Luke's Timestamp for checking times timestamp& = time&(0)
SUB makeFace
(x
, y
, white
) IF white
THEN fcirc x
, y
, cellW
/ 3, &HFF994422 ELSE fcirc x
, y
, cellW
/ 3, &HFFAABBFF fcirc x - 3 * cellW / 24, y, cellW / 14, &HFF0000FF
fcirc x + 3 * cellW / 24, y, cellW / 14, &HFF0000FF
fcirc x - 3 * cellW / 24, y + 1, cellW / 28, &HFF000000
fcirc x + 3 * cellW / 24, y + 1, cellW / 28, &HFF000000
LINE (x
- cellW
/ 12, y
+ cellW
/ 6)-STEP(cellW
/ 6, 2), &HFFFF4444, BF
fcirc x, y, cellW / 2.5, &HFF990000
LINE (x
- cellW
/ 6, y
- 2)-STEP(cellW
/ 18, 1), &HFF000000, BF
LINE (x
+ cellW
/ 12, y
- 2)-STEP(cellW
/ 18, 1), &HFF000000, BF
LINE (x
- cellW
/ 12, y
+ cellW
/ 6)-STEP(cellW
/ 6, 2), &HFF000000, BF
fcirc x, y, cellW / 2.5, &HFF990000
LINE (x
- cellW
/ 6, y
- 6)-STEP(cellW
/ 18, 1), &HFF000000, BF
LINE (x
+ cellW
/ 12, y
- 6)-STEP(cellW
/ 18, 1), &HFF000000, BF
fcirc x, y + cellW / 6, cellW / 6, &HFF000000
Radius
= ABS(R
): RadiusError
= -Radius: X
= Radius: Y
= 0 LINE (CX
- X
, CY
)-(CX
+ X
, CY
), C
, BF
RadiusError = RadiusError + Y * 2 + 1
LINE (CX
- Y
, CY
- X
)-(CX
+ Y
, CY
- X
), C
, BF
LINE (CX
- Y
, CY
+ X
)-(CX
+ Y
, CY
+ X
), C
, BF
X = X - 1
RadiusError = RadiusError - X * 2
Y = Y + 1
LINE (CX
- X
, CY
- Y
)-(CX
+ X
, CY
- Y
), C
, BF
LINE (CX
- X
, CY
+ Y
)-(CX
+ X
, CY
+ Y
), C
, BF
' From SmallBASIC code written by Chris WS developer
' Backtracking maze generator by chrisws 2016-06-30 now found at
' https://github.com/smallbasic/smallbasic.github.io/blob/5601c8bc1d794c5b143d863555bb7c15a5966a3c/samples/node/1623.bas
'
' Chris notes:
' https://en.wikipedia.org/wiki/Maze_generation_algorithm
' - Starting from a random cell,
' - Selects a random neighbouring cell that has not been visited.
' - Remove the wall between the two cells and marks the new cell as visited,
' and adds it to the stack to facilitate backtracking.
' - Continues with a cell that has no unvisited neighbours being considered a dead-end.
' When at a dead-end it backtracks through the path until it reaches a cell with an
' unvisited neighbour, continuing the path generation by visiting this new,
' unvisited cell (creating a new junction).
' This process continues until every cell has been visited, backtracking all the
' way back to the beginning cell. We can be sure every cell is visited.
v_walls(x, y) = 1
h_walls(x, y) = 1
py = border
px = border
LINE (px
, py
)-STEP(cellW
, 2), mazeClr
, BF
LINE (px
, py
)-STEP(2, cellH
), mazeClr
, BF
px = px + cellW
py = py + cellH
x = current.x: y = current.y: uvi = 0
uvi = uvi + 1
unvisited(uvi).x = x - 1: unvisited(uvi).y = y
uvi = uvi + 1
unvisited(uvi).x = x + 1: unvisited(uvi).y = y
uvi = uvi + 1
unvisited(uvi).x = x: unvisited(uvi).y = y - 1
uvi = uvi + 1
unvisited(uvi).x = x: unvisited(uvi).y = y + 1
DIM curr_cell
AS cell
, next_cell
AS cell
, cur_cell
AS cell
rand_cell cur_cell.x, cur_cell.y
visited(curr_cell.x, curr_cell.y) = 1
num_visited = 1: num_cells = W * H: si = 0
WHILE num_visited
< num_cells
cnt = 0
get_unvisited visited(), curr_cell, cells(), cnt
' choose randomly one of the current cell's unvisited neighbours
next_cell.x = cells(rc).x: next_cell.y = cells(rc).y
' push the current cell to the stack
si = si + 1
stack(si).x = curr_cell.x: stack(si).y = curr_cell.y
' remove the wall between the current cell and the chosen cell
IF next_cell.x
= curr_cell.x
THEN x = next_cell.x: y = max(next_cell.y, curr_cell.y)
h_walls(x, y) = 0
x = max(next_cell.x, curr_cell.x): y = next_cell.y
v_walls(x, y) = 0
' make the chosen cell the current cell and mark it as visited
curr_cell.x = next_cell.x: curr_cell.y = next_cell.y
visited(curr_cell.x, curr_cell.y) = 1
num_visited = num_visited + 1
' pop a cell from the stack and make it the current cell
curr_cell.x = stack(si).x: curr_cell.y = stack(si).y
si = si - 1