CLI-based maze-game: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 692: Line 692:
Collected treasure = 1 Bombs = 3
Collected treasure = 1 Bombs = 3
</pre>
</pre>

=={{header|Nim}}==
{{trans|Phix}}
{{libheader|nim-ncurses}}
This translation uses the binding for “ncurses” and have been tested on Linux (Manjaro).
<lang Nim>import os, random, sequtils, strutils, std/exitprocs, locks
import ncurses

const

KeyUp = 259
Keydown = 258
KeyLeft = 260
KeyRight = 261

Mx = 69 # No of columns (1..Mx), must be odd.
My = 31 # No of rows (1..My), must be odd.
Treasure = '$'
TreasureDb= 3 # How many $ signs will be placed.
Way = ' '
Wall = 'X'
Doors = 20 # No of doors.
DoorCenter = 'o'
DoorWingVertical = '|'
DoorWingHorizontal = '-'
Hero = '@'
DeadHero = '+'
NumberOfBombs = 5
Bomb = 'b'
NumberOfMonsters = 20
Monster = '*'
WeakMonster = '.'
MonsterWeaknessProbability = 25
# The higher the above number, the lower the chance that a strong monster will become weak.
MonsterIntensifiesProbability = 5
# The higher the number above, the lower the chance that a weak monster will get stronger.

HelpText = """
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.
"""

type

Direction = enum dirLeft, dirRight, dirUp, dirDown

Position = tuple[x, y: int]

Game = object
grid: array[1..My, array[1..Mx, char]]
scoords: array[1..NumberOfMonsters, Position]
showHelp: bool
terminate: bool
treasureCounter: Natural
bombs: Natural
x, y: Natural

const
None: Position = (0, 0)
Dy = [-1, 1, 0, 0]
Dx = [0, 0, -1, 1]

var gameLock: Lock


proc genFlags(n: static int): array[1..n, bool] =
for i in countup(1, n, 2):
result[i] = true


proc initGame(): Game =

result.bombs = 3

for x in 1..Mx:
result.grid[1][x] = Wall
result.grid[My][x] = Wall
for y in 2..<My:
result.grid[y][1] = Wall
for x in 2..<Mx: result.grid[y][x] = Way
result.grid[y][Mx] = Wall

var colFlags = genFlags(Mx)
var rowFlags = genFlags(My)

while colFlags.anyIt(it) or rowFlags.anyIt(it):
let direction = Direction(rand(3))
let j = rand(1..(if direction <= dirRight: My else: Mx)) div 2 * 2 + 1
case direction
of dirLeft:
if rowFlags[j]:
for r in 1..<Mx:
if result.grid[j][r] != Wall and result.grid[j][r+1] != Wall:
result.grid[j][r] = Wall
rowFlags[j] = false
of dirRight:
if rowFlags[j]:
for r in countdown(Mx, 3):
if result.grid[j][r-1] != Wall and result.grid[j][r-2] != Wall:
result.grid[j][r-1] = Wall
rowFlags[j] = false
of dirUp:
if colFlags[j]:
for c in countdown(My, 3):
if result.grid[c-1][j] != Wall and result.grid[c-2][j] != Wall:
result.grid[c-1][j] = Wall
colFlags[j] = false
of dirDown:
if colFlags[j]:
for c in 1..<My:
if result.grid[c][j] != Wall and result.grid[c+1][j] != Wall:
result.grid[c][j] = Wall
colFlags[j] = false

var doorsPlaced = 0
while doorsPlaced < Doors:
let x = rand(3..Mx-2)
let y = rand(3..My-2)
if result.grid[y][x] != Way and
result.grid[y-1][x-1] == Way and # top left corner free
result.grid[y-1][x+1] == Way and # top right corner free
result.grid[y+1][x-1] == Way and # left corner free
result.grid[y+1][x+1] == Way: # right corner free
# Let's see if we can put a vertical door.
if result.grid[y-1][x] == Wall and # wall above the current position
result.grid[y-2][x] == Wall and # wall above the current position
result.grid[y+1][x] == Wall and # wall below the current position
result.grid[y+2][x] == Wall and # wall below the current position
result.grid[y][x-1] == Way and # left neighbor free
result.grid[y][x+1] == Way: # right neighbor free
result.grid[y][x] = DoorCenter
result.grid[y-1][x] = DoorWingVertical
result.grid[y+1][x] = DoorWingVertical
inc doorsPlaced
# Let's see if we can put a horizontal door.
elif result.grid[y][x-1] == Wall and # wall left of the current position
result.grid[y][x-2] == Wall and # wall left of the current position
result.grid[y][x+1] == Wall and # wall right of the current position
result.grid[y][x+2] == Wall and # wall right of the current position
result.grid[y+1][x] == Way and # above neighbor free
result.grid[y-1][x] == Way: # below neighbor free
result.grid[y][x] = DoorCenter
result.grid[y][x-1] = DoorWingHorizontal
result.grid[y][x+1] = DoorWingHorizontal
inc doorsPlaced

const Stuff = [(TreasureDb, Treasure),
(NumberOfBombs, Bomb),
(NumberOfMonsters, WeakMonster)] # At first, all monsters are weak.

for (n, what) in Stuff:
var iter = 1
var n = n
while n > 0:
let x = rand(1..Mx)
let y = rand(1..My)
if result.grid[y][x] == Way:
result.grid[y][x] = what
if what == WeakMonster:
result.scoords[n] = (x, y)
dec n
inc iter
assert iter <= 10_000 # (sanity check)

result.x = 1
result.y = My - 2
result.grid[My - 2][1] = Hero


proc draw(game: ptr Game) {.thread.} =
cursSet(0)
while true:
acquire gameLock
if game.showHelp:
erase()
addStr HelpText
while getch() == -1: sleep 10
erase()
game.showHelp = false
erase()
move(0, 0)
for row in game.grid:
addstr row.join("") & '\n'
addstr "\n\nCollected treasures = $1 Bombs = $2\n".format(game.treasureCounter, game.bombs)
refresh()
if game.terminate: break
release gameLock
sleep 200
release gameLock


proc monsterStepFinder(game: ptr Game; sx, sy: int): Position =
result = None
var m = [0, 1, 2, 3]
m.shuffle()
for i in m:
let nx = sx + Dx[i]
let ny = sy + Dy[i]
if ny in 1..My and nx in 1..Mx and game.grid[ny][nx] in [Way, Hero]:
result = (nx, ny)


proc monsterMove(game: ptr Game) {.thread.} =
while not game.terminate:
acquire gameLock
let active = rand(1..NumberOfMonsters)
let (sx, sy) = game.scoords[active]
if sx != 0:
let ch = game.grid[sy][sx]
if ch == Monster:
if rand(1..MonsterWeaknessProbability) == 1:
game.grid[sy][sx] = WeakMonster
else:
let monster = game.monsterStepFinder(sx, sy)
if monster != None:
if game.grid[monster.y][monster.x] == Hero:
game.grid[monster.y][monster.x] = DeadHero
game.terminate = true
break
game.grid[sy][sx] = Way
game.grid[monster.y][monster.x] = Monster
game.scoords[active] = monster
elif ch == WeakMonster:
if rand(1..MonsterIntensifiesProbability) == 1:
game.grid[sy][sx] = Monster
else:
let monster = game.monsterStepFinder(sx, sy)
if monster != None:
game.grid[sy][sx] = Way
if game.grid[monster.y][monster.x] != Hero:
game.grid[monster.y][monster.x] = WeakMonster
game.scoords[active] = monster
else:
game.scoords[active] = None
release gameLock
sleep 100

release gameLock


proc rotateDoor(game: var Game; nx, ny: int) =
for i in 1..4:
let
wy = Dy[i-1]
wx = Dx[i-1]
cy = ny + wy
cx = nx + wx
if game.grid[cy][cx] == DoorCenter:
if game.grid[cy-1][cx-1] == Way and
game.grid[cy-1][cx+1] == Way and
game.grid[cy+1][cx-1] == Way and
game.grid[cy+1][cx+1] == Way: # four corners empty
let py = Dy[^i]
let px = Dx[^i]
if game.grid[cy+py][cx+px] == Way and
game.grid[cy-py][cx-px] == Way: # swung door empty
let door = game.grid[ny][nx]
let flip = if door == DoorWingVertical: DoorWingHorizontal else: DoorWingVertical
game.grid[cy+py][cx+px] = flip
game.grid[cy-py][cx-px] = flip
game.grid[cy+wy][cx+wx] = Way
game.grid[cy-wy][cx-wx] = Way
break


proc keyboard(game: var Game; win: PWindow) =
while not game.terminate:
var key = -1
while key == -1 and not game.terminate:
sleep 10
key = win.wgetch()
acquire gameLock
case key
of ord('\e'), ord('q'):
game.terminate = true
of ord('b'):
if game.bombs != 0:
dec game.bombs
for i in 0..3:
let nx = game.x + Dx[i]
let ny = game.y + Dy[i]
if ny in 2..<My and nx in 2..<Mx and game.grid[ny][nx] == Wall:
game.grid[ny][nx] = Way
of ord('c'):
inc game.bombs
of ord('?'), ord('h'):
game.showHelp = true
else:
let chIndex = [KeyUp, Keydown, KeyLeft, KeyRight].find(key)
if chIndex >= 0:
let nx = game.x + Dx[chIndex]
let ny = game.y + Dy[chIndex]
if ny in 2..<My and nx in 2..<Mx:
var ch = game.grid[ny][nx]
if ch in [DoorWingVertical, DoorWingHorizontal]:
game.grid[game.y][game.x] = Way # (temp. "ghost" him)
game.rotateDoor(nx, ny)
game.grid[game.y][game.x] = Hero
ch = game.grid[ny][nx] # (maybe unaltered)
elif ch == Monster:
game.grid[game.y][game.x] = Way
game.grid[ny][nx] = DeadHero
game.y = ny
game.x = nx
game.terminate = true
elif ch == Treasure:
inc game.treasureCounter
if game.treasureCounter == TreasureDb:
game.terminate = true
ch = Way
elif ch == Bomb:
inc game.bombs
ch = Way
if ch in [Way, WeakMonster]:
game.grid[game.y][game.x] = Way
game.grid[ny][nx] = Hero
game.y = ny
game.x = nx

release gameLock

while getch() != -1: discard # (purge kbd buffer)


proc play() =

randomize()
let win = initscr()
win.nodelay(true)
win.keypad(true)
noecho()
cbreak()
addExitProc proc() = endwin()
addExitProc proc() = cursSet(1)
var game = initGame()

var tdraw, tmove: Thread[ptr Game]
createThread(tdraw, draw, addr(game))
createThread(tmove, monsterMove, addr(game))
game.keyboard(win)

joinThreads(tdraw, tmove)
if game.treasureCounter == TreasureDb:
addstr "\nYOU WON! Congratulations!\n"
refresh()
while getch() == -1: sleep(1)
elif game.grid[game.y][game.x] == DeadHero:
addstr "\nYOU PERISHED!\n"
refresh()
while getch() == -1: sleep(1)


play()</lang>


=={{header|Phix}}==
=={{header|Phix}}==

Revision as of 16:02, 25 July 2021

CLI-based maze-game is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Task: Create a complete but CLI-controlled maze-game!

Use the CLI interface only. The symbols:

1. The hero: @

2. Strong monsters: * (they can kill you).

3. Weak monsters: . (You can kill them).

4. Treasure: $

5. Wall: X

6. Bomb: b

7. Revolving door: -o-

and:

|
o
|

(the monsters are stupid, they can't use these doors)

Monsters must be moved by the computer, automatically. Use for this subtask a fork()-ed part of your program.

The maze must be generated randomly, at each start of the game.

Note: I apologize of my bad English, I'm very sorry...

Furor

<lang Furor>

      1. sysinclude terminal.uh
      2. sysinclude into.uh
      3. sysinclude math.uh
      1. define VÁRAKOZIK 40000

// Minél nagyobb a fenti szám, annál lassabban mozognak a szörnyek.

      1. define MERETX 69

// A labirintus oszlopainak számozása 0 és MERETX-1 közt történik. // MERETX muszáj hogy páratlan szám legyen.

      1. define MERETY 31

// A labirintus sorainak számozása 0 és MERETY-1 közt történik. // MERETY muszáj hogy páratlan szám legyen.

      1. define TREASURE '$
      2. define TREASUREDB 3

// A treasuredb jelenti, hány $ jel lesz elhelyezve

      1. define WAY 32
      2. define FAL 'X
      3. define wayszín 0
      4. define wayháttérszín 0

// Az alábbi doors az ajtók számát jelzi a labirintus falaiban.

      1. define doors 20
      2. define AJTÓKÖZEPE 'o
      3. define AJTÓSZÁRNYFÜGGŐLEGES '|
      4. define AJTÓSZÁRNYVÍZSZINTES '-
      5. define AJTÓszín $e
      6. define AJTÓháttérszín 0
      7. define FALszín $1b
      8. define FALháttérszín FALszín
      9. define HŐS '@
      10. define HALOTTHŐS '+
      11. define HŐSszín 9
      12. define HŐSháttérszín 0
      13. define kincsszín $b
      14. define kincsháttérszín 0

// Ennyi bombát lehet találni a labirintusban:

      1. define bombákszáma 5
      2. define bomba 'b
      3. define bombaszín $a6
      4. define bombaháttérszín 0
      1. define szörnyekszáma 20
      2. define szörny '*
      3. define szörnyszín $d
      4. define szörnyháttérszín 0
      5. define gyengeszörny '.
      6. define gyengeszörnyszín $cd
      7. define gyengeszörnyháttérszín 0
      8. define szörnygyengülvalószínűség 25

// A fenti szám minél magasabb, annál kisebb az esélye hogy egy erős szörny gyengévé válik.

      1. define szörnyerősödikvalószínűség 5

// A fenti szám minél magasabb, annál kisebb az esélye annak, hogy egy gyenge szörny megerősödik.

argc 2 > { ."Labirintusjáték. Készítette: Viola Zoltán alias Harold King alias Fossil Codger.\n" ."(fossilcodger@gmail.com)\n" ."A program a Furor programnyelven íródott, azt a programnyelvet is én, Viola Zoltán írtam.\n" ."A játék célja: az összes kincs megszerzése. A kincs jelképe a $ jel.\n" ."Kilépés: az Esc 2-szer lenyomva, vagy a q.\n" ."A b lenyomásával robbanthatsz, de csak amíg maradt bombád.\n" ."Egy bomba minden falat lerombol a játékos körül (a labirintus legszélső, keretező" ." falait kivéve), de a szörnyeket nem öli meg.\n" ."A bomba átlósan se rombol, csak függőlegesen és vízszintesen!\n" ."A bomba nem pusztítja el az ajtókat, és a kincset se.\n" ."Bombákat találhatsz is a labirintusban, ezeket a b betű jelképezi. Ha rájuk lépsz,\n" ."azzal megszerezted a bombát, azaz a bombáid száma növekszik, később ezeket\n" ."felhasználhatod.\n" ."A játék akkor ér véget, ha az összes kincset megszerezted.\n" ."A labirintusban nem csak falak, de forgóajtók is vannak.\n" ."A forgóajtó ha vízszintes, így néz ki: -o-\n" ."Ha meg függőleges akkor így:\n" ."|\n" ."o\n" ."|\n" ."A forgóajtó közepét az o karakter, a szárnyait a vonal jelképezi.\n" ."A forgóajtó elfordítható, ha a szárnyának a megfelelő irányból nekimész a karaktereddel,\n" ."és ha semmi se áll az elforgatás útjában.\n" ."A játékost a @ jelképezi a játékban, s kiindulási helye mindig a bal alsó sarokban van.\n" ."Van a játékban kis csalásra is lehetőség: a B (nagy bé betű) minden lenyomása eggyel\n" ."megnöveli a bombáid mennyiségét.\n"

end }

3 sto bombs // A bombák száma. randinit // A véletlenszámgenerátor inicializálása pálya MERETY MERETX createsharedscreen 100 shared sto messagestring // kommunikációs terület a forkolt programrészeknek szörnyekszáma shared sto sxkoord szörnyekszáma shared sto sykoord üres() // Ez elkészíti az üres területet, falakkal körülhatárolva generatemaze() // Ez legenerálja véletlenszerűen a labirintust // ******************************************************** // // Ki- és bejáratok generálása, ha szükséges: // MERETY 2 - dup sto y sto newy 0 dup sto x sto newx pálya @y @x HŐS ^ // A hős karakterének letevése // ********************************************************

cursoroff cls §kirajzol fork sto kirajzoló §szörnymozgat fork sto szörnymozgató

kirajzolni: @newy sto y @newx sto x kirajzol2: @messagestring 6 [] then §meghaltahős @messagestring 1 @bombs [^] @messagestring 2 @kincsszámláló [^] @kincsszámláló TREASUREDB #g == { 100000 usleep @messagestring 5 1 [^] // Üzenetküldés a szörnymozgatás leállítására @messagestring 0 1 [^] // üzenetküldés a kirajzolónak hogy álljon le @szörnymozgató wait @kirajzoló wait ."YOU WON! Congratulations!\n" goto §vége } pálya @y @x [[]] HALOTTHŐS == { 100000 usleep meghaltahős: @messagestring 5 1 [^] // Üzenetküldés a szörnymozgatás leállítására @messagestring 0 1 [^] // üzenetküldés a kirajzolónak hogy álljon le @szörnymozgató wait @kirajzoló wait ."YOU PERISHED! :(\n" goto §vége } // Billentyűzetinput newinputchar: #g 11 into sto kar @kar $ffffffffffffffff == then §kirajzol2 @kar 128 < { @kar 27 == then §vége2 @kar 'q == then §vége2 @kar 'B == { inc bombs goto §kirajzol2 } @kar 'b == { @bombs else §newinputchar // Ha elfogyott a bomba, hiába minden... dec bombs @x 1 > { pálya @y @x -- [[]] FAL == { pálya @y @x -- WAY ^ } } @y 1 > { @x { pálya @y -- @x [[]] FAL == { pálya @y -- @x WAY ^ } } } @x MERETX 2 - < { pálya @y @x ++ [[]] FAL == { pálya @y @x ++ WAY ^ } } @y MERETY 2 - < { @x { pálya @y ++ @x [[]] FAL == { pálya @y ++ @x WAY ^ } } } goto §kirajzol2 } goto §newinputchar } @kar $ff & sto k @x sto newx @y sto newy @k 1 == { // kurzorfel dec newy @newy else §newinputchar @x else §lépés @y 1 == §newinputchar // -o- // @ pálya @newy @newx [[]] AJTÓSZÁRNYVÍZSZINTES == pálya @newy @newx ++ [[]] AJTÓKÖZEPE == pálya @newy -- @newx [[]] WAY == pálya @newy -- @newx ++ [[]] WAY == pálya @newy ++ @newx 2 + [[]] WAY == pálya @newy ++ @newx ++ [[]] WAY == & & & & & { pálya @newy @newx WAY ^ pálya @newy @newx 2 + WAY ^ pálya @newy -- @newx ++ AJTÓSZÁRNYFÜGGŐLEGES ^ pálya @newy ++ @newx ++ AJTÓSZÁRNYFÜGGŐLEGES ^ goto §lépés } // -o- // @ pálya @newy @newx [[]] AJTÓSZÁRNYVÍZSZINTES == pálya @newy @newx -- [[]] AJTÓKÖZEPE == pálya @newy -- @newx [[]] WAY == pálya @newy -- @newx -- [[]] WAY == pálya @newy ++ @newx 2 - [[]] WAY == pálya @newy ++ @newx -- [[]] WAY == & & & & & { pálya @newy @newx WAY ^ pálya @newy @newx 2 - WAY ^ pálya @newy -- @newx -- AJTÓSZÁRNYFÜGGŐLEGES ^ pálya @newy ++ @newx -- AJTÓSZÁRNYFÜGGŐLEGES ^ goto §lépés } goto §lépés } // kurzorfel vége @k 2 == { // kurzorle inc newy @newy MERETY -- >= then §newinputchar @x else §lépés // @ // -o- pálya @newy @newx [[]] AJTÓSZÁRNYVÍZSZINTES == pálya @newy @newx ++ [[]] AJTÓKÖZEPE == pálya @newy ++ @newx [[]] WAY == pálya @newy ++ @newx ++ [[]] WAY == pálya @newy -- @newx 2 + [[]] WAY == pálya @newy -- @newx ++ [[]] WAY == & & & & & { pálya @newy @newx WAY ^ pálya @newy @newx 2 + WAY ^ pálya @newy -- @newx ++ AJTÓSZÁRNYFÜGGŐLEGES ^ pálya @newy ++ @newx ++ AJTÓSZÁRNYFÜGGŐLEGES ^ goto §lépés } // @ // -o- pálya @newy @newx [[]] AJTÓSZÁRNYVÍZSZINTES == pálya @newy @newx -- [[]] AJTÓKÖZEPE == pálya @newy ++ @newx [[]] WAY == pálya @newy ++ @newx -- [[]] WAY == pálya @newy -- @newx 2 - [[]] WAY == pálya @newy -- @newx -- [[]] WAY == & & & & & { pálya @newy @newx WAY ^ pálya @newy @newx 2 - WAY ^ pálya @newy -- @newx -- AJTÓSZÁRNYFÜGGŐLEGES ^ pálya @newy ++ @newx -- AJTÓSZÁRNYFÜGGŐLEGES ^ goto §lépés } goto §lépés } // kurzorle vége @k 3 == { // kurzorjobbra inc newx @newx MERETX >= then §newinputchar @x MERETX -- == then §newinputchar @x else §lépés // @| // o // | //@newy 2 + MERETY >= then §lépés pálya @newy @newx [[]] AJTÓSZÁRNYFÜGGŐLEGES == pálya @newy ++ @newx [[]] AJTÓKÖZEPE == & else §jobbra2 pálya @newy @newx ++ [[]] WAY == pálya @newy ++ @newx ++ [[]] WAY == pálya @newy ++ @newx -- [[]] WAY == pálya @newy 2 + @newx -- [[]] WAY == & & & { pálya @newy @newx WAY ^ pálya @newy 2 + @newx WAY ^ pálya @newy ++ @newx -- AJTÓSZÁRNYVÍZSZINTES ^ pálya @newy ++ @newx ++ AJTÓSZÁRNYVÍZSZINTES ^ goto §lépés } // | // o // @| jobbra2: @newy -- else §lépés pálya @newy @newx [[]] AJTÓSZÁRNYFÜGGŐLEGES == pálya @newy -- @newx [[]] AJTÓKÖZEPE == pálya @newy @newx ++ [[]] WAY == pálya @newy -- @newx ++ [[]] WAY == pálya @newy -- @newx -- [[]] WAY == pálya @newy 2 - @newx -- [[]] WAY == & & & & & { pálya @newy @newx WAY ^ pálya @newy 2 - @newx WAY ^ pálya @newy -- @newx -- AJTÓSZÁRNYVÍZSZINTES ^ pálya @newy -- @newx ++ AJTÓSZÁRNYVÍZSZINTES ^ goto §lépés } goto §lépés } // kurzorjobbra vége @k 4 == { // kurzorbalra @x else §newinputchar dec newx @newx else §newinputchar // |@ // o // | //@newy 2 + MERETY >= then §lépés pálya @newy @newx [[]] AJTÓSZÁRNYFÜGGŐLEGES == pálya @newy ++ @newx [[]] AJTÓKÖZEPE == & else §balra2 pálya @newy @newx -- [[]] WAY == pálya @newy ++ @newx -- [[]] WAY == pálya @newy ++ @newx ++ [[]] WAY == pálya @newy 2 + @newx ++ [[]] WAY == & & & { pálya @newy @newx WAY ^ pálya @newy 2 + @newx WAY ^ pálya @newy ++ @newx -- AJTÓSZÁRNYVÍZSZINTES ^ pálya @newy ++ @newx ++ AJTÓSZÁRNYVÍZSZINTES ^ goto §lépés } // | // o // |@ balra2: //@newy -- else §lépés pálya @newy @newx [[]] AJTÓSZÁRNYFÜGGŐLEGES == pálya @newy -- @newx [[]] AJTÓKÖZEPE == & else §lépés pálya @newy @newx -- [[]] WAY == pálya @newy -- @newx ++ [[]] WAY == pálya @newy -- @newx -- [[]] WAY == pálya @newy 2 - @newx ++ [[]] WAY == & & & { pálya @newy @newx WAY ^ pálya @newy 2 - @newx WAY ^ pálya @newy -- @newx -- AJTÓSZÁRNYVÍZSZINTES ^ pálya @newy -- @newx ++ AJTÓSZÁRNYVÍZSZINTES ^ goto §lépés } goto §lépés

} // kurzorbalra vége goto §newinputchar // ========================================================= // ========================================================= lépés: pálya @newy @newx [[]] FAL == then §newinputchar pálya @newy @newx [[]] AJTÓKÖZEPE == then §newinputchar pálya @newy @newx [[]] AJTÓSZÁRNYVÍZSZINTES == then §newinputchar pálya @newy @newx [[]] AJTÓSZÁRNYFÜGGŐLEGES == then §newinputchar pálya @newy @newx [[]] TREASURE == { inc kincsszámláló } pálya @newy @newx [[]] bomba == { inc bombs } pálya @newy @newx [[]] szörny == { pálya @y @x WAY ^ pálya @newy @newx HALOTTHŐS ^ goto §kirajzolni } pálya @y @x WAY ^ pálya @newy @newx HŐS ^ goto §kirajzolni

// ******************************************************* vége2: // üzenetküldés a child processeknek hogy álljanak le @messagestring 0 1 [^] @messagestring 5 1 [^] // Várakozás a child processek befejeződésére: @szörnymozgató wait @kirajzoló wait vége: @messagestring free @sxkoord free @sykoord free pálya eraseshared ,,, cursoron end // ********************************************************

kirajzol: closestdin // Nem várunk semmi billentyűzetinputot {... // végtelenciklus // ....................................................... @messagestring 0 [] { end } // Parancs érkezett szeppuku elkövetésére... // ....................................................... topleft

  1. k MERETY yloop: {| MERETX {|

pálya {}§yloop {} [[]] WAY == { wayszín tint wayháttérszín !tint pálya {}§yloop {} [[]] print {<} } pálya {}§yloop {} [[]] FAL == { FALszín tint FALháttérszín !tint pálya {}§yloop {} [[]] print {<} } pálya {}§yloop {} [[]] AJTÓSZÁRNYFÜGGŐLEGES == { AJTÓszín tint AJTÓháttérszín !tint pálya {}§yloop {} [[]] print {<} } pálya {}§yloop {} [[]] AJTÓSZÁRNYVÍZSZINTES == { AJTÓszín tint AJTÓháttérszín !tint pálya {}§yloop {} [[]] print {<} } pálya {}§yloop {} [[]] AJTÓKÖZEPE == { AJTÓszín tint AJTÓháttérszín !tint pálya {}§yloop {} [[]] print {<} } pálya {}§yloop {} [[]] bomba == { bombaszín tint bombaháttérszín !tint pálya {}§yloop {} [[]] print {<} } pálya {}§yloop {} [[]] szörny == { szörnyszín tint szörnyháttérszín !tint pálya {}§yloop {} [[]] print {<} } pálya {}§yloop {} [[]] gyengeszörny == { gyengeszörnyszín tint gyengeszörnyháttérszín !tint pálya {}§yloop {} [[]] print {<} } pálya {}§yloop {} [[]] HŐS == { HŐSszín tint HŐSháttérszín !tint pálya {}§yloop {} [[]] print {<} } pálya {}§yloop {} [[]] HALOTTHŐS == { HŐSszín tint HŐSháttérszín !tint pálya {}§yloop {} [[]] print {<} } pálya {}§yloop {} [[]] 'a >= pálya {}§yloop {} [[]] 'z <= & { kincsszín tint kincsháttérszín !tint pálya {}§yloop {} [[]] print {<} } ,,, pálya {}§yloop {} [[]] print |} ,,, NL |} NL ."Collected treasure = " #g @messagestring 2 [] print ." Bombs = " @messagestring 1 [] printnl VÁRAKOZIK usleep ...} // ******************************************************** szörnymozgat: closestdin closestdout closestderr // Nem várunk semmi billentyűzetinputot és nem is írunk sehova randinit {... // végtelenciklus 6000 usleep // ....................................................... @messagestring 5 [] { end } // Parancs érkezett szeppuku elkövetésére... // ....................................................... szörnyekszáma random sto akts @sxkoord @akts [] sto! sx @sykoord @akts [] sto! sy #g | !{ {.<.} } pálya @sy @sx [[]] szörny == { szörnygyengülvalószínűség random 1 == { pálya @sy @sx gyengeszörny ^ {.<.} } sbr §szörnylépéskeres

  1. g

@szörnyy @szörnyx | !{ {.<.} } // Ha nem talált helyet ahova mozoghatna pálya @szörnyy @szörnyx [[]] HŐS == { pálya @szörnyy @szörnyx HALOTTHŐS ^ @messagestring 6 1 [^] 1000 usleep {.<.} } pálya @sy @sx WAY ^ pálya @szörnyy @szörnyx szörny ^ @sxkoord @akts @szörnyx [^] @sykoord @akts @szörnyy [^] {.<.} } pálya @sy @sx [[]] gyengeszörny == { szörnyerősödikvalószínűség random 1 == { pálya @sy @sx szörny ^ {.<.} } sbr §szörnylépéskeres

  1. g

@szörnyy @szörnyx | !{ {.<.} } // Ha nem talált helyet ahova mozoghatna pálya @sy @sx WAY ^ pálya @szörnyy @szörnyx [[]] HŐS != { // Ha gyenge szörny találkozik a hőssel, a szörnynek vége, nem rajzoljuk ki pálya @szörnyy @szörnyx gyengeszörny ^ }{ zero szörnyx zero szörnyy } @sxkoord @akts @szörnyx [^] @sykoord @akts @szörnyy [^] {.<.} }

...} // ....................................................... szörnylépéskeres: zero szörnyy zero szörnyx 24 random sto kvartett // Választunk egy iránykvartettet

  1. g 4 {|

@kvartett 4 * {} + §irányok[] sto sirány @sirány 0 == { // fel @sy !{ {<} } pálya @sy -- @sx [[]] WAY == pálya @sy -- @sx [[]] HŐS == | { @sy -- sto szörnyy @sx sto szörnyx rts } {<} } // fel vége @sirány 1 == { // le @sy ++ MERETY -- >= { {<} } pálya @sy ++ @sx [[]] WAY == pálya @sy ++ @sx [[]] HŐS == | { @sy ++ sto szörnyy @sx sto szörnyx rts } {<} } // le vége @sirány 2 == { // balra @sx !{ {<} } pálya @sy @sx -- [[]] WAY == pálya @sy @sx -- [[]] HŐS == | { @sy sto szörnyy @sx -- sto szörnyx rts } {<} } // balra vége @sirány 3 == { // jobbra @sx ++ MERETX -- >= { {<} } pálya @sy @sx ++ [[]] WAY == pálya @sy @sx ++ [[]] HŐS == | { @sy sto szörnyy @sx ++ sto szörnyx rts } {<} } // jobbra vége |} rts irányok: 0 1 2 3 0 1 3 2 0 2 1 3 0 2 3 1 0 3 1 2 0 3 2 1 1 0 2 3 1 0 3 2 1 2 0 3 1 2 3 0 1 3 0 2 1 3 2 0 2 1 0 3 2 1 3 0 2 0 1 3 2 0 3 1 2 3 1 0 2 3 0 1 3 1 2 0 3 1 0 2 3 2 1 0 3 2 0 1 3 0 1 2 3 0 2 1 // ******************************************************************** { „k” } { „x” } { „y” } { „sx” } { „sy” } { „kar” } { „newx” } { „newy” } { „akts” } { „bombs” } { „pálya” } { „sirány” } { „sxkoord” } { „sykoord” } { „szörnyx” } { „szörnyy” } { „kvartett” } { „kirajzoló” } { „messagestring” } { „szörnymozgató” } { „kincsszámláló” } { „myerrorhandler” // A hibakezelő rutin. Igazság szerint abszolút nincs szükség rá, // de itt illik legyen a helye ha egy komolyabb progi része lenne // ez a labirintusrajzoló.

  1. g sto hibakód sto hívórutin sto hívóneve

."Hiba történt ebben a névtérben: " @hívóneve sprintnl ."Ezt a hibakódot kaptam: " @hibakód printnl end { „hibakód” } { „hívórutin” } { „hívóneve” } } // --------------------------------------------- { „üres” __usebigbossnamespace // Kitölti úttal az egész pályát, de a széleit falakkal MERETY yciklus: {| MERETX {| pálya {}§yciklus {} WAY ^ |} |} MERETY {| pálya {} 0 FAL ^ pálya {} MERETX -- FAL ^ |} MERETX {| pálya 0 {} FAL ^ pálya MERETY -- {} FAL ^ |} end } // --------------------------------------------- { „generatemaze” __usebigbossnamespace

      1. sysinclude math.uh

// Az alábbi sorban beállítjuk az errorhandler függvényt a megfelelőképpen: @initflag !{ one initflag myerrorhandler §myerrorhandlerlabel set errorhandler }

  1. g // Végig egész számokkal dolgozunk

// Az alábbi 2 sorban memóriát foglalunk 2 stringnek, amik // segédváltozókként funkcionálnak majd, flagek tárolását végzik: MERETX mem !maximize sto oszlopflag MERETY mem !maximize sto sorflag // *********************************************************** // Az oszlopok és sorok első és utolsó pozícióit bejelöljük, // mondván hogy ott már van fal. // @oszlopflag 0 1 [^] @oszlopflag @oszlopflag~ -- 1 [^] @sorflag 0 1 [^] @sorflag @sorflag~ -- 1 [^] // *********************************************************** // Az alábbi 2 ciklusban az oszlopok és sorok flagjait tároló // stringek minden páratlanadik pozícióját bejelöljük, ez jelzi // később, hogy azokkal a sorokkal illetve oszlopokkal nem kell // törődnie. Fal ugyanis csak páros indexű helyeken építhető. // MERETX -- {| {} 2 !/ then{<} @oszlopflag {+} 1 [^] |} MERETY -- {| {} 2 !/ then{<} @sorflag {+} 1 [^] |} // *********************************************************** nextrandom: // ............................................... // E két ciklus csekkolja le, van-e még olyan // sor illetve oszlop, amit nem vizsgáltunk végig. @oszlopflag {~ @@ !{ goto §kell } |} @sorflag {~ @@ !{ goto §kell } |} // ............................................... // Elhelyezzük a forgóajtókat:

doors {| newrandomneed: MERETX random sto x MERETY random sto y pálya @y @x [[]] WAY == then §newrandomneed // Most már biztos hogy itt fal van. @x 2 < then §newrandomneed @y 2 < then §newrandomneed @x MERETX 3 - > then §newrandomneed @y MERETY 3 - > then §newrandomneed // Megnézzük, függőleges ajtót betehetünk-e. pálya @y -- @x [[]] FAL == // Ha az aktuális pozíció fölött is fal van pálya @y ++ @x [[]] FAL == // Ha az aktuális pozíció alatt is fal van pálya @y -- @x -- [[]] WAY == // balfelső sarok szabad pálya @y -- @x ++ [[]] WAY == // jobbfelső sarok szabad pálya @y ++ @x -- [[]] WAY == // balalsó sarok szabad pálya @y ++ @x ++ [[]] WAY == // jobbalsó sarok szabad pálya @y @x -- [[]] WAY == // bal szomszéd szabad pálya @y @x ++ [[]] WAY == // jobb szomszéd szabad & & & & & & & else §vízszintesteszt pálya @y @x AJTÓKÖZEPE ^ pálya @y -- @x AJTÓSZÁRNYFÜGGŐLEGES ^ pálya @y ++ @x AJTÓSZÁRNYFÜGGŐLEGES ^ {<} vízszintesteszt: // Megnézzük, vízszintes ajtót betehetünk-e. pálya @y @x -- [[]] FAL == // Ha az aktuális pozíció mellett balra is fal van pálya @y @x ++ [[]] FAL == // Ha az aktuális pozíció mellett jobbra is fal van pálya @y -- @x -- [[]] WAY == // balfelső sarok szabad pálya @y -- @x ++ [[]] WAY == // jobbfelső sarok szabad pálya @y ++ @x -- [[]] WAY == // balalsó sarok szabad pálya @y ++ @x ++ [[]] WAY == // jobbalsó sarok szabad pálya @y ++ @x [[]] WAY == // fent szabad pálya @y -- @x [[]] WAY == // lent szabad & & & & & & & else §newrandomneed pálya @y @x AJTÓKÖZEPE ^ pálya @y @x -- AJTÓSZÁRNYVÍZSZINTES ^ pálya @y @x ++ AJTÓSZÁRNYVÍZSZINTES ^ |} // Elhelyezzük a kincseket. TREASUREDB {| sbr §newrandomnumber pálya @y @x TREASURE ^ |} // Elhelyezzük a bombákat. bombákszáma {| sbr §newrandomnumber pálya @y @x bomba ^ |} // Elhelyezzük a szörnyeket. Kezdetben mind gyengék. szörnyekszáma {| sbr §newrandomnumber pálya @y @x gyengeszörny ^ @sxkoord {} @x [^] @sykoord {} @y [^] |} // ............................................... @oszlopflag free @sorflag free // Az ideiglenes változók // memóriaterületének felszabadítása end kell: 4 random // Választunk egy irányt véletlenszerűen §jumpingtable[] [goto] // és elugrunk a megfelelő rutinra bal: // balról jobbra MERETY random 2 / 2 * sto aktrand // így biztos páros szám @sorflag @aktrand [] !{ MERETX -- {| pálya @aktrand {} [[]] FAL == { {<} } pálya @aktrand {+} [[]] FAL == { {<} } pálya @aktrand {} FAL ^ |} @sorflag @aktrand 1 [^] } goto §nextrandom

jobb: // jobbról balra MERETY random 2 / 2 * sto aktrand @sorflag @aktrand [] !{ MERETX -- {| pálya @aktrand {-} [[]] FAL == { {<} } pálya @aktrand {--} [[]] FAL == { {<} } pálya @aktrand {-} FAL ^ |} @sorflag @aktrand 1 [^] } goto §nextrandom

lent: // Lentről fel MERETX random 2 / 2 * sto aktrand @oszlopflag @aktrand [] !{ MERETY -- {| pálya {-} @aktrand [[]] FAL == { {<} } pálya {--} @aktrand [[]] FAL == { {<} } pálya {-} @aktrand FAL ^ |} @oszlopflag @aktrand 1 [^] } goto §nextrandom

fent: // Fentről le MERETX random 2 / 2 * sto aktrand @oszlopflag @aktrand [] !{ MERETY -- {| pálya {} @aktrand [[]] FAL == { {<} } pálya {+} @aktrand [[]] FAL == { {<} } pálya {} @aktrand FAL ^ |} @oszlopflag @aktrand 1 [^] } goto §nextrandom newrandomnumber: MERETX random sto x MERETY random sto y pálya @y @x [[]] WAY != then §newrandomnumber rts // .......................................................... myerrorhandlerlabel: fail { „x” } { „y” } { „initflag” } { „oszlopflag” } { „sorflag” } { „aktrand” } jumpingtable: §bal §jobb §lent §fent } // --------------------------------------------------------- </lang>

Output:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X             X       | X   X X X  .  X       X   X X X     X       X
X XXXXX XXX X X XXXXX o XXX X X XXX X XXXXX XbXXX X X X-o-X XXXXXXX*X
X X X . X   X X X   X | X   X X X   | X X   X X   X X X   X X     * X
X X XXX XXX X X X X X X XXX X X X X o | XXX X XXX X*X XXX X X XXXXX X
X X     X   X   X X     X   X |   X | o     X .   X X X       X     X
X X XXXXX XXX XXXXXXXXXXX XXX o XXXXX | XXXXXXXXXXX X X XXXXXXXXXXXXX
X X     X   X X     * X X   X | X   X X       X   X X X     X       X
X X XXXXX XXX X X XXXXX X XXX X X XXX X XXXXX X XXX X X XXXXX -o-XXXX
X X   @ X   X * X       X   X       X       X                $      X
X XX-o-XXXXXX XXXXXXXXXXX XXX XXXXXXX X-o-XXXXXXXXXXXXXXXXXXXXXXXXXXX
X           X X       X X   X X X   X X       X   X X X     X       X
X   XXXXX XXX X X XXXXX$X XXX X X XXX | XXXXX X XXXbX X*XXXXX X-o-XXX
X-o-    X   X X X .   X X   X X X   X o     X X . X X X     X       X
X   XXXXX XXX X X XXXXX X XXX X X X X | XXXXX X XXX X X XXXXX XX-o-XX
X X     X   X*  X       X  bX     X X       X                       X
X XXXXXXXXXXX XXXXXXXXXXX XXX XXXXXXX XXX-o-XXXXXXXXXXXXXXXXXXXXXXXXX
X   X       X X .   X X X   X X X   X X X     X   X X X   X X       X
X X.X XXX XXX X X X X X X XXX X X X X X X XXX X XXX X X XXX X XXXXXXX
X X     X   X   X X     X  .X     X X       X                       X
X XXX-o-XXXXXXXXXXXXXXXXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XX
X   X         X     X X X   X X X     X X X   X   X X X   X X     * X
X X XXX XXX X X X X X X XXX X X X X X X X X X XXX X X XXX X X XXXXX X
X |     X   X * X X     X   X X   X X X     X     X X X       X     X
X o -o-XX XXX XXXXXXXXXXX XXX X XXXXX X XXXXXXXXXXX X X XXXXXXXXXXXXX
X |     X   X           X   X       X                               X
XXXXXXXXXXX XXX-o-XXXXX XXX XXXXXXX XXXXXXX-o-XXXXXXXXXXXXXXXXXXXXX X
X   X       X X     X X X   X X X   X X X     X   X XbX     X       X
X X XXX XXX X X XXX X X XXX X X X X X X XXX X XXX X X XXXXX X-o-XXX X
  X     X   X   X                 X X       X      *b    *        * X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Collected treasure = 1    Bombs = 3

Nim

Translation of: Phix
Library: nim-ncurses

This translation uses the binding for “ncurses” and have been tested on Linux (Manjaro). <lang Nim>import os, random, sequtils, strutils, std/exitprocs, locks import ncurses

const

 KeyUp = 259
 Keydown = 258
 KeyLeft = 260
 KeyRight = 261
 Mx = 69 # No of columns (1..Mx), must be odd.
 My = 31 # No of rows (1..My), must be odd.
 Treasure = '$'
 TreasureDb= 3 # How many $ signs will be placed.
 Way = ' '
 Wall = 'X'
 Doors = 20 # No of doors.
 DoorCenter = 'o'
 DoorWingVertical = '|'
 DoorWingHorizontal = '-'
 Hero = '@'
 DeadHero = '+'
 NumberOfBombs = 5
 Bomb = 'b'
 NumberOfMonsters = 20
 Monster = '*'
 WeakMonster = '.'
 MonsterWeaknessProbability = 25
   # The higher the above number, the lower the chance that a strong monster will become weak.
 MonsterIntensifiesProbability = 5
   # The higher the number above, the lower the chance that a weak monster will get stronger.
 HelpText = """
 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. """

type

 Direction = enum dirLeft, dirRight, dirUp, dirDown
 Position = tuple[x, y: int]
 Game = object
   grid: array[1..My, array[1..Mx, char]]
   scoords: array[1..NumberOfMonsters, Position]
   showHelp: bool
   terminate: bool
   treasureCounter: Natural
   bombs: Natural
   x, y: Natural

const

 None: Position = (0, 0)
 Dy = [-1, 1, 0, 0]
 Dx = [0, 0, -1, 1]

var gameLock: Lock


proc genFlags(n: static int): array[1..n, bool] =

 for i in countup(1, n, 2):
   result[i] = true


proc initGame(): Game =

 result.bombs = 3
 for x in 1..Mx:
   result.grid[1][x] = Wall
   result.grid[My][x] = Wall
 for y in 2..<My:
   result.grid[y][1] = Wall
   for x in 2..<Mx: result.grid[y][x] = Way
   result.grid[y][Mx] = Wall
 var colFlags = genFlags(Mx)
 var rowFlags = genFlags(My)
 while colFlags.anyIt(it) or rowFlags.anyIt(it):
   let direction = Direction(rand(3))
   let j = rand(1..(if direction <= dirRight: My else: Mx)) div 2 * 2 + 1
   case direction
   of dirLeft:
     if rowFlags[j]:
       for r in 1..<Mx:
         if result.grid[j][r] != Wall and result.grid[j][r+1] != Wall:
           result.grid[j][r] = Wall
       rowFlags[j] = false
   of dirRight:
     if rowFlags[j]:
       for r in countdown(Mx, 3):
         if result.grid[j][r-1] != Wall and result.grid[j][r-2] != Wall:
           result.grid[j][r-1] = Wall
       rowFlags[j] = false
   of dirUp:
     if colFlags[j]:
       for c in countdown(My, 3):
         if result.grid[c-1][j] != Wall and result.grid[c-2][j] != Wall:
           result.grid[c-1][j] = Wall
       colFlags[j] = false
   of dirDown:
     if colFlags[j]:
       for c in 1..<My:
         if result.grid[c][j] != Wall and result.grid[c+1][j] != Wall:
           result.grid[c][j] = Wall
       colFlags[j] = false
 var doorsPlaced = 0
 while doorsPlaced < Doors:
   let x = rand(3..Mx-2)
   let y = rand(3..My-2)
   if result.grid[y][x] != Way and
       result.grid[y-1][x-1] == Way and         # top left corner free
       result.grid[y-1][x+1] == Way and         # top right corner free
       result.grid[y+1][x-1] == Way and         # left corner free
       result.grid[y+1][x+1] == Way:            # right corner free
     # Let's see if we can put a vertical door.
     if result.grid[y-1][x] == Wall and         # wall above the current position
         result.grid[y-2][x] == Wall and        # wall above the current position
         result.grid[y+1][x] == Wall and        # wall below the current position
         result.grid[y+2][x] == Wall and        # wall below the current position
         result.grid[y][x-1] == Way and         # left neighbor free
         result.grid[y][x+1] == Way:            # right neighbor free
       result.grid[y][x] = DoorCenter
       result.grid[y-1][x] = DoorWingVertical
       result.grid[y+1][x] = DoorWingVertical
       inc doorsPlaced
     # Let's see if we can put a horizontal door.
     elif result.grid[y][x-1] == Wall and       # wall left of the current position
           result.grid[y][x-2] == Wall and      # wall left of the current position
           result.grid[y][x+1] == Wall and      # wall right of the current position
           result.grid[y][x+2] == Wall and      # wall right of the current position
           result.grid[y+1][x] == Way and       # above neighbor free
           result.grid[y-1][x] == Way:          # below neighbor free
         result.grid[y][x] = DoorCenter
         result.grid[y][x-1] = DoorWingHorizontal
         result.grid[y][x+1] = DoorWingHorizontal
         inc doorsPlaced
 const Stuff = [(TreasureDb, Treasure),
                (NumberOfBombs, Bomb),
                (NumberOfMonsters, WeakMonster)]   # At first, all monsters are weak.
 for (n, what) in Stuff:
   var iter = 1
   var n = n
   while n > 0:
     let x = rand(1..Mx)
     let y = rand(1..My)
     if result.grid[y][x] == Way:
       result.grid[y][x] = what
       if what == WeakMonster:
         result.scoords[n] = (x, y)
       dec n
     inc iter
     assert iter <= 10_000    # (sanity check)
 result.x = 1
 result.y = My - 2
 result.grid[My - 2][1] = Hero


proc draw(game: ptr Game) {.thread.} =

 cursSet(0)
 while true:
   acquire gameLock
   if game.showHelp:
     erase()
     addStr HelpText
     while getch() == -1: sleep 10
     erase()
     game.showHelp = false
   erase()
   move(0, 0)
   for row in game.grid:
     addstr row.join("") & '\n'
   addstr "\n\nCollected treasures = $1     Bombs = $2\n".format(game.treasureCounter, game.bombs)
   refresh()
   if game.terminate: break
   release gameLock
   sleep 200
 release gameLock


proc monsterStepFinder(game: ptr Game; sx, sy: int): Position =

 result = None
 var m = [0, 1, 2, 3]
 m.shuffle()
 for i in m:
   let nx = sx + Dx[i]
   let ny = sy + Dy[i]
   if ny in 1..My and nx in 1..Mx and game.grid[ny][nx] in [Way, Hero]:
     result = (nx, ny)


proc monsterMove(game: ptr Game) {.thread.} =

 while not game.terminate:
   acquire gameLock
   let active = rand(1..NumberOfMonsters)
   let (sx, sy) = game.scoords[active]
   if sx != 0:
     let ch = game.grid[sy][sx]
     if ch == Monster:
       if rand(1..MonsterWeaknessProbability) == 1:
         game.grid[sy][sx] = WeakMonster
       else:
         let monster = game.monsterStepFinder(sx, sy)
         if monster != None:
           if game.grid[monster.y][monster.x] == Hero:
             game.grid[monster.y][monster.x] = DeadHero
             game.terminate = true
             break
           game.grid[sy][sx] = Way
           game.grid[monster.y][monster.x] = Monster
           game.scoords[active] = monster
     elif ch == WeakMonster:
       if rand(1..MonsterIntensifiesProbability) == 1:
         game.grid[sy][sx] = Monster
       else:
         let monster = game.monsterStepFinder(sx, sy)
         if monster != None:
           game.grid[sy][sx] = Way
           if game.grid[monster.y][monster.x] != Hero:
             game.grid[monster.y][monster.x] = WeakMonster
             game.scoords[active] = monster
           else:
             game.scoords[active] = None
   release gameLock
   sleep 100
 release gameLock


proc rotateDoor(game: var Game; nx, ny: int) =

 for i in 1..4:
   let
     wy = Dy[i-1]
     wx = Dx[i-1]
     cy = ny + wy
     cx = nx + wx
   if game.grid[cy][cx] == DoorCenter:
     if game.grid[cy-1][cx-1] == Way and
        game.grid[cy-1][cx+1] == Way and
        game.grid[cy+1][cx-1] == Way and
        game.grid[cy+1][cx+1] == Way:  # four corners empty
       let py = Dy[^i]
       let px = Dx[^i]
       if game.grid[cy+py][cx+px] == Way and
          game.grid[cy-py][cx-px] == Way:  # swung door empty
         let door = game.grid[ny][nx]
         let flip = if door == DoorWingVertical: DoorWingHorizontal else: DoorWingVertical
         game.grid[cy+py][cx+px] = flip
         game.grid[cy-py][cx-px] = flip
         game.grid[cy+wy][cx+wx] = Way
         game.grid[cy-wy][cx-wx] = Way
     break


proc keyboard(game: var Game; win: PWindow) =

 while not game.terminate:
   var key = -1
   while key == -1 and not game.terminate:
     sleep 10
     key = win.wgetch()
   acquire gameLock
   case key
   of ord('\e'), ord('q'):
     game.terminate = true
   of ord('b'):
     if game.bombs != 0:
       dec game.bombs
       for i in 0..3:
         let nx = game.x + Dx[i]
         let ny = game.y + Dy[i]
         if ny in 2..<My and nx in 2..<Mx and game.grid[ny][nx] == Wall:
           game.grid[ny][nx] = Way
   of ord('c'):
     inc game.bombs
   of ord('?'), ord('h'):
     game.showHelp = true
   else:
     let chIndex = [KeyUp, Keydown, KeyLeft, KeyRight].find(key)
     if chIndex >= 0:
       let nx = game.x + Dx[chIndex]
       let ny = game.y + Dy[chIndex]
       if ny in 2..<My and nx in 2..<Mx:
         var ch = game.grid[ny][nx]
         if ch in [DoorWingVertical, DoorWingHorizontal]:
           game.grid[game.y][game.x] = Way   # (temp. "ghost" him)
           game.rotateDoor(nx, ny)
           game.grid[game.y][game.x] = Hero
           ch = game.grid[ny][nx]            # (maybe unaltered)
         elif ch == Monster:
           game.grid[game.y][game.x] = Way
           game.grid[ny][nx] = DeadHero
           game.y = ny
           game.x = nx
           game.terminate = true
         elif ch == Treasure:
           inc game.treasureCounter
           if game.treasureCounter == TreasureDb:
             game.terminate = true
           ch = Way
         elif ch == Bomb:
           inc game.bombs
           ch = Way
         if ch in [Way, WeakMonster]:
           game.grid[game.y][game.x] = Way
           game.grid[ny][nx] = Hero
           game.y = ny
           game.x = nx
   release gameLock
 while getch() != -1: discard   # (purge kbd buffer)


proc play() =

 randomize()
 let win = initscr()
 win.nodelay(true)
 win.keypad(true)
 noecho()
 cbreak()
 addExitProc proc() = endwin()
 addExitProc proc() = cursSet(1)
 var game = initGame()
 var tdraw, tmove: Thread[ptr Game]
 createThread(tdraw, draw, addr(game))
 createThread(tmove, monsterMove, addr(game))
 game.keyboard(win)
 joinThreads(tdraw, tmove)
 if game.treasureCounter == TreasureDb:
   addstr "\nYOU WON! Congratulations!\n"
   refresh()
   while getch() == -1: sleep(1)
 elif game.grid[game.y][game.x] == DeadHero:
   addstr "\nYOU PERISHED!\n"
   refresh()
   while getch() == -1: sleep(1)


play()</lang>

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>