CLI-based maze-game

From Rosetta Code
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

###sysinclude terminal.uh
###sysinclude into.uh
###sysinclude math.uh

###define VÁRAKOZIK 40000
// Minél nagyobb a fenti szám, annál lassabban mozognak a szörnyek.
###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.
###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.
###define TREASURE '$
###define TREASUREDB 3
// A treasuredb jelenti, hány $ jel lesz elhelyezve
###define WAY 32
###define FAL 'X
###define wayszín 0
###define wayháttérszín 0
// Az alábbi doors az ajtók számát jelzi a labirintus falaiban.
###define doors 20
###define AJTÓKÖZEPE 'o
###define AJTÓSZÁRNYFÜGGŐLEGES '|
###define AJTÓSZÁRNYVÍZSZINTES '-
###define AJTÓszín $e
###define AJTÓháttérszín 0
###define FALszín $1b
###define FALháttérszín FALszín
###define HŐS '@
###define HALOTTHŐS '+
###define HŐSszín 9
###define HŐSháttérszín 0
###define kincsszín $b
###define kincsháttérszín 0
// Ennyi bombát lehet találni a labirintusban:
###define bombákszáma 5
###define bomba 'b
###define bombaszín $a6
###define bombaháttérszín 0

###define szörnyekszáma 20
###define szörny '*
###define szörnyszín $d
###define szörnyháttérszín 0
###define gyengeszörny '.
###define gyengeszörnyszín $cd
###define gyengeszörnyháttérszín 0
###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.
###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
#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
#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
#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
#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ó.
#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
###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 }

#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
}
// ---------------------------------------------------------
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

Julia

Translation of: Nim
using Ansillary
using Crayons
using Random

const Mx = 69 # No of columns (1..Mx), must be odd.
const My = 31 # No of rows (1..My), must be odd.
const Treasure = '$'
const TreasureDb = 3 # How many $ signs will be placed.
const Way = ' '
const Wall = 'X'
const Doors = 20 # No of doors.
const DoorCenter = 'o'
const DoorWingVertical = '|'
const DoorWingHorizontal = '-'
const Hero = '@'
const DeadHero = '+'
const NumberOfBombs = 5
const Bomb = 'b'
const NumberOfMonsters = 20
const Monster = '*'
const WeakMonster = '.'
const MonsterWeaknessProbability = 25
    # The higher the above number, the lower the chance that a strong monster will become weak.
const MonsterIntensifiesProbability = 5
    # The higher the number above, the lower the chance that a weak monster will get stronger.
const 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 get the bomb with it, so that 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 move into a door wing in the right direction with
your character, as long as nothing stands in the way of door 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 increases the
number of remaining bombs by one.

(This help screen closes after 10 seconds.)
"""

const Position = NamedTuple{(:x, :y)}

mutable struct Game
    grid::Matrix{Char}
    scoords::Vector{Position}
    showhelp::Bool
    terminate::Bool
    counterschanged::Bool
    treasurecounter::Int
    bombs::Int
    x::Int
    y::Int
end

const NoPosition = Position((0, 0))
const Dy = [-1, 1, 0, 0]
const Dx = [0, 0, -1, 1]
@enum Direction Left Right Up Down
const gamelock = ReentrantLock()

""" Game constructor for game initialization """
function Game()
    grid = fill(Way, My, Mx)
    grid[[begin, end], begin:end] .= Wall
    grid[begin+1:end-1, [begin, end]] .= Wall
    colflags = [isodd(n) for n in 1:Mx]
    rowflags = [isodd(n) for n in 1:My]

    while any(colflags) || any(rowflags)
        direction = rand([Left, Right, Up,  Down])
        j = rand(1:(direction in [Left, Right] ? My : Mx)) ÷ 2 * 2 + 1 # if even, add one
        if direction == Left && rowflags[j]
            for r in 1:Mx-1
                if grid[j, r] != Wall && grid[j, r+1] != Wall
                    grid[j, r] = Wall
                end
            end
            rowflags[j] = false
        elseif direction == Right && rowflags[j]
            for r in Mx:-1:3
                if grid[j, r-1] != Wall && grid[j, r-2] != Wall
                    grid[j, r-1] = Wall
                end
            end
            rowflags[j] = false
        elseif direction == Up && colflags[j]
            for c in My:-1:3
                if grid[c-1, j] != Wall && grid[c-2, j] != Wall
                    grid[c-1, j] = Wall
                end
            end
            colflags[j] = false
        elseif direction == Down && colflags[j]
            for c in 1:My-1
                if grid[c, j] != Wall && grid[c+1, j] != Wall
                    grid[c, j] = Wall
                end
            end
            colflags[j] = false
        end
    end
    doorsplaced = 0
    while doorsplaced < Doors
        x = rand(3:Mx-2)
        y = rand(3:My-2)
        if grid[y, x] != Way && grid[y-1, x-1] == Way && grid[y-1, x+1] == Way &&
           grid[y+1, x-1] == Way && grid[y+1, x+1] == Way # corners free?
            if grid[y-1, x] == Wall && grid[y-2, x] == Wall && grid[y+1, x] == Wall &&
               grid[y+2, x] == Wall && grid[y, x-1] == Way && grid[y, x+1] == Way
                grid[y, x] = DoorCenter
                grid[y-1, x] = DoorWingVertical
                grid[y+1, x] = DoorWingVertical
                doorsplaced += 1
            elseif grid[y, x-1] == Wall && grid[y, x-2] == Wall && grid[y, x+1] == Wall &&
               grid[y, x+2] == Wall && grid[y+1, x] == Way && grid[y-1, x] == Way
                grid[y, x] = DoorCenter
                grid[y, x-1] = DoorWingHorizontal
                grid[y, x+1] = DoorWingHorizontal
                doorsplaced += 1
            end
        end
    end
    # note all monsters start as weak (weak ones count == NumberofMonsters)
    scoords = Position[]
    stuff = [(TreasureDb, Treasure), (NumberOfBombs, Bomb),(NumberOfMonsters, WeakMonster)]
    for (n, what) in stuff
        iterations = 1
        cnt = n
        while cnt > 0
            x = rand(1:Mx)
            y = rand(1:My) 
            if grid[y, x] == Way
                grid[y, x] = what
                cnt -= 1
                what == WeakMonster && push!(scoords, Position((x, y)))
            end
            iterations += 1
            @assert iterations <= 10_000 # (sanity check)
        end
    end
    grid[end-1, begin+1] = Hero
    return Game(grid, scoords, false, false, true, 0, 3, 2, My - 1)
end

function draw!(game)
    while true
        lock(gamelock)
        if game.showhelp
            Screen.clear!(Screen.All())
            Cursor.move!(Cursor.Coordinate(1, 1))
            print(HelpText)
            sleep(10)
            Screen.clear!(Screen.All())
            game.showhelp = false
            game.counterschanged = true
        end
        Cursor.move!(Cursor.Coordinate(1, 1))
        for row in eachrow(game.grid)
            s = join(row) # colorize
            s = replace(s, Treasure => "$(crayon"light_green")$Treasure$(crayon"white")")
            s = replace(s, Monster => "$(crayon"light_red")$Monster$(crayon"white")")
            s = replace(s, Hero => "$(crayon"light_yellow")$Hero$(crayon"white")")
            s = replace(s, Bomb => "$(crayon"light_blue")$Bomb$(crayon"white")")
            println(s)
        end
        if game.counterschanged
            print("\n\nCollected treasures = $(game.treasurecounter)     Bombs = $(game.bombs)\n")
            game.counterschanged = false
        end
        unlock(gamelock)
        game.terminate && break
        sleep(0.05)
    end
end

function monsterstepfinder(game, sx, sy)
    result = NoPosition
    for i in shuffle(1:4)
        nx = sx + Dx[i]
        ny = sy + Dy[i]
        if ny in 1:My && nx in 1:Mx && game.grid[ny, nx] in [Way, Hero]
            result = Position((nx, ny))
        end
    end
    return result
end

function monstermove!(game)
    cnt = 0
    while true
        active = rand(1:NumberOfMonsters)
        pos = game.scoords[active]
        sx, sy = pos.x, pos.y
        if sy in 1:My && sx in 1:Mx
            ch = game.grid[sy, sx]
            if ch == Monster
                if rand(1:MonsterWeaknessProbability) == 1
                    game.grid[sy, sx] = WeakMonster
                else
                    monster = monsterstepfinder(game, sx, sy)
                    if monster != NoPosition && monster.y in 1:My && monster.x in 1:Mx
                        if game.grid[monster.y, monster.x] == Hero
                            game.grid[monster.y, monster.x] = DeadHero
                            game.terminate = true
                            break
                        end
                    end
                    game.grid[sy, sx] = Way
                    if monster.y in 1:My && monster.x in 1:Mx
                        game.grid[monster.y, monster.x] = Monster
                        game.scoords[active] = monster
                    end
                end
            elseif ch == WeakMonster
                if rand(1:MonsterIntensifiesProbability) == 1
                    game.grid[sy, sx] = Monster
                else
                    monster = monsterstepfinder(game, sx, sy)
                    if monster != NoPosition && monster.y in 1:My && monster.x in 1:Mx
                        if game.grid[monster.y, monster.x] != Hero
                            game.grid[monster.y, monster.x] = WeakMonster
                            game.scoords[active] = monster
                        else
                            game.scoords[active] = NoPosition
                        end
                    end
                end
            end
        end
        sleep(0.2)
    end
end

function rotatedoor!(game, nx, ny)
    for i in 1:4
        wy = Dy[i]
        wx = Dx[i]
        cy = ny + wy
        cx = nx + wx
        if game.grid[cy, cx] == DoorCenter
            if game.grid[cy-1, cx-1] == Way &&
              game.grid[cy-1, cx+1] == Way &&
              game.grid[cy+1, cx-1] == Way &&
              game.grid[cy+1, cx+1] == Way  # four corners empty
                py = Dy[end-i+1]
                px = Dx[end-i+1]
                if game.grid[cy+py, cx+px] == Way &&
                  game.grid[cy-py, cx-px] == Way  # swung door empty
                    door = game.grid[ny, nx]
                    flip = door == DoorWingVertical ? DoorWingHorizontal : 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
                end
            end
            break
        end
    end
end

function keyboard!(game)
    cnt = 0
    Screen.raw() do
        for event in Inputs.Events()
            key = lowercase(string(event))
            sleep(0.01)
            if key in ["esc", "q"]
                game.terminate = true
                break
            elseif key == "b"
                if game.bombs > 0
                    lock(gamelock)
                    game.bombs -= 1
                    game.counterschanged = true
                    for i in 1:4
                        nx = game.x + Dx[i]
                        ny = game.y + Dy[i]
                        if ny in 2:My-1 && nx in 2:Mx-1 && game.grid[ny, nx] == Wall
                            game.grid[ny, nx] = Way
                        end
                    end
                    unlock(gamelock)
                end
            elseif key == "c"
                game.bombs += 1
                game.counterschanged = true
            elseif key in ["?", "h"]
                game.showhelp = true
            else
                chindex = findfirst(==(key), ["up", "down", "left", "right"])
                if chindex != nothing
                    nx = game.x + Dx[chindex]
                    ny = game.y + Dy[chindex]
                    if ny in 2:My-1 && nx in 2:Mx-1
                        ch = game.grid[ny, nx]
                        if ch in [DoorWingVertical, DoorWingHorizontal]
                                lock(gamelock)
                                game.grid[game.y, game.x] = Way   # (temp. "ghost" him)
                                rotatedoor!(game, nx, ny)
                                game.grid[game.y, game.x] = Hero
                                unlock(gamelock)
                                ch = game.grid[ny, nx]            # (maybe unaltered)
                        elseif ch == Monster
                            lock(gamelock)
                            game.grid[game.y, game.x] = Way
                            game.grid[ny, nx] = DeadHero
                            game.y = ny
                            game.x = nx
                            game.terminate = true
                            unlock(gamelock)
                            break
                        elseif ch == Treasure
                            game.treasurecounter += 1
                            game.counterschanged = true
                            ch = Way
                            if game.treasurecounter == TreasureDb
                                lock(gamelock)
                                game.grid[game.y, game.x] = Way
                                game.grid[ny, nx] = Hero
                                game.y = ny
                                game.x = nx
                                game.terminate = true
                                unlock(gamelock)
                                break
                            end
                        elseif ch == Bomb
                            game.bombs += 1
                            game.counterschanged = true
                            ch = Way
                        end
                        if ch in [Way, WeakMonster]
                            lock(gamelock)
                            game.grid[game.y, game.x] = Way
                            game.grid[ny, nx] = Hero
                            game.y = ny
                            game.x = nx
                            unlock(gamelock)
                        end
                    end
                end
            end
            sleep(0.01)
        end
    end
end

function play()
    print(Crayon(background=(0,0,0), foreground=(250,250,250))) # white on black
    Screen.clear!(Screen.All())
    game = Game()
    @async draw!(game)
    @async keyboard!(game)
    @async monstermove!(game)
    while !game.terminate
        sleep(1)
    end
    if game.treasurecounter == TreasureDb
        print("\nYOU WON! Congratulations!\n")
    elseif game.grid[game.y, game.x] == DeadHero
        print("\nYOU PERISHED!\n")
    end
end

play()
Output:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X   X   .   X       X       X  .    X X     X   .   X     X   X    .X
X XXX XXX XXX.XXXXXXX XXXXXXX X.XXXXX X X XXX XXXXX X X XXX XXX X XXX
X   X   X   X       X       X X     X X X   X     | X X   X   X X   X
XXX XXX XXX XXXXXXX XXX X X X XXX X X X XXX XXXXX o X XXX XXX X XXX X
X   X   X  b            X X.  X   X     X         |   X       $ X   X
X XXX XXX-o-XXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXX-o-XXXXXXX
X   X     ..X               X.X     X.X     X     X       X   X     X
XXX XXX XXX.XXXXXXXXXXXXXXX X XXXXXbX X XXX XXXXX XXX XXX XXX.X XXX X
X       X                     X         X         X   X      .  X   X
XXXXXXXXXXXXXXXX-o-XXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XXXXXXXXXXXXXXXXXX X
X   X    .  X       X       X       X X     X      .X     X b X     X
X XXX XXX XXX XXXXXXX XXXXXXX X XXXXX X X XXX XXXXX.X X XXX XXX X XXX
X   X   X   X       X       X X     X X X   X     X X X   X   X X   X
XXX XXX XXX XXXXXXX.XXX-o-X X XXXXX X X XXX XXXXX.X X XXX XXX X XXX X
X       X          .          X         X         X   X         X   X
X XXXXXXXX-o-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X   X            $                                                  X
X XXX XXXXXXXXXXX-o-XXXXXXXXXXX XXXXXXXXXX-o-XXXX-o-X-o-XXXXXXXXXXXXX
X             b               X          $                ..        X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XXXX-o-XXXXXX X
Xb  X           .                                                   X
XXX XXXXXXXXXXXXXXXXXXXXX-o-X.XXXXX-o-XXXXX-o-XXX XXXXXXXXX-o-XXXXX X
X                             X            ..     X    .            X
X XXXXXXX-o-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XXXXXXXXXX
X                                                                   X
XXXXXXXXXXXXXXXXX-o-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 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 X X XXX X X X X X X X X X X X X X X X X X X X XXX X*X X XXX
X@X   X X       X X     X X   X   X     X         X   X         X   X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


Collected treasures = 0     Bombs = 3

Peri

###sysinclude standard.uh
###sysinclude system.uh
###sysinclude into.uh
###sysinclude math.uh
###sysinclude args.uh
###sysinclude str.uh
###sysinclude io.uh

###define VÁRAKOZIK 40000
// Minél nagyobb a fenti szám, annál lassabban mozognak a szörnyek.
###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.
###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.
###define TREASURE '$
###define TREASUREDB 3
// A treasuredb jelenti, hány $ jel lesz elhelyezve
###define WAY 32
###define FAL 'X
###define wayszín 0
###define wayháttérszín 0
// Az alábbi doors az ajtók számát jelzi a labirintus falaiban.
###define doors 20
###define AJTÓKÖZEPE 'o
###define AJTÓSZÁRNYFÜGGŐLEGES '|
###define AJTÓSZÁRNYVÍZSZINTES '-
###define AJTÓszín $e
###define AJTÓhszin 0
###define FALszín $1b
###define FALháttérszín FALszín
###define HŐS '@
###define HALOTTHŐS '+
###define HŐSszín 9
###define HŐSháttérszín 0
###define kincsszín $b
###define kincsháttérszín 0
// Ennyi bombát lehet találni a labirintusban:
###define bombákszáma 5
###define bomba 'b
###define bombaszín $a6
###define bombahszin 0

###define szörnyekszáma 20
###define szörny '*
###define szörnyszín $d
###define szörnyhszin 0
###define gyengeszörny '.
###define gyengeszörnyszín $cd
###define gyengeszörnyhszin 0
###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.
###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.


#g 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 Peri 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
MERETY MERETX [[mem...]]! sto pálya
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


// ---------------------------------------------
// Elkészítjük az üres területet, falakkal körülhatárolva.
// Kitölti úttal az egész pályát, de a széleit falakkal.
MERETY yciklus: {{ MERETX {{
{{}}§yciklus {{}} WAY inv [[pálya]][]
}} }}
MERETY {{ {{}} 0 FAL inv [[pálya]][] {{}} MERETX -- FAL inv [[pálya]][] }}
MERETX {{ 0 {{}} FAL inv [[pálya]][] MERETY -- {{}} FAL inv [[pálya]][] }}
// ---------------------------------------------
// Ez legenerálja véletlenszerűen a labirintust
#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 inv []
@oszlopflag oszlopflag~ -- 1 inv []
@sorflag    0 1 inv []
@sorflag    sorflag~    -- 1 inv []

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

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

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

fent: // Fentről le
MERETX random 2 / 2 * sto aktrand
@oszlopflag @aktrand [] inv {
MERETY -- {{
{{}}  @aktrand [[pálya]][] FAL == then {{<}}
{{+}} @aktrand [[pálya]][] FAL == then {{<}}
{{}}  @aktrand  FAL inv [[pálya]][]
}}
@oszlopflag @aktrand 1 inv []
}
goto §nextrandom
newrandomnumber:
MERETX random sto xx MERETY random sto yy @yy @xx [[pálya]][] WAY != then §newrandomnumber
rts

indulajáték:
."Indul a játék\n"
// ---------------------------------------------
// ********************************************************************
//
// Ki- és bejáratok generálása, ha szükséges:
//
MERETY 2 - dup sto yy sto newy 0 dup sto xx sto newx
@yy @xx HŐS inv [[pálya]][] // A hős karakterének letevése
// ********************************************************************

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

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

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

// ********************************************************************
vége2:
// üzenetküldés a child processeknek hogy álljanak le
@messagestring 0 1 inv []
@messagestring 5 1 inv []
// Várakozás a child processek befejeződésére:
@szörnymozgató wait
@kirajzoló     wait
vége:

@messagestring inv mem
@sxkoord inv mem
@sykoord inv mem
@pálya   inv mem

,,, cursoron
end
// ********************************************************************

kirajzol:
closestdin // Nem várunk semmi billentyűzetinputot
{.. // végtelenciklus
// ..................................................................
@messagestring 0 [] { end } // Parancs érkezett szeppuku elkövetésére...
// ..................................................................
topleft
#k MERETY yloop: {{ MERETX {{
{{}}§yloop {{}} [[pálya]][] WAY == { wayszín tint wayháttérszín inv tint {{}}§yloop {{}} [[pálya]][] print {{<}}  }
{{}}§yloop {{}} [[pálya]][] FAL == { FALszín tint FALháttérszín inv tint {{}}§yloop {{}} [[pálya]][] print {{<}}  }
{{}}§yloop {{}} [[pálya]][] AJTÓSZÁRNYFÜGGŐLEGES == { AJTÓszín   tint AJTÓhszin   inv tint {{}}§yloop {{}} [[pálya]][] print {{<}} }
{{}}§yloop {{}} [[pálya]][] AJTÓSZÁRNYVÍZSZINTES == { AJTÓszín   tint AJTÓhszin   inv tint {{}}§yloop {{}} [[pálya]][] print {{<}} }
{{}}§yloop {{}} [[pálya]][] AJTÓKÖZEPE           == { AJTÓszín   tint AJTÓhszin   inv tint {{}}§yloop {{}} [[pálya]][] print {{<}} }
{{}}§yloop {{}} [[pálya]][] bomba                == { bombaszín  tint bombahszin  inv tint {{}}§yloop {{}} [[pálya]][] print {{<}} }
{{}}§yloop {{}} [[pálya]][] szörny               == { szörnyszín tint szörnyhszin inv tint {{}}§yloop {{}} [[pálya]][] print {{<}} }
{{}}§yloop {{}} [[pálya]][] gyengeszörny         == {
gyengeszörnyszín tint gyengeszörnyhszin inv tint {{}}§yloop {{}} [[pálya]][] print {{<}} }
{{}}§yloop {{}} [[pálya]][] HŐS           == { HŐSszín tint HŐSháttérszín inv tint {{}}§yloop {{}} [[pálya]][] print {{<}} }
{{}}§yloop {{}} [[pálya]][] HALOTTHŐS     == { HŐSszín tint HŐSháttérszín inv tint {{}}§yloop {{}} [[pálya]][] print {{<}} }
{{}}§yloop {{}} [[pálya]][] 'a >= {{}}§yloop {{}} [[pálya]][] 'z <= &
{ kincsszín tint kincsháttérszín inv tint {{}}§yloop {{}} [[pálya]][] print {{<}} }
,,, @pálya {{}}§yloop {{}} [][] print
}} ,,, NL }} NL
."Collected treasure = " #g @messagestring 2 [] print ."    Bombs = " @messagestring 1 [] printnl
VÁRAKOZIK inv sleep
..}
// ********************************************************************
szörnymozgat:
closestdin closestdout closestderr // Nem várunk semmi billentyűzetinputot és nem is írunk sehova
randinit
{.. // végtelenciklus
6000 inv sleep
// .....................................................................
@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 | inv { {.<.} }
@sy @sx [[pálya]][] szörny == {
szörnygyengülvalószínűség random 1 == { @pálya @sy @sx gyengeszörny inv [][] {.<.} }
sbr §szörnylépéskeres
#g
@szörnyy @szörnyx | else {.<.} // Ha nem talált helyet ahova mozoghatna
@szörnyy @szörnyx [[pálya]][] HŐS == { @pálya @szörnyy @szörnyx HALOTTHŐS inv [][] @messagestring 6 1 inv [] 1000 inv sleep {.<.} }
@pálya @sy @sx WAY inv [][] @pálya @szörnyy @szörnyx szörny inv [][]
@sxkoord @akts @szörnyx inv [] @sykoord @akts @szörnyy inv []
{.<.}
}
@sy @sx [[pálya]][] gyengeszörny == {
szörnyerősödikvalószínűség random 1 == { @pálya @sy @sx szörny inv [][] {.<.} }
sbr §szörnylépéskeres
#g
@szörnyy @szörnyx | else {.<.} // Ha nem talált helyet ahova mozoghatna
@pálya @sy @sx WAY inv [][]
@szörnyy @szörnyx [[pálya]][] 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 inv [][]
}{ zero szörnyx zero szörnyy }
@sxkoord @akts @szörnyx inv [] @sykoord @akts @szörnyy inv []
{.<.}
}


..}
// ..................................................................
szörnylépéskeres:
zero szörnyy zero szörnyx
24 random sto kvartett // Választunk egy iránykvartettet
#g 4 {{
@kvartett 4 * {{}} + §irányok[] sto sirány
@sirány 0 == { // fel
@sy else {{<}}
@sy -- @sx [[pálya]][] WAY ==
@sy -- @sx [[pálya]][] HŐS == | { @sy -- sto szörnyy @sx sto szörnyx rts }
{{<}}
} // fel vége
@sirány 1 == { // le
@sy ++ MERETY -- >= then {{<}}
@sy ++ @sx [[pálya]][] WAY ==
@sy ++ @sx [[pálya]][] HŐS == | { @sy ++ sto szörnyy @sx sto szörnyx rts }
{{<}}
} // le vége
@sirány 2 == { // balra
@sx else {{<}}
@sy @sx -- [[pálya]][] WAY ==
@sy @sx -- [[pálya]][] HŐS == | { @sy sto szörnyy @sx -- sto szörnyx rts }
{{<}}
} // balra vége
@sirány 3 == { // jobbra
@sx ++ MERETX -- >= then {{<}}
@sy @sx ++ [[pálya]][] WAY ==
@sy @sx ++ [[pálya]][] 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
// ********************************************************************
{ „kk” }
{ „xx” }
{ „yy” }
{ „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ó” }
// ---------------------------------------------
// ..........................................................
{ „initflag” }
{ „oszlopflag” }
{ „sorflag” }
{ „aktrand” }
jumpingtable: §bal §jobb §lent §fent

// ---------------------------------------------------------
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).

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()

Phix

-- demo/rosetta/CLI_maze.exw
without js -- (wait_key(), get_key(), position(), clear_screen(), etc)
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),
         inw = WALL&repeat(WAY,MX-2)&WALL,
         grid = {tb}&repeat(inw,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

Wren

Translation of: Nim
Translation of: Phix
Library: ncurses
Library: Wren-dynamic
Library: Wren-str
Library: Wren-iterate

An embedded script so we can use the ncurses library.

/* CLI-based_maze_game.wren */

import "./dynamic" for Enum, Tuple, Struct
import "./str" for Char
import "./iterate" for Stepped
import "random" for Random

// all methods assume stdscr
class NC {
    foreign static initScr()

    foreign static cbreak()
    foreign static nocbreak()

    foreign static keypad(bf)

    foreign static echo()
    foreign static noecho()

    foreign static cursSet(visibility)

    foreign static erase()

    foreign static addStr(str)

    foreign static getch()

    foreign static move(y, x)

    foreign static refresh()

    foreign static endwin()
}

var KeyUp    = 259
var KeyDown  = 258
var KeyLeft  = 260
var KeyRight = 261

var Mx = 69  // no of columns (0..Mx-1), must be odd
var My = 31  // no of rows (0..My-1), must be odd
var Treasure = Char.code("$")
var TreasureDb = 3 // how many $ signs will be placed
var Way  = Char.code(" ")
var Wall = Char.code("X")
var Doors = 20 // no of doors
var DoorCenter = Char.code("o")
var DoorWingVertical = Char.code("|")
var DoorWingHorizontal = Char.code("-")
var Hero = Char.code("@")
var DeadHero = Char.code("+")
var NumberOfBombs = 5
var Bomb = Char.code("b")
var NumberOfMonsters = 20
var Monster = Char.code("*")
var WeakMonster = Char.code(".")

// the higher this is, the lower the chance that a string monster will become weak
var MonsterWeaknessProbability = 25

// the higher this is, the lower the chance that a weak monster will get stronger
var MonsterIntensifiesProbability = 5

var 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 increases by one
the amount of your bombs.
"""

var Direction = Enum.create("Direction", ["left", "right", "up", "down"])
var Position = Tuple.create("Position", ["x", "y"])

var gameFields = ["grid", "scoords", "showHelp", "terminate", "treasureCounter", "bombs", "x", "y"]
var Game = Struct.create("Game", gameFields)

var None = Position.new(0, 0)
var Dy = [-1, 1, 0, 0]
var Dx = [0, 0, -1, 1]

var rand = Random.new()

var genFlags = Fn.new { |n|
    var flags = List.filled(n, false)
    for (i in Stepped.new(0...n, 2)) flags[i] = true
    return flags
}

var initGame = Fn.new {
    var grid = List.filled(My, null)
    for (y in 0...My) grid[y] = List.filled(Mx, Wall)
    for (y in 1...My-1) {
        for (x in 1...Mx-1) grid[y][x] = Way
    }
    var colFlags = genFlags.call(Mx)
    var rowFlags = genFlags.call(My)
    while (colFlags.any { |f| f } || rowFlags.any { |f| f }) {
        var dir = rand.int(4)
        var j = rand.int((dir <= Direction.right) ? My : Mx)
        if (j % 2 == 1) j = j + 1
        if (dir == Direction.left) {
            if (rowFlags[j]) {
                for (r in 0...Mx-1) {
                    if (grid[j][r] != Wall && grid[j][r+1] != Wall) grid[j][r] = Wall
                }
                rowFlags[j] = false
            }
        } else if (dir == Direction.right) {
            if (rowFlags[j]) {
                for (r in Mx-1..2) {
                    if (grid[j][r-1] != Wall && grid[j][r-2] != Wall) grid[j][r-1] = Wall
                }
                rowFlags[j] = false
            }
        } else if (dir == Direction.up) {
            if (colFlags[j]) {
                for (c in My-1..2) {
                    if (grid[c-1][j] != Wall && grid[c-2][j] != Wall) grid[c-1][j] = Wall
                }
                colFlags[j] = false
            }
        } else if (dir == Direction.down) {
            if (colFlags[j]) {
                for (c in 0...My-1) {
                    if (grid[c][j] != Wall && grid[c+1][j] != Wall) grid[c][j] = Wall
                }
                colFlags[j] = false
            }
        }
    }
    var doorsPlaced = 0
    while (doorsPlaced < Doors) {
        var x = rand.int(2, Mx - 2)
        var y = rand.int(2, My - 2)
        if (grid[y][x]     != Way  &&
            grid[y-1][x-1] == Way  &&  // top left corner free
            grid[y-1][x+1] == Way  &&  // top right corner free
            grid[y+1][x-1] == Way  &&  // left corner free
            grid[y+1][x+1] == Way) {   // right corner free
            // let's see if we can put a vertical door
            if (grid[y-1][x] == Wall &&    // wall above the current position
                grid[y-2][x] == Wall &&    // wall above the current position
                grid[y+1][x] == Wall &&    // wall below the current position
                grid[y+2][x] == Wall &&    // wall below the current position
                grid[y][x-1] == Way  &&    // left neighbor free
                grid[y][x+1] == Way) {     // right neighbor free         
                grid[y][x]   = DoorCenter
                grid[y-1][x] = DoorWingVertical
                grid[y+1][x] = DoorWingVertical
                doorsPlaced  = doorsPlaced + 1
            // let's see if we can put a horizontal door
            } else if (grid[y][x-1] == Wall &&   // wall left of the current position
                       grid[y][x-2] == Wall &&   // wall left of the current position
                       grid[y][x+1] == Wall &&   // wall right of the current position
                       grid[y][x+2] == Wall &&   // wall right of the current position
                       grid[y+1][x] == Way  &&   // above neighbor free
                       grid[y-1][x] == Way) {    // below neighbor free
                grid[y][x]   = DoorCenter
                grid[y][x-1] = DoorWingHorizontal
                grid[y][x+1] = DoorWingHorizontal
                doorsPlaced  = doorsPlaced + 1
            }
        }
    }
    var scoords = List.filled(NumberOfMonsters, null)
    for (i in 0...NumberOfMonsters) scoords[i] = Position.new(0, 0)
    var stuff = [
        [TreasureDb, Treasure],
        [NumberOfBombs, Bomb],
        [NumberOfMonsters, WeakMonster] // at first, all monsters are weak
    ]
    for (s in stuff) {
        var n = s[0]
        var what = s[1]
        var iter = 1
        while (n >= 0) {
            var x = rand.int(Mx)
            var y = rand.int(My)
            if (grid[y][x] == Way) {
                grid[y][x] = what
                if (what == WeakMonster) scoords[n-1] = Position.new(x, y)
                n = n - 1
            }
            iter = iter + 1
            if (iter > 10000) Fiber.abort("Something went wrong.") // sanity check
        }
    }
    grid[My - 2][1] = Hero
    return Game.new(grid, scoords, false, false, 0, 3, 1, My - 2)
}

var draw = Fn.new { |game|
    NC.cursSet(0)
    while (true) {
        if (game.showHelp) {
            NC.erase()
            NC.addStr(HelpText)
            NC.getch()
            NC.erase()
            game.showHelp = false
        }
        NC.erase()
        NC.move(0, 0)
        for (row in game.grid) NC.addStr(row.map { |c| String.fromByte(c) }.join() + "\n")
        NC.addStr("\n\nCollected treasure = %(game.treasureCounter)     Bombs = %(game.bombs)\n")
        NC.refresh()
        Fiber.yield()
    }
}

var monsterStepFinder = Fn.new { |game, sx, sy|
    var result = None
    var m = [0, 1, 2, 3]
    rand.shuffle(m)
    for (i in m) {
        var nx = sx + Dx[i]
        var ny = sy + Dy[i]
        if (ny >= 0 && ny < My && nx >= 0 && nx < Mx && [Way, Hero].contains(game.grid[ny][nx])) {
            result = Position.new(nx, ny)
        }
    }
    return result
}

var monsterMove = Fn.new { |game|
    while (true) {
        var active = rand.int(NumberOfMonsters)
        var pos = game.scoords[active]
        var sx = pos.x
        var sy = pos.y
        if (sx != 0) {
            var ch = game.grid[sy][sx]
            if (ch == Monster) {
                if (rand.int(MonsterWeaknessProbability) == 0) {
                    game.grid[sy][sx] = WeakMonster
                } else {
                    var monster = monsterStepFinder.call(game, sx, sy)
                    if (monster.x != 0 && monster.y != 0) {
                        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
                }
            } else if (ch == WeakMonster) {
                if (rand.int(MonsterIntensifiesProbability) == 0) {
                    game.grid[sy][sx] = Monster
                } else {
                    var monster = monsterStepFinder.call(game, sx, sy)
                    if (monster.x != 0 && monster.y != 0) {
                        if (game.grid[monster.y][monster.x] == Hero) {
                            game.grid[monster.y][monster.x] = WeakMonster
                            game.scoords[active] = monster
                            break
                        } else {
                            game.scoords[active] = None
                        }
                    }
                }
            }
        }
        Fiber.yield()
    }
}

var rotateDoor = Fn.new { |game, nx, ny|
    for (i in 1..4) {
        var wy = Dy[i-1]
        var wx = Dx[i-1]
        var cy = ny + wy
        var cx = nx + wx
        if (game.grid[cy][cx] == DoorCenter) {
            if (game.grid[cy-1][cx-1] == Way &&
                game.grid[cy-1][cx+1] == Way &&
                game.grid[cy+1][cx-1] == Way &&
                game.grid[cy+1][cx+1] == Way) {  // 4 corners empty
                var py = Dy[-i]
                var px = Dx[-i]
                if (game.grid[cy+py][cx+px] == Way &&
                    game.grid[cy-py][cx-px] == Way) { // swung door empty
                    var door = game.grid[ny][nx]
                    var flip = DoorWingVertical ? DoorWingHorizontal : 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
        }
    }
}

var keyboard = Fn.new { |game|
    while (true) {
        var key = NC.getch()
        if (key == Char.code("\e") || key == Char.code("q")) {
            game.terminate = true
            break
        } else if (key == Char.code("b")) {
            if (game.bombs != 0) {
                game.bombs = game.bombs - 1
                for (i in 0..3) {
                    var nx = game.x + Dx[i]
                    var ny = game.y + Dy[i]
                    if (ny >= 1 && ny < My-1 && nx >= 1 && nx < Mx-1 && game.grid[ny][nx] == Wall) {
                        game.grid[ny][nx] =  Way
                    }
                }
            }
        } else if (key == Char.code("c")) {
            game.bombs = game.bombs + 1
        } else if (key == Char.code("?") || key == Char.code("h")) {
            game.showHelp = true
        } else {
            var chIndex = [KeyUp, KeyDown, KeyLeft, KeyRight].indexOf(key)
            if (chIndex >= 0) {
                var nx = game.x + Dx[chIndex]
                var ny = game.y + Dy[chIndex]
                if (ny >= 1 && ny < My-1 && nx >= 1 && nx < Mx-1) {
                    var ch = game.grid[ny][nx]
                    if (ch == DoorWingVertical || ch == DoorWingHorizontal) {
                        game.grid[game.y][game.x] = Way  // temp. "ghost" him
                        rotateDoor.call(game, nx, ny)
                        game.grid[game.y][game.x] = Hero
                        ch = game.grid[ny][nx]  // may be unaltered
                    } else if (ch == Monster) {
                        game.grid[game.y][game.x] = Way
                        game.grid[ny][nx] = DeadHero
                        game.y = ny
                        game.x = nx
                        game.terminate = true
                        break
                    } else if (ch == Treasure) {
                        game.treasureCounter = game.treasureCounter + 1
                        if (game.treasureCounter == TreasureDb) {
                            game.grid[game.y][game.x] = Way
                            game.grid[ny][nx] = Hero
                            game.y = ny
                            game.x = nx
                            game.terminate = true
                            break
                        }
                        ch = Way
                    } else if (ch == Bomb) {
                        game.bombs = game.bombs + 1
                        ch = Way
                    }
                    if (ch == Way || ch == WeakMonster) {
                        game.grid[game.y][game.x] = Way
                        game.grid[ny][nx] = Hero
                        game.y = ny
                        game.x = nx
                    }
                }
            }
        }
        Fiber.yield()
    }
}
                        
var play = Fn.new {
    NC.initScr()
    NC.cbreak()
    NC.keypad(true)
    NC.noecho()
    var game = initGame.call()
    var fDraw = Fiber.new(draw)
    var fKeyboard = Fiber.new(keyboard)
    var fMonsterMove = Fiber.new(monsterMove)
    while (true) {
        fDraw.call(game)
        if (game.terminate) break
        fKeyboard.call(game)
        if (!game.terminate) fMonsterMove.call(game)
    }
    if (game.treasureCounter == TreasureDb) {
        NC.addStr("\nYOU WON! Congratulations!\n")
        NC.refresh()
        NC.getch()
    } else if (game.grid[game.y][game.x] == DeadHero) {
        NC.addStr("\nYOU PERISHED!\n")
        NC.refresh()
        NC.getch()
    }
}

play.call()
NC.echo()
NC.nocbreak()
NC.endwin()
NC.cursSet(1)


We now embed this in the following C program, build and run it.

/* gcc CLI-based_maze_game.c -o CLI-based_maze_game -lncurses -lwren -lm */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include <unistd.h>
#include "wren.h"

/* C <=> Wren interface functions */

void C_initScr(WrenVM* vm) {
    initscr();
}

void C_cbreak(WrenVM* vm) {
    int res = cbreak();
    wrenSetSlotDouble(vm, 0, (double)res);
}

void C_nocbreak(WrenVM* vm) {
    int res = nocbreak();
    wrenSetSlotDouble(vm, 0, (double)res);
}

void C_keypad(WrenVM* vm) {
    bool bf = wrenGetSlotBool(vm, 1);
    int res = keypad(stdscr, bf);
    wrenSetSlotDouble(vm, 0, (double)res);
}

void C_echo(WrenVM* vm) {
    int res = echo();
    wrenSetSlotDouble(vm, 0, (double)res);
}

void C_noecho(WrenVM* vm) {
    int res = noecho();
    wrenSetSlotDouble(vm, 0, (double)res);
}

void C_cursSet(WrenVM* vm) {
    int visibility = (int)wrenGetSlotDouble(vm, 1);
    int res = curs_set(visibility);
    wrenSetSlotDouble(vm, 0, (double)res);
}

void C_erase(WrenVM* vm) {
    int res = erase();
    wrenSetSlotDouble(vm, 0, (double)res);
}

void C_addStr(WrenVM* vm) {
    const char *str = wrenGetSlotString(vm, 1);
    int res = addstr(str);
    wrenSetSlotDouble(vm, 0, (double)res);
}

void C_getch(WrenVM* vm) {
    int ch = getch();
    wrenSetSlotDouble(vm, 0, (double)ch);
}

void C_move(WrenVM* vm) {
    int y = (int)wrenGetSlotDouble(vm, 1);
    int x = (int)wrenGetSlotDouble(vm, 2);
    int res = move(y, x);
    wrenSetSlotDouble(vm, 0, (double)res);
}

void C_refresh(WrenVM* vm) {
    int res = refresh();
    wrenSetSlotDouble(vm, 0, (double)res);
}

void C_endwin(WrenVM* vm) {
    int res = endwin();
    wrenSetSlotDouble(vm, 0, (double)res);
}

WrenForeignMethodFn bindForeignMethod(
    WrenVM* vm,
    const char* module,
    const char* className,
    bool isStatic,
    const char* signature) {
    if (strcmp(module, "main") == 0) {
        if (strcmp(className, "NC") == 0) {
            if (isStatic && strcmp(signature, "initScr()") == 0)       return C_initScr;
            if (isStatic && strcmp(signature, "cbreak()") == 0)        return C_cbreak;
            if (isStatic && strcmp(signature, "nocbreak()") == 0)      return C_nocbreak;
            if (isStatic && strcmp(signature, "keypad(_)") == 0)       return C_keypad;
            if (isStatic && strcmp(signature, "echo()") == 0)          return C_echo;
            if (isStatic && strcmp(signature, "noecho()") == 0)        return C_noecho;
            if (isStatic && strcmp(signature, "cursSet(_)") == 0)      return C_cursSet;
            if (isStatic && strcmp(signature, "erase()") == 0)         return C_erase;
            if (isStatic && strcmp(signature, "addStr(_)") == 0)       return C_addStr;
            if (isStatic && strcmp(signature, "getch()") == 0)         return C_getch;
            if (isStatic && strcmp(signature, "move(_,_)") == 0)       return C_move;
            if (isStatic && strcmp(signature, "refresh()") == 0)       return C_refresh;
            if (isStatic && strcmp(signature, "endwin()") == 0)        return C_endwin;
        }
    }
    return NULL;
}

static void writeFn(WrenVM* vm, const char* text) {
    printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
    switch (errorType) {
        case WREN_ERROR_COMPILE:
            printf("[%s line %d] [Error] %s\n", module, line, msg);
            break;
        case WREN_ERROR_STACK_TRACE:
            printf("[%s line %d] in %s\n", module, line, msg);
            break;
        case WREN_ERROR_RUNTIME:
            printf("[Runtime Error] %s\n", msg);
            break;
    }
}

char *readFile(const char *fileName) {
    FILE *f = fopen(fileName, "r");
    fseek(f, 0, SEEK_END);
    long fsize = ftell(f);
    rewind(f);
    char *script = malloc(fsize + 1);
    fread(script, 1, fsize, f);
    fclose(f);
    script[fsize] = 0;
    return script;
}

static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
    if( result.source) free((void*)result.source);
}

WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
    WrenLoadModuleResult result = {0};
    if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
        result.onComplete = loadModuleComplete;
        char fullName[strlen(name) + 6];
        strcpy(fullName, name);
        strcat(fullName, ".wren");
        result.source = readFile(fullName);
    }
    return result;
}

int main(int argc, char **argv) {
    WrenConfiguration config;
    wrenInitConfiguration(&config);
    config.writeFn = &writeFn;
    config.errorFn = &errorFn;
    config.bindForeignMethodFn = &bindForeignMethod;
    config.loadModuleFn = &loadModule;
    WrenVM* vm = wrenNewVM(&config);
    const char* module = "main";
    const char* fileName = "CLI-based_maze_game.wren";
    char *script = readFile(fileName);
    WrenInterpretResult result = wrenInterpret(vm, module, script);
    switch (result) {
        case WREN_RESULT_COMPILE_ERROR:
            printf("Compile Error!\n");
            break;
        case WREN_RESULT_RUNTIME_ERROR:
            printf("Runtime Error!\n");
            usleep(10000000); // allow time to read it
            timeout(-1);
            nocbreak();
            echo();
            endwin();
            break;
        case WREN_RESULT_SUCCESS:
            break;
    }
    wrenFreeVM(vm);
    free(script);
    return 0;
}
Output:

Sample opening screen.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X  .  X    b        .       X                         X     X       X
XXXXX X X XXX XXXXX X XXXXX XXXXX X-o-X X X X XXXXXXX X-o-X XXXXX X X
X     X X X   X     X X           X     X X X X       X     X     X X
X XXXXX X X XXXbXXXXX X XXXXXXXXXXX XXXXX X XXX XXXXXXX XXXXX XXXXX X
X     X X X   X     X X           X     X X   X  .    .           X X
XXXXX XXXXXXX XXX-o-XXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXX X X
X     X  $    X             X           .     X    .  X     X     X X
X XXXXX X X XXX XXXXX X XXXXX XXXXX XXXXX X X X XXXXX X.XXXXX XXXXX X
X     X X X   X     X X      .    X     X X X X     X X     X     X X
XXXXX X X XXX XXXXX XXXXXXXXXXXXX X-o-X X XXX XX-o-XX XXXXX XXXXX X X
X     X X X   X     X       X     X     X X   X       X    .X     X X
X.XXXXX X X$XXX XXXXX X XXXXX XXX X XXXXX X X X$XXXXX X XXXXX XXXXX X
X     X | X   X     X X         X X     X X X X     X X           X X
X XXXXX o XXXXX X-o-XXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXX XXXXXXXXXXX X
X     X |     Xb            X                 X     . X     X     X X
X XXXXX X X XXX XXXXX X XXXXX XXXXX XXXXX X X X XXXXX X XXXXX XXXXX X
X       X X   X     X X           X     X X X X     X           b X X
X XXXXXXXXX-o-XXXXXXXXXXXX-o-XXXXXXXXXXXXXXXXXXXXXXXX-o-XXXXXXXXXXXXX
X                       .                                           X
XX-o-XXXXX-o-XXXXX-o-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XXXX X
X             .             .              .                        X
X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XXXX-o-XXXX
X .   X                                               X     X       X
XXXXX X X XXX XXXXX X XXXXXXXXXXX XXXXX X XXX XX-o-XX XXXXX XXXXX X X
X     X X X   X     X X   .       X     X X   X       X           X X
XXXXX$X XXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXXXXX XXXXXXX XXXX-o-XXXX X X
X       X     X   b               X           X                   X X
X XXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XXXXXXXXXXX-o-X XXXXXXXXXXXXXXXXXXXXX
X@                                  .       . X    .    .       b   X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


Collected treasure = 0     Bombs = 3

Corresponding closing screen after a rare victory!

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X  .  X    b        .       X                         X     X       X
XXXXX X X XXX XXXXX X XXXXX XXXXX X-o-X X X X XXXXXXX X-o-X XXXXX X X
X     X X X   X     X X           X     X X X X       X     X     X X
X XXXXX X X XXXbXXXXX X XXXXXXXXXXX XXXXX X XXX XXXXXXX XXXXX XXXXX X
X     X X X   X     X X           X     X X   X   *    *          X X
XXXXX XXXXXXX XXX-o-XXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXX X X
X     X       X             X           .     X    .  X     X     X X
X XXXXX X X XXX XXXXX X XXXXX XXXXX XXXXX X X X XXXXX X.XXXXX XXXXX X
X     X X X   X     X X      .    X     X X X X     X X     X     X X
XXXXX X X XXX XXXXX XXXXXXXXXXXXX X-o-X X XXX XX-o-XX XXXXX XXXXX X X
X     X X X   X     X       X     X     X X   X       X    .X     X X
X.XXX X    @XXX XXXXX X XXXXX XXX X XXXXX X X X$XXXXX X XXXXX XXXXX X
X         X   X     X X         X X     X X X X     X X           X X
X XXX X-o-XXXXX X-o-XXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXX XXXXXXXXXXX X
X     X       Xb            X                 X     . X     X     X X
X XXXXX X X XXX XXXXX X XXXXX XXXXX XXXXX X X X XXXXX X XXXXX XXXXX X
X       X X   X     X X           X     X X X X     X           b X X
X XXXXXXXXX-o-XXXXXXXXXXXX-o-XXXXXXXXXXXXXXXXXXXXXXXX-o-XXXXXXXXXXXXX
X  -                    .                                           X
XX o XXXXX-o-XXXXX-o-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XXXX X
X  -          .             .              .                        X
X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XXXX-o-XXXX
X     X                                               X     X       X
XXXXX X X XXX XXXXX X XXXXXXXXXXX XXXXX X XXX XX-o-XX XXXXX XXXXX X X
X     X X X   X     X X   .       X     X X   X       X           X X
XXXXX X XXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXXXXX XXXXXXX XXXX-o-XXXX X X
X       X     X   b               X           X                   X X
X XXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XXXXXXXXXXX-o-X XXXXXXXXXXXXXXXXXXXXX
X                                   .       . X    .    .       b   X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


Collected treasure = 3     Bombs = 1

YOU WON! Congratulations!