Jump to content

CLI-based maze-game: Difference between revisions

Line 692:
Collected treasure = 1 Bombs = 3
</pre>
 
=={{header|Phix}}==
<lang Phix>-- demo/rosetta/CLI_maze.exw
constant W = platform()=WINDOWS,
UP = iff(W?328:259),
DOWN = iff(W?336:258),
LEFT = iff(W?331:260),
RGHT = iff(W?333:261),
ESC = #1B,
 
MX = 69, -- No of columns (1..MX), must be odd.
MY = 31, -- No of rows (1..MY), must be odd.
TREASURE = '$',
TREASUREDB = 3, -- treasuredb means how many $ signs will be placed
WAY = ' ',
WALL = 'X',
DOORS = 20, -- No of doors
DOOR_CENTER = 'o',
DOOR_WING_VERTICAL = '|',
DOOR_WING_HORIZONTAL = '-',
HERO = '@',
DEAD_HERO = '+',
NUMBER_OF_BOMBS = 5,
BOMB = 'b',
NUMBER_OF_MONSTERS = 20,
MONSTER = '*',
WEAK_MONSTER = '.',
MONSTER_WEAKNESS_PROBABILITY = 25,
-- The higher the above number, the lower the chance that a strong monster will become weak.
MONSTER_INTENSIFIES_PROBABILITY = 5,
-- The higher the number above, the lower the chance that a weak monster will get stronger.
help_text = """
Maze game.
 
The object of the game is to get all the treasures. The symbol of the treasure is the $ sign.
Help (display this text): press ? or h
Exit: press Esc or q
You can detonate a bomb by pressing b, but only as long as your bomb remains.
A bomb destroys every wall around the player (the outermost, framing of the maze
except for its walls), but it won't kill monsters.
The bomb does not destroy diagonally, only vertically and horizontally.
The bomb will not destroy the doors or the treasure.
You can also find bombs in the maze, represented by the letter b. If you step on them,
you got the bomb with it, that is, the number of your bombs increases, for later use.
The game ends when you have acquired all the treasures.
The maze has not only walls but also revolving doors.
The revolving door, if horizontal, looks like this: -o-
If vertical, like this:
|
o
|
The center of the revolving door is represented by the character o, the wings by the line.
The revolving door can be rotated if you take your wing in the right direction with your character,
and if nothing stands in the way of rotation.
The player is represented by @ in the game, and his starting point is always in the lower left corner.
There is a possibility of a little cheating in the game: each press of the letter c is one increases
the amount of your bombs.
"""
 
integer bombs = 3,
treasure_counter = 0
 
sequence tb = repeat(WALL,MX),
in = WALL&repeat(WAY,MX-2)&WALL,
grid = {tb}&repeat(in,MY-2)&{tb},
sxkoord = repeat(0,NUMBER_OF_MONSTERS),
sykoord = repeat(0,NUMBER_OF_MONSTERS)
 
function gen_flags(integer l)
sequence res = repeat(false,l)
for i=1 to l by 2 do res[i] = true end for
return res
end function
 
procedure generatemaze()
sequence colflag = gen_flags(MX),
rowflag = gen_flags(MY)
while find(true,colflag)
or find(true,rowflag) do
integer direction = rand(4),
j = floor(rand(iff(direction<=2?MY:MX))/2)*2+1
switch direction do
case 1: -- left
if rowflag[j] then
for r=1 to MX-1 do
if grid[j][r]!=WALL
and grid[j][r+1]!=WALL then
grid[j][r] = WALL
end if
end for
rowflag[j] = false
end if
case 2: -- right
if rowflag[j] then
for r=MX to 3 by -1 do
if grid[j][r-1]!=WALL
and grid[j][r-2]!=WALL then
grid[j][r-1] = WALL
end if
end for
rowflag[j] = false
end if
case 3: -- up
if colflag[j] then
for c=MY to 3 by -1 do
if grid[c-1][j]!=WALL
and grid[c-2][j]!=WALL then
grid[c-1][j] = WALL
end if
end for
colflag[j] = false
end if
case 4: -- down
if colflag[j] then
for c=1 to MY-1 do
if grid[c][j]!=WALL
and grid[c+1][j]!=WALL then
grid[c][j] = WALL
end if
end for
colflag[j] = false
end if
end switch
end while
 
integer doors_placed = 0, x, y
while doors_placed<DOORS do
x = rand(MX-4)+2
y = rand(MY-4)+2
if grid[y ][x ] != WAY
and grid[y-1][x-1] == WAY -- top left corner free
and grid[y-1][x+1] == WAY -- top right corner free
and grid[y+1][x-1] == WAY -- left corner free
and grid[y+1][x+1] == WAY then -- right corner free
-- Let's see if we can put a vertical door.
if grid[y-1][x ] == WALL -- wall above the current position
and grid[y-2][x ] == WALL -- wall above the current position
and grid[y+1][x ] == WALL -- wall below the current position
and grid[y+2][x ] == WALL -- wall below the current position
and grid[y ][x-1] == WAY -- left neighbor free
and grid[y ][x+1] == WAY then -- right neighbor free
grid[y ][x] = DOOR_CENTER
grid[y-1][x] = DOOR_WING_VERTICAL
grid[y+1][x] = DOOR_WING_VERTICAL
doors_placed += 1
-- Let's see if we can put a horizontal door.
elsif grid[y ][x-1] == WALL -- wall left of the current position
and grid[y ][x-2] == WALL -- wall left of the current position
and grid[y ][x+1] == WALL -- wall right of the current position
and grid[y ][x+2] == WALL -- wall right of the current position
and grid[y+1][x ] == WAY -- above neighbor free
and grid[y-1][x ] == WAY then -- below neighbor free
grid[y][x ] = DOOR_CENTER
grid[y][x-1] = DOOR_WING_HORIZONTAL
grid[y][x+1] = DOOR_WING_HORIZONTAL
doors_placed += 1
end if
end if
end while
 
sequence stuff = {{TREASUREDB, TREASURE},
{NUMBER_OF_BOMBS, BOMB},
{NUMBER_OF_MONSTERS, WEAK_MONSTER}} -- At first, all monsters are weak.
 
for i=1 to length(stuff) do
integer {n, what} = stuff[i],
iter = 1
while n do
x = rand(MX)
y = rand(MY)
if grid[y][x]==WAY then
grid[y][x] = what
if what=WEAK_MONSTER then
sxkoord[n] = x
sykoord[n] = y
end if
n -= 1
end if
iter += 1
if iter>10000 then ?9/0 end if -- (sanity check)
end while
end for
end procedure
 
integer terminate = false,
showhelp = false
 
procedure draw()
cursor(NO_CURSOR)
while true do
if showhelp then
clear_screen()
puts(1,help_text)
{} = wait_key()
clear_screen()
showhelp = false
end if
position(1,1)
puts(1,join(grid,"\n")&"\n\n")
printf(1,"Collected treasure = %d Bombs = %d\n",{treasure_counter,bombs})
if terminate then exit end if
task_yield()
end while
end procedure
 
constant dy = {-1,+1, 0, 0},
dx = { 0, 0,-1,+1},
HV = {DOOR_WING_HORIZONTAL,DOOR_WING_VERTICAL}
 
procedure rotate_door(integer ny,nx)
for i=1 to 4 do
integer wy = dy[i],
wx = dx[i],
cy = ny+wy,
cx = nx+wx
if grid[cy,cx]=DOOR_CENTER then
if grid[cy-1][cx-1]=WAY
and grid[cy-1][cx+1]=WAY
and grid[cy+1][cx-1]=WAY
and grid[cy+1][cx+1]=WAY then -- four corners empty
integer py = dy[-i],
px = dx[-i]
if grid[cy+py][cx+px]=WAY
and grid[cy-py][cx-px]=WAY then -- swung door empty
integer door = grid[ny][nx],
flip = HV[-find(door,HV)]
grid[cy+py][cx+px] = flip
grid[cy-py][cx-px] = flip
grid[cy+wy][cx+wx] = WAY
grid[cy-wy][cx-wx] = WAY
end if
end if
exit
end if
end for
end procedure
integer x = 1,
y = MY-2
 
procedure keyboard()
integer ny,nx
while not terminate do
integer ch = lower(get_key())
if ch=-1 then task_yield()
elsif ch=ESC or ch='q' then exit
elsif ch='b' and bombs!=0 then
bombs -= 1
for i=1 to 4 do
ny = y+dy[i]
nx = x+dx[i]
if ny>1 and ny<MY
and nx>1 and nx<MX
and grid[ny][nx]=WALL then
grid[ny][nx]=WAY
end if
end for
elsif ch='c' then
bombs += 1
elsif ch='?' or ch='h' then
showhelp = true
else
ch = find(ch,{UP,DOWN,LEFT,RGHT})
if ch then
ny = y+dy[ch]
nx = x+dx[ch]
if ny>1 and ny<MY
and nx>1 and nx<MX then
ch = grid[ny][nx]
if ch=DOOR_WING_VERTICAL
or ch=DOOR_WING_HORIZONTAL then
grid[y][x] = WAY -- (temp. "ghost" him)
rotate_door(ny,nx)
grid[y][x] = HERO
ch = grid[ny][nx] -- (maybe unaltered)
elsif ch=MONSTER then
grid[y][x] = WAY
grid[ny][nx] = DEAD_HERO
y = ny
x = nx
exit
elsif ch=TREASURE then
treasure_counter += 1
if treasure_counter=TREASUREDB then
terminate = true
end if
ch = WAY
elsif ch=BOMB then
bombs += 1
ch = WAY
end if
if ch=WAY
or ch=WEAK_MONSTER then
grid[y][x] = WAY
grid[ny][nx] = HERO
y = ny
x = nx
end if
end if
end if
end if
end while
terminate = true
while get_key()!=-1 do end while -- (purge kbd buffer)
end procedure
 
integer sy, sx, monster_y, monster_x
 
function monster_step_finder()
monster_y = 0
monster_x = 0
sequence m = shuffle(tagset(4))
for i=1 to length(m) do
integer ny = sy+dy[i],
nx = sx+dx[i]
if ny>=1 and ny<=MY
and nx>=1 and nx<=MX
and find(grid[ny][nx],{WAY,HERO}) then
monster_y = ny
monster_x = nx
return true
end if
end for
return false
end function
 
procedure monster_move()
while not terminate do
integer active = rand(NUMBER_OF_MONSTERS)
sx = sxkoord[active]
sy = sykoord[active]
if sx then
integer ch = grid[sy][sx]
if ch=MONSTER then
if rand(MONSTER_WEAKNESS_PROBABILITY)=1 then
grid[sy][sx] = WEAK_MONSTER
elsif monster_step_finder() then
if grid[monster_y][monster_x]=HERO then
grid[monster_y][monster_x]=DEAD_HERO
terminate = true
exit
end if
grid[sy][sx] = WAY
grid[monster_y][monster_x] = MONSTER
sxkoord[active] = monster_x
sykoord[active] = monster_y
end if
elsif ch=WEAK_MONSTER then
if rand(MONSTER_INTENSIFIES_PROBABILITY)=1 then
grid[sy][sx] = MONSTER
elsif monster_step_finder() then
grid[sy][sx] = WAY
if grid[monster_y][monster_x]!=HERO then
grid[monster_y][monster_x]=WEAK_MONSTER
sxkoord[active] = monster_x
sykoord[active] = monster_y
else
sxkoord[active] = 0
sykoord[active] = 0
end if
end if
end if
end if
task_yield()
end while
end procedure
 
generatemaze()
grid[y][x] = HERO
integer draw_id = task_create(draw,{}),
mstr_id = task_create(monster_move,{})
task_schedule(draw_id,{0.2,0.2})
task_schedule(mstr_id,{0.1,0.1})
 
keyboard()
 
if treasure_counter=TREASUREDB then
puts(1,"YOU WON! Congratulations!\n")
{} = wait_key()
elsif grid[y][x]=DEAD_HERO then
puts(1,"YOU PERISHED!\n")
{} = wait_key()
end if</lang>
7,818

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.