_TITLE "Escape from Monster Maze 2 Ninja" 'B+ 2019-09-04 & 5 ' 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.
'2019-09-04 could have monsters follow one direction until blocked flip a coin and go on
' really want mouse smoother
' Oh dang did not have wallThk update! fixed
' OK my guy can cut corners now!!!
'2019-09-05 Escape From Monster Maze 3:
' I have another idea that will greatly simplify the mouse corner moves
' AND display step by step, no diagonal skips so all moves remain rectilinear.
' This version removes more walls because monsters can block only way through
' and goal tend either top left or bottom right critical cells.
'
'2 subs for my toolbox yCP - printing center alignment at pixel y row
' cSleep - wait for keypress or Mouse Click
'2019-09-05 plug in mouse action code that cuts corners in one step, Ninja!
' Because Ninja can cut corners (go diagonally) 2 steps in one,
' it removes less walls per monster added, maybe none??
CONST xmax
= 700, ymax
= 700 'screen CONST W
= 15, H
= 15, border
= 50, wallThk
= 2 'maze cells wide and high CONST mazeClr
= &HFFFF8800 CONST mDelay
= 6 'slow monsters down so I can speed up limit for loops for mouse moving player
cellW = (xmax - 2 * border) / W
cellH = (ymax - 2 * border) / H
' Locals for Main module code
nMonsters = 3
init_walls
generate_maze
'open gate a bottom right corner to esacpe
h_walls(W - 1, H) = 0
nMonsters = nMonsters + 1
newMonster (i)
FOR j
= 1 TO 1 '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
IF m
(i
).delay
MOD 4 = 0 THEN m
(i
).face
= 1 - m
(i
).face
'toggle face 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
m(i).delay = m(i).delay - 1
m(i).delay = mDelay
IF moveOK
(m
(i
).x
, m
(i
).y
, m
(i
).dir
) AND RND < .5 THEN 'most of time monsters on momentum move m(i).x, m(i).y, m(i).dir
WHILE moveOK
(m
(i
).x
, m
(i
).y
, d
) = 0 move m(i).x, m(i).y, d
m(i).dir = d
makeFace (px + .5) * cellW + border, (py + .5) * cellH + border, 1
px = 0: py = 0
IF (m
(i
).x
= W
- 1 AND m
(i
).y
= H
- 1) OR (m
(i
).x
= 0 AND m
(i
).y
= 0) THEN newMonster i
'EDIT 2019-09-07 I think game plays better without next code block
'FOR j = 1 TO nMonsters
' IF j <> i AND m(j).x = m(i).x AND m(j).y = m(i).y THEN newMonster i
'NEXT
IF mouseOK
(0) = -1 THEN 'might not need this? dx = mx - px: dy = my - py
IF (v_walls
(px
, py
) = 0 AND h_walls
(px
- 1, py
) = 0) OR (h_walls
(px
, py
) = 0 AND v_walls
(px
, py
- 1) = 0) THEN px = px - 1: py = py - 1
IF v_walls
(px
, py
) = 0 THEN px
= px
- 1 IF v_walls
(px
, py
) = 0 AND h_walls
(px
- 1, py
+ 1) = 0 OR (h_walls
(px
, py
+ 1) = 0 AND v_walls
(px
, py
+ 1) = 0) THEN px = px - 1: py = py + 1
IF h_walls
(px
, py
) = 0 THEN py
= py
- 1 IF h_walls
(px
, py
+ 1) = 0 THEN py
= py
+ 1
IF h_walls
(px
, py
) = 0 AND v_walls
(px
+ 1, py
- 1) = 0 OR v_walls
(px
+ 1, py
) = 0 AND h_walls
(px
+ 1, py
) = 0 THEN px = px + 1: py = py - 1
IF v_walls
(px
+ 1, py
) = 0 THEN px
= px
+ 1 IF h_walls
(px
, py
+ 1) = 0 AND v_walls
(px
+ 1, py
+ 1) = 0 OR v_walls
(px
+ 1, py
) = 0 AND h_walls
(px
+ 1, py
+ 1) = 0 THEN px = px + 1: py = py + 1
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: tmp
= mouseOK
(1):
IF moveOK
(px
, py
, 1) THEN move px
, py
, 1 'up CASE 80: tmp
= mouseOK
(1):
IF moveOK
(px
, py
, 2) THEN move px
, py
, 2 'down CASE 77: tmp
= mouseOK
(1):
IF moveOK
(px
, py
, 3) THEN move px
, py
, 3 'right CASE 75: tmp
= mouseOK
(1):
IF moveOK
(px
, py
, 4) THEN move px
, py
, 4 'left makeFace (px + .5) * cellW + border, (py + .5) * cellH + border, 0
yCP
20, STR$(nMonsters
) + " Monsters " + STR$((TIMER - start
) \
1) + " Secs" yCP ymax
- 20, "You escaped in" + STR$((TIMER - start
) \
1) + " secs, click to continue..." cSleep
' is the way blocked or even inside maze, assuming move is not OK
' _____ ________
' |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
(curX
, curY
) = 0 THEN moveOK
= -1 IF curY
+ 1 <= H
THEN ' OR (curX = W - 1 AND curY = H - 1) THEN 'let through gate bottom right corner IF h_walls
(curX
, curY
+ 1) = 0 THEN moveOK
= -1 IF v_walls
(curX
+ 1, curY
) = 0 THEN moveOK
= -1 IF v_walls
(curX
, curY
) = 0 THEN moveOK
= -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, &HFF88AAFF fcirc x - 3 * cellW / 24, y, cellW / 14, &HFFFFFFFF
fcirc x + 3 * cellW / 24, y, cellW / 14, &HFFFFFFFF
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
restart:
x
= RND * 7 * W
/ 8 + W
/ 8 - 1: y
= RND * 7 * H
/ 8 + H
/ 8 - 1 m(i).x = x: m(i).y = y
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
SUB cSleep
'wait for keypress or mouseclick wayt = 1
SUB yCP
(y
, s$
) 'for xmax pixel wide graphics screen
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
+ wallThk
, wallThk
), mazeClr
, BF
LINE (px
, py
)-STEP(wallThk
, cellH
+ wallThk
), 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