CLI-based maze-game: Difference between revisions
(Added Wren) |
|||
Line 1,452: | Line 1,452: | ||
{} = wait_key() |
{} = wait_key() |
||
end if</lang> |
end if</lang> |
||
=={{header|Wren}}== |
|||
{{trans|Nim}} |
|||
{{trans|Phix}} |
|||
{{libheader|ncurses}} |
|||
{{libheader|Wren-dynamic}} |
|||
{{libheader|Wren-str}} |
|||
{{libheader|Wren-trait}} |
|||
An embedded script so we can use the ncurses library. |
|||
<lang ecmascript>/* cli_based_maze_game.wren */ |
|||
import "./dynamic" for Enum, Tuple, Struct |
|||
import "./str" for Char |
|||
import "./trait" 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)</lang> |
|||
<br> |
|||
We now embed this in the following C program, build and run it. |
|||
<lang c>/* 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; |
|||
}</lang> |
|||
{{out}} |
|||
Sample opening screen. |
|||
<pre> |
|||
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 |
|||
</pre> |
|||
Corresponding closing screen after a rare victory! |
|||
<pre> |
|||
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! |
|||
</pre> |
Revision as of 18:30, 26 December 2021
Task: Create a complete but CLI-controlled maze-game!
Use the CLI interface only. The symbols:
1. The hero: @
2. Strong monsters: * (they can kill you).
3. Weak monsters: . (You can kill them).
4. Treasure: $
5. Wall: X
6. Bomb: b
7. Revolving door: -o-
and:
|
o
|
(the monsters are stupid, they can't use these doors)
Monsters must be moved by the computer, automatically. Use for this subtask a fork()-ed part of your program.
The maze must be generated randomly, at each start of the game.
Note: I apologize of my bad English, I'm very sorry...
Furor
<lang Furor>
- 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 } // --------------------------------------------------------- </lang>
- Output:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X X | X X X X . X X X X X X X X XXXXX XXX X X XXXXX o XXX X X XXX X XXXXX XbXXX X X X-o-X XXXXXXX*X X X X . X X X X X | X X X X | X X X X X X X X X * X X X XXX XXX X X X X X X XXX X X X X o | XXX X XXX X*X XXX X X XXXXX X X X X X X X X X | X | o X . X X X X X X X XXXXX XXX XXXXXXXXXXX XXX o XXXXX | XXXXXXXXXXX X X XXXXXXXXXXXXX X X X X X * X X X | X X X X X X X X X X X XXXXX XXX X X XXXXX X XXX X X XXX X XXXXX X XXX X X XXXXX -o-XXXX X X @ X X * X X X X X $ X X XX-o-XXXXXX XXXXXXXXXXX XXX XXXXXXX X-o-XXXXXXXXXXXXXXXXXXXXXXXXXXX X X X X X X X X X X X X X X X X X XXXXX XXX X X XXXXX$X XXX X X XXX | XXXXX X XXXbX X*XXXXX X-o-XXX X-o- X X X X . X X X X X X o X X . X X X X X X XXXXX XXX X X XXXXX X XXX X X X X | XXXXX X XXX X X XXXXX XX-o-XX X X X X* X X bX X X X X X XXXXXXXXXXX XXXXXXXXXXX XXX XXXXXXX XXX-o-XXXXXXXXXXXXXXXXXXXXXXXXX X X X X . X X X X X X X X X X X X X X X X X X.X XXX XXX X X X X X X XXX X X X X X X XXX X XXX X X XXX X XXXXXXX X X X X X X X .X X X X X X XXX-o-XXXXXXXXXXXXXXXXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-o-XX X X X X X X X X X X X X X X X X X X * X X X XXX XXX X X X X X X XXX X X X X X X X X X XXX X X XXX X X XXXXX X X | X X * X X X X X X X X X X X X X X X o -o-XX XXX XXXXXXXXXXX XXX X XXXXX X XXXXXXXXXXX X X XXXXXXXXXXXXX X | X X X X X X XXXXXXXXXXX XXX-o-XXXXX XXX XXXXXXX XXXXXXX-o-XXXXXXXXXXXXXXXXXXXXX X X X X X X X X X X X X X X X X XbX X X X X XXX XXX X X XXX X X XXX X X X X X X XXX X XXX X X XXXXX X-o-XXX X X X X X X X X *b * * X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Collected treasure = 1 Bombs = 3
Nim
This translation uses the binding for “ncurses” and have been tested on Linux (Manjaro). <lang Nim>import os, random, sequtils, strutils, std/exitprocs, locks import ncurses
const
KeyUp = 259 Keydown = 258 KeyLeft = 260 KeyRight = 261
Mx = 69 # No of columns (1..Mx), must be odd. My = 31 # No of rows (1..My), must be odd. Treasure = '$' TreasureDb= 3 # How many $ signs will be placed. Way = ' ' Wall = 'X' Doors = 20 # No of doors. DoorCenter = 'o' DoorWingVertical = '|' DoorWingHorizontal = '-' Hero = '@' DeadHero = '+' NumberOfBombs = 5 Bomb = 'b' NumberOfMonsters = 20 Monster = '*' WeakMonster = '.' MonsterWeaknessProbability = 25 # The higher the above number, the lower the chance that a strong monster will become weak. MonsterIntensifiesProbability = 5 # The higher the number above, the lower the chance that a weak monster will get stronger.
HelpText = """ Maze game.
The object of the game is to get all the treasures. The symbol of the treasure is the $ sign. Help (display this text): press ? or h Exit: press Esc or q You can detonate a bomb by pressing b, but only as long as your bomb remains. A bomb destroys every wall around the player (the outermost, framing of the maze except for its walls), but it won't kill monsters. The bomb does not destroy diagonally, only vertically and horizontally. The bomb will not destroy the doors or the treasure. You can also find bombs in the maze, represented by the letter b. If you step on them, you got the bomb with it, that is, the number of your bombs increases, for later use. The game ends when you have acquired all the treasures. The maze has not only walls but also revolving doors. The revolving door, if horizontal, looks like this: -o- If vertical, like this:
| o |
The center of the revolving door is represented by the character o, the wings by the line. The revolving door can be rotated if you take your wing in the right direction with your character, and if nothing stands in the way of rotation. The player is represented by @ in the game, and his starting point is always in the lower left corner. There is a possibility of a little cheating in the game: each press of the letter c is one increases the amount of your bombs. """
type
Direction = enum dirLeft, dirRight, dirUp, dirDown
Position = tuple[x, y: int]
Game = object grid: array[1..My, array[1..Mx, char]] scoords: array[1..NumberOfMonsters, Position] showHelp: bool terminate: bool treasureCounter: Natural bombs: Natural x, y: Natural
const
None: Position = (0, 0) Dy = [-1, 1, 0, 0] Dx = [0, 0, -1, 1]
var gameLock: Lock
proc genFlags(n: static int): array[1..n, bool] =
for i in countup(1, n, 2): result[i] = true
proc initGame(): Game =
result.bombs = 3
for x in 1..Mx: result.grid[1][x] = Wall result.grid[My][x] = Wall for y in 2..<My: result.grid[y][1] = Wall for x in 2..<Mx: result.grid[y][x] = Way result.grid[y][Mx] = Wall
var colFlags = genFlags(Mx) var rowFlags = genFlags(My)
while colFlags.anyIt(it) or rowFlags.anyIt(it): let direction = Direction(rand(3)) let j = rand(1..(if direction <= dirRight: My else: Mx)) div 2 * 2 + 1 case direction of dirLeft: if rowFlags[j]: for r in 1..<Mx: if result.grid[j][r] != Wall and result.grid[j][r+1] != Wall: result.grid[j][r] = Wall rowFlags[j] = false of dirRight: if rowFlags[j]: for r in countdown(Mx, 3): if result.grid[j][r-1] != Wall and result.grid[j][r-2] != Wall: result.grid[j][r-1] = Wall rowFlags[j] = false of dirUp: if colFlags[j]: for c in countdown(My, 3): if result.grid[c-1][j] != Wall and result.grid[c-2][j] != Wall: result.grid[c-1][j] = Wall colFlags[j] = false of dirDown: if colFlags[j]: for c in 1..<My: if result.grid[c][j] != Wall and result.grid[c+1][j] != Wall: result.grid[c][j] = Wall colFlags[j] = false
var doorsPlaced = 0 while doorsPlaced < Doors: let x = rand(3..Mx-2) let y = rand(3..My-2) if result.grid[y][x] != Way and result.grid[y-1][x-1] == Way and # top left corner free result.grid[y-1][x+1] == Way and # top right corner free result.grid[y+1][x-1] == Way and # left corner free result.grid[y+1][x+1] == Way: # right corner free # Let's see if we can put a vertical door. if result.grid[y-1][x] == Wall and # wall above the current position result.grid[y-2][x] == Wall and # wall above the current position result.grid[y+1][x] == Wall and # wall below the current position result.grid[y+2][x] == Wall and # wall below the current position result.grid[y][x-1] == Way and # left neighbor free result.grid[y][x+1] == Way: # right neighbor free result.grid[y][x] = DoorCenter result.grid[y-1][x] = DoorWingVertical result.grid[y+1][x] = DoorWingVertical inc doorsPlaced # Let's see if we can put a horizontal door. elif result.grid[y][x-1] == Wall and # wall left of the current position result.grid[y][x-2] == Wall and # wall left of the current position result.grid[y][x+1] == Wall and # wall right of the current position result.grid[y][x+2] == Wall and # wall right of the current position result.grid[y+1][x] == Way and # above neighbor free result.grid[y-1][x] == Way: # below neighbor free result.grid[y][x] = DoorCenter result.grid[y][x-1] = DoorWingHorizontal result.grid[y][x+1] = DoorWingHorizontal inc doorsPlaced
const Stuff = [(TreasureDb, Treasure), (NumberOfBombs, Bomb), (NumberOfMonsters, WeakMonster)] # At first, all monsters are weak.
for (n, what) in Stuff: var iter = 1 var n = n while n > 0: let x = rand(1..Mx) let y = rand(1..My) if result.grid[y][x] == Way: result.grid[y][x] = what if what == WeakMonster: result.scoords[n] = (x, y) dec n inc iter assert iter <= 10_000 # (sanity check)
result.x = 1 result.y = My - 2 result.grid[My - 2][1] = Hero
proc draw(game: ptr Game) {.thread.} =
cursSet(0) while true: acquire gameLock if game.showHelp: erase() addStr HelpText while getch() == -1: sleep 10 erase() game.showHelp = false erase() move(0, 0) for row in game.grid: addstr row.join("") & '\n' addstr "\n\nCollected treasures = $1 Bombs = $2\n".format(game.treasureCounter, game.bombs) refresh() if game.terminate: break release gameLock sleep 200 release gameLock
proc monsterStepFinder(game: ptr Game; sx, sy: int): Position =
result = None var m = [0, 1, 2, 3] m.shuffle() for i in m: let nx = sx + Dx[i] let ny = sy + Dy[i] if ny in 1..My and nx in 1..Mx and game.grid[ny][nx] in [Way, Hero]: result = (nx, ny)
proc monsterMove(game: ptr Game) {.thread.} =
while not game.terminate: acquire gameLock let active = rand(1..NumberOfMonsters) let (sx, sy) = game.scoords[active] if sx != 0: let ch = game.grid[sy][sx] if ch == Monster: if rand(1..MonsterWeaknessProbability) == 1: game.grid[sy][sx] = WeakMonster else: let monster = game.monsterStepFinder(sx, sy) if monster != None: if game.grid[monster.y][monster.x] == Hero: game.grid[monster.y][monster.x] = DeadHero game.terminate = true break game.grid[sy][sx] = Way game.grid[monster.y][monster.x] = Monster game.scoords[active] = monster elif ch == WeakMonster: if rand(1..MonsterIntensifiesProbability) == 1: game.grid[sy][sx] = Monster else: let monster = game.monsterStepFinder(sx, sy) if monster != None: game.grid[sy][sx] = Way if game.grid[monster.y][monster.x] != Hero: game.grid[monster.y][monster.x] = WeakMonster game.scoords[active] = monster else: game.scoords[active] = None release gameLock sleep 100
release gameLock
proc rotateDoor(game: var Game; nx, ny: int) =
for i in 1..4: let wy = Dy[i-1] wx = Dx[i-1] cy = ny + wy cx = nx + wx if game.grid[cy][cx] == DoorCenter: if game.grid[cy-1][cx-1] == Way and game.grid[cy-1][cx+1] == Way and game.grid[cy+1][cx-1] == Way and game.grid[cy+1][cx+1] == Way: # four corners empty let py = Dy[^i] let px = Dx[^i] if game.grid[cy+py][cx+px] == Way and game.grid[cy-py][cx-px] == Way: # swung door empty let door = game.grid[ny][nx] let flip = if door == DoorWingVertical: DoorWingHorizontal else: DoorWingVertical game.grid[cy+py][cx+px] = flip game.grid[cy-py][cx-px] = flip game.grid[cy+wy][cx+wx] = Way game.grid[cy-wy][cx-wx] = Way break
proc keyboard(game: var Game; win: PWindow) =
while not game.terminate: var key = -1 while key == -1 and not game.terminate: sleep 10 key = win.wgetch() acquire gameLock case key of ord('\e'), ord('q'): game.terminate = true of ord('b'): if game.bombs != 0: dec game.bombs for i in 0..3: let nx = game.x + Dx[i] let ny = game.y + Dy[i] if ny in 2..<My and nx in 2..<Mx and game.grid[ny][nx] == Wall: game.grid[ny][nx] = Way of ord('c'): inc game.bombs of ord('?'), ord('h'): game.showHelp = true else: let chIndex = [KeyUp, Keydown, KeyLeft, KeyRight].find(key) if chIndex >= 0: let nx = game.x + Dx[chIndex] let ny = game.y + Dy[chIndex] if ny in 2..<My and nx in 2..<Mx: var ch = game.grid[ny][nx] if ch in [DoorWingVertical, DoorWingHorizontal]: game.grid[game.y][game.x] = Way # (temp. "ghost" him) game.rotateDoor(nx, ny) game.grid[game.y][game.x] = Hero ch = game.grid[ny][nx] # (maybe unaltered) elif ch == Monster: game.grid[game.y][game.x] = Way game.grid[ny][nx] = DeadHero game.y = ny game.x = nx game.terminate = true elif ch == Treasure: inc game.treasureCounter if game.treasureCounter == TreasureDb: game.terminate = true ch = Way elif ch == Bomb: inc game.bombs ch = Way if ch in [Way, WeakMonster]: game.grid[game.y][game.x] = Way game.grid[ny][nx] = Hero game.y = ny game.x = nx
release gameLock
while getch() != -1: discard # (purge kbd buffer)
proc play() =
randomize() let win = initscr() win.nodelay(true) win.keypad(true) noecho() cbreak() addExitProc proc() = endwin() addExitProc proc() = cursSet(1) var game = initGame()
var tdraw, tmove: Thread[ptr Game] createThread(tdraw, draw, addr(game)) createThread(tmove, monsterMove, addr(game)) game.keyboard(win)
joinThreads(tdraw, tmove) if game.treasureCounter == TreasureDb: addstr "\nYOU WON! Congratulations!\n" refresh() while getch() == -1: sleep(1) elif game.grid[game.y][game.x] == DeadHero: addstr "\nYOU PERISHED!\n" refresh() while getch() == -1: sleep(1)
play()</lang>
Phix
<lang Phix>-- demo/rosetta/CLI_maze.exw constant W = platform()=WINDOWS,
UP = iff(W?328:259), DOWN = iff(W?336:258), LEFT = iff(W?331:260), RGHT = iff(W?333:261), ESC = #1B,
MX = 69, -- No of columns (1..MX), must be odd. MY = 31, -- No of rows (1..MY), must be odd. TREASURE = '$', TREASUREDB = 3, -- treasuredb means how many $ signs will be placed WAY = ' ', WALL = 'X', DOORS = 20, -- No of doors DOOR_CENTER = 'o', DOOR_WING_VERTICAL = '|', DOOR_WING_HORIZONTAL = '-', HERO = '@', DEAD_HERO = '+', NUMBER_OF_BOMBS = 5, BOMB = 'b', NUMBER_OF_MONSTERS = 20, MONSTER = '*', WEAK_MONSTER = '.', MONSTER_WEAKNESS_PROBABILITY = 25, -- The higher the above number, the lower the chance that a strong monster will become weak. MONSTER_INTENSIFIES_PROBABILITY = 5, -- The higher the number above, the lower the chance that a weak monster will get stronger. help_text = """
Maze game.
The object of the game is to get all the treasures. The symbol of the treasure is the $ sign. Help (display this text): press ? or h Exit: press Esc or q You can detonate a bomb by pressing b, but only as long as your bomb remains. A bomb destroys every wall around the player (the outermost, framing of the maze except for its walls), but it won't kill monsters. The bomb does not destroy diagonally, only vertically and horizontally. The bomb will not destroy the doors or the treasure. You can also find bombs in the maze, represented by the letter b. If you step on them, you got the bomb with it, that is, the number of your bombs increases, for later use. The game ends when you have acquired all the treasures. The maze has not only walls but also revolving doors. The revolving door, if horizontal, looks like this: -o- If vertical, like this:
| o |
The center of the revolving door is represented by the character o, the wings by the line. The revolving door can be rotated if you take your wing in the right direction with your character, and if nothing stands in the way of rotation. The player is represented by @ in the game, and his starting point is always in the lower left corner. There is a possibility of a little cheating in the game: each press of the letter c is one increases the amount of your bombs. """
integer bombs = 3,
treasure_counter = 0
sequence tb = repeat(WALL,MX),
in = WALL&repeat(WAY,MX-2)&WALL, grid = {tb}&repeat(in,MY-2)&{tb}, sxkoord = repeat(0,NUMBER_OF_MONSTERS), sykoord = repeat(0,NUMBER_OF_MONSTERS)
function gen_flags(integer l)
sequence res = repeat(false,l) for i=1 to l by 2 do res[i] = true end for return res
end function
procedure generatemaze()
sequence colflag = gen_flags(MX), rowflag = gen_flags(MY) while find(true,colflag) or find(true,rowflag) do integer direction = rand(4), j = floor(rand(iff(direction<=2?MY:MX))/2)*2+1 switch direction do case 1: -- left if rowflag[j] then for r=1 to MX-1 do if grid[j][r]!=WALL and grid[j][r+1]!=WALL then grid[j][r] = WALL end if end for rowflag[j] = false end if case 2: -- right if rowflag[j] then for r=MX to 3 by -1 do if grid[j][r-1]!=WALL and grid[j][r-2]!=WALL then grid[j][r-1] = WALL end if end for rowflag[j] = false end if case 3: -- up if colflag[j] then for c=MY to 3 by -1 do if grid[c-1][j]!=WALL and grid[c-2][j]!=WALL then grid[c-1][j] = WALL end if end for colflag[j] = false end if case 4: -- down if colflag[j] then for c=1 to MY-1 do if grid[c][j]!=WALL and grid[c+1][j]!=WALL then grid[c][j] = WALL end if end for colflag[j] = false end if end switch end while
integer doors_placed = 0, x, y while doors_placed<DOORS do x = rand(MX-4)+2 y = rand(MY-4)+2 if grid[y ][x ] != WAY and grid[y-1][x-1] == WAY -- top left corner free and grid[y-1][x+1] == WAY -- top right corner free and grid[y+1][x-1] == WAY -- left corner free and grid[y+1][x+1] == WAY then -- right corner free -- Let's see if we can put a vertical door. if grid[y-1][x ] == WALL -- wall above the current position and grid[y-2][x ] == WALL -- wall above the current position and grid[y+1][x ] == WALL -- wall below the current position and grid[y+2][x ] == WALL -- wall below the current position and grid[y ][x-1] == WAY -- left neighbor free and grid[y ][x+1] == WAY then -- right neighbor free grid[y ][x] = DOOR_CENTER grid[y-1][x] = DOOR_WING_VERTICAL grid[y+1][x] = DOOR_WING_VERTICAL doors_placed += 1 -- Let's see if we can put a horizontal door. elsif grid[y ][x-1] == WALL -- wall left of the current position and grid[y ][x-2] == WALL -- wall left of the current position and grid[y ][x+1] == WALL -- wall right of the current position and grid[y ][x+2] == WALL -- wall right of the current position and grid[y+1][x ] == WAY -- above neighbor free and grid[y-1][x ] == WAY then -- below neighbor free grid[y][x ] = DOOR_CENTER grid[y][x-1] = DOOR_WING_HORIZONTAL grid[y][x+1] = DOOR_WING_HORIZONTAL doors_placed += 1 end if end if end while
sequence stuff = {{TREASUREDB, TREASURE}, {NUMBER_OF_BOMBS, BOMB}, {NUMBER_OF_MONSTERS, WEAK_MONSTER}} -- At first, all monsters are weak.
for i=1 to length(stuff) do integer {n, what} = stuff[i], iter = 1 while n do x = rand(MX) y = rand(MY) if grid[y][x]==WAY then grid[y][x] = what if what=WEAK_MONSTER then sxkoord[n] = x sykoord[n] = y end if n -= 1 end if iter += 1 if iter>10000 then ?9/0 end if -- (sanity check) end while end for
end procedure
integer terminate = false,
showhelp = false
procedure draw()
cursor(NO_CURSOR) while true do if showhelp then clear_screen() puts(1,help_text) {} = wait_key() clear_screen() showhelp = false end if position(1,1) puts(1,join(grid,"\n")&"\n\n") printf(1,"Collected treasure = %d Bombs = %d\n",{treasure_counter,bombs}) if terminate then exit end if task_yield() end while
end procedure
constant dy = {-1,+1, 0, 0},
dx = { 0, 0,-1,+1}, HV = {DOOR_WING_HORIZONTAL,DOOR_WING_VERTICAL}
procedure rotate_door(integer ny,nx)
for i=1 to 4 do integer wy = dy[i], wx = dx[i], cy = ny+wy, cx = nx+wx if grid[cy,cx]=DOOR_CENTER then if grid[cy-1][cx-1]=WAY and grid[cy-1][cx+1]=WAY and grid[cy+1][cx-1]=WAY and grid[cy+1][cx+1]=WAY then -- four corners empty integer py = dy[-i], px = dx[-i] if grid[cy+py][cx+px]=WAY and grid[cy-py][cx-px]=WAY then -- swung door empty integer door = grid[ny][nx], flip = HV[-find(door,HV)] grid[cy+py][cx+px] = flip grid[cy-py][cx-px] = flip grid[cy+wy][cx+wx] = WAY grid[cy-wy][cx-wx] = WAY end if end if exit end if end for
end procedure
integer x = 1,
y = MY-2
procedure keyboard() integer ny,nx
while not terminate do integer ch = lower(get_key()) if ch=-1 then task_yield() elsif ch=ESC or ch='q' then exit elsif ch='b' and bombs!=0 then bombs -= 1 for i=1 to 4 do ny = y+dy[i] nx = x+dx[i] if ny>1 and ny<MY and nx>1 and nx<MX and grid[ny][nx]=WALL then grid[ny][nx]=WAY end if end for elsif ch='c' then bombs += 1 elsif ch='?' or ch='h' then showhelp = true else ch = find(ch,{UP,DOWN,LEFT,RGHT}) if ch then ny = y+dy[ch] nx = x+dx[ch] if ny>1 and ny<MY and nx>1 and nx<MX then ch = grid[ny][nx] if ch=DOOR_WING_VERTICAL or ch=DOOR_WING_HORIZONTAL then grid[y][x] = WAY -- (temp. "ghost" him) rotate_door(ny,nx) grid[y][x] = HERO ch = grid[ny][nx] -- (maybe unaltered) elsif ch=MONSTER then grid[y][x] = WAY grid[ny][nx] = DEAD_HERO y = ny x = nx exit elsif ch=TREASURE then treasure_counter += 1 if treasure_counter=TREASUREDB then terminate = true end if ch = WAY elsif ch=BOMB then bombs += 1 ch = WAY end if if ch=WAY or ch=WEAK_MONSTER then grid[y][x] = WAY grid[ny][nx] = HERO y = ny x = nx end if end if end if end if end while terminate = true while get_key()!=-1 do end while -- (purge kbd buffer)
end procedure
integer sy, sx, monster_y, monster_x
function monster_step_finder()
monster_y = 0 monster_x = 0 sequence m = shuffle(tagset(4)) for i=1 to length(m) do integer ny = sy+dy[i], nx = sx+dx[i] if ny>=1 and ny<=MY and nx>=1 and nx<=MX and find(grid[ny][nx],{WAY,HERO}) then monster_y = ny monster_x = nx return true end if end for return false
end function
procedure monster_move()
while not terminate do integer active = rand(NUMBER_OF_MONSTERS) sx = sxkoord[active] sy = sykoord[active] if sx then integer ch = grid[sy][sx] if ch=MONSTER then if rand(MONSTER_WEAKNESS_PROBABILITY)=1 then grid[sy][sx] = WEAK_MONSTER elsif monster_step_finder() then if grid[monster_y][monster_x]=HERO then grid[monster_y][monster_x]=DEAD_HERO terminate = true exit end if grid[sy][sx] = WAY grid[monster_y][monster_x] = MONSTER sxkoord[active] = monster_x sykoord[active] = monster_y end if elsif ch=WEAK_MONSTER then if rand(MONSTER_INTENSIFIES_PROBABILITY)=1 then grid[sy][sx] = MONSTER elsif monster_step_finder() then grid[sy][sx] = WAY if grid[monster_y][monster_x]!=HERO then grid[monster_y][monster_x]=WEAK_MONSTER sxkoord[active] = monster_x sykoord[active] = monster_y else sxkoord[active] = 0 sykoord[active] = 0 end if end if end if end if task_yield() end while
end procedure
generatemaze() grid[y][x] = HERO integer draw_id = task_create(draw,{}),
mstr_id = task_create(monster_move,{})
task_schedule(draw_id,{0.2,0.2}) task_schedule(mstr_id,{0.1,0.1})
keyboard()
if treasure_counter=TREASUREDB then
puts(1,"YOU WON! Congratulations!\n") {} = wait_key()
elsif grid[y][x]=DEAD_HERO then
puts(1,"YOU PERISHED!\n") {} = wait_key()
end if</lang>
Wren
An embedded script so we can use the ncurses library. <lang ecmascript>/* cli_based_maze_game.wren */
import "./dynamic" for Enum, Tuple, Struct import "./str" for Char import "./trait" 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)</lang>
We now embed this in the following C program, build and run it.
<lang c>/* 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;
}</lang>
- 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!