Robots/Wren
< Robots
Code
An embedded script so we can use the ncurses library.
/* Robots.wren */
import "./dynamic" for Struct
import "./str" for Char
import "./fmt" for Fmt
import "random" for Random
// all methods assume stdscr
class NC {
foreign static initScr()
foreign static useDefaultColors()
foreign static startColor()
foreign static cbreak()
foreign static nocbreak()
foreign static echo()
foreign static noecho()
foreign static cursSet(visibility)
foreign static initPair(index, fg, bg)
foreign static attron(cp)
foreign static attroff(cp)
foreign static move(x, y)
foreign static mvaddStr(x, y, str)
foreign static getch()
foreign static refresh()
foreign static napms(ms)
foreign static endwin()
}
var COLOR_DEFAULT = -1
var COLOR_BLACK = 0
var COLOR_RED = 1
var COLOR_GREEN = 2
var COLOR_YELLOW = 3
var COLOR_BLUE = 4
var COLOR_MAGENTA = 5
var COLOR_CYAN = 6
var COLOR_WHITE = 7
var A_BOLD = 0x200000
var Coord = Struct.create("Coord", ["x", "y"])
var width = 62
var height = 42
var inc = 10
var board = List.filled(width * height, null)
var robotsCount = 0
var score = 0
var aliveRobots = 0
var cursor = Coord.new(0, 0)
var alive = false
var rand = Random.new()
var colors = [
COLOR_DEFAULT,
COLOR_WHITE,
COLOR_BLACK | A_BOLD,
COLOR_BLUE | A_BOLD,
COLOR_GREEN | A_BOLD,
COLOR_CYAN | A_BOLD,
COLOR_RED | A_BOLD,
COLOR_MAGENTA | A_BOLD,
COLOR_YELLOW | A_BOLD,
COLOR_WHITE | A_BOLD
]
var printAt = Fn.new { |x, y, s, cp|
NC.attron(cp)
NC.mvaddStr(y, x, s)
NC.attroff(cp)
}
var clearBoard = Fn.new {
for (y in 0...height) {
for (x in 0...width) {
board[x + width*y] = " "
if (x == 0 || x == width-1 || y == 0 || y == height-1) {
board[x + width*y] = "#"
}
}
}
}
var printScore = Fn.new {
var s = Fmt.swrite(" SCORE: $d ", score)
printAt.call(0, height, s, colors[4] + 10)
NC.refresh()
NC.attroff(colors[4] + 10)
}
var createBoard = Fn.new {
aliveRobots = robotsCount
for (x in 0...robotsCount) {
var a
var b
while (true) {
a = rand.int(width)
b = rand.int(height)
if (board[a + width*b] == " ") break
}
board[a + width*b] = "+"
}
printScore.call()
}
var displayBoard = Fn.new() {
var cp
for (y in 0...height) {
for (x in 0...width) {
var t = board[x + width*y]
if (t == " ") {
cp = 1
} else if (t == "#") {
cp = 4
} else if (t == "+") {
cp = 9
} else if (t == "A" || t == "*") {
cp = 7
} else if (t == "@") {
cp = 5
}
printAt.call(x, y, t, cp)
}
}
NC.refresh()
NC.attroff(cp)
}
var teleport = Fn.new {
board[cursor.x + width*cursor.y] = " "
cursor.x = rand.int(width-2) + 1
cursor.y = rand.int(height-2) + 1
var x = cursor.x + width*cursor.y
if (board[x] == "*" || board[x] == "+" || board[x] == "~") {
alive = false
board[x] = "A"
} else {
board[x] = "@"
}
}
var checkCollision = Fn.new { |x, y|
if (cursor.x == x && cursor.y == y) {
alive = false
board[x + width*y] = "A"
return
}
x = x + y * width
if (board[x] == "*" || board[x] == "+" || board[x] == "~") {
if (board[x] != "*") {
aliveRobots = aliveRobots - 1
score = score + 1
}
board[x] = "*"
aliveRobots = aliveRobots - 1
score = score + 1
}
}
var moveRobots = Fn.new {
for (y in 0...height) {
for (x in 0...width) {
if (board[x + width*y] != "+") continue
var tx = x
var ty = y
if (tx < cursor.x) {
tx = tx + 1
} else if (tx > cursor.x) {
tx = tx - 1
}
if (ty < cursor.y) {
ty = ty + 1
} else if (ty > cursor.y) {
ty = ty - 1
}
if (tx != x || ty != y) {
board[x + width*y] = " "
if (board[tx + width*ty] == " ") {
board[tx + width*ty] = "~"
} else {
checkCollision.call(tx, ty)
}
}
}
}
for (x in 0...width*height) {
if (board[x] == "~") board[x] = "+"
}
}
var execute = Fn.new { |x, y|
board[cursor.x + width*cursor.y] = " "
cursor.x = cursor.x + x
cursor.y = cursor.y + y
board[cursor.x + width*cursor.y] = "@"
moveRobots.call()
}
var waitForEnd = Fn.new {
while (aliveRobots != 0 && alive) {
moveRobots.call()
displayBoard.call()
NC.napms(500)
}
}
var play = Fn.new {
NC.initScr()
NC.useDefaultColors()
NC.startColor()
for (i in 0...colors.count) {
NC.initPair(i+1, colors[i], -1)
NC.initPair(i+11, colors[i], 2)
}
NC.cbreak()
NC.noecho()
while (true) {
NC.cursSet(0)
robotsCount = 10
score = 0
alive = true
clearBoard.call()
cursor.x = rand.int(width-2) + 1
cursor.y = rand.int(height-2) + 1
board[cursor.x + width*cursor.y] = "@"
createBoard.call()
while (true) {
displayBoard.call()
var key = Char.upper(Char.fromCode(NC.getch()))
if (key == "Q") {
if (cursor.x > 1 && cursor.y > 1) execute.call(-1, -1)
} else if (key == "W") {
if (cursor.y > 1) execute.call(0, -1)
} else if (key == "E") {
if (cursor.x < width - 2 && cursor.y > 1) execute.call(1, -1)
} else if (key == "A") {
if (cursor.x > 1) execute.call(-1, 0)
} else if (key == "D") {
if (cursor.x < width - 2) execute.call(1, 0)
} else if (key == "Z") {
if (cursor.x > 1 && cursor.y < height - 2) execute.call (-1, 1)
} else if(key == "X") {
if (cursor.y < height - 2) execute.call(0, 1)
} else if (key == "C") {
if (cursor.x < width - 2 && cursor.y < height - 2) execute.call(1, 1)
} else if (key == "T") {
teleport.call()
moveRobots.call()
} else if (key == "H") {
waitForEnd.call()
} else if (key == "L") { // leave key
return
}
printScore.call()
if (aliveRobots == 0) {
robotsCount = robotsCount + inc
clearBoard.call()
board[cursor.x + width*cursor.y] = "@"
createBoard.call()
}
if (!alive) break
}
displayBoard.call()
var cp = 10
printAt.call(10, 8, "+----------------------------------------+", cp)
printAt.call(10, 9, "| GAME OVER |", cp)
printAt.call(10, 10, "| PLAY AGAIN(Y/N)? |", cp)
printAt.call(10, 11, "+----------------------------------------+", cp)
NC.move(10, 39)
NC.cursSet(1)
NC.refresh()
var yn = Char.upper(Char.fromCode(NC.getch()))
if (yn != "Y") return
}
}
play.call()
NC.nocbreak()
NC.echo()
NC.endwin()
NC.cursSet(1)
We now embed this in the following C program, build and run it.
/* gcc Robots.c -o Robots -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_useDefaultColors(WrenVM* vm) {
use_default_colors();
}
void C_startColor(WrenVM* vm) {
int res = start_color();
wrenSetSlotDouble(vm, 0, (double)res);
}
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_initPair(WrenVM* vm) {
short index = (short)wrenGetSlotDouble(vm, 1);
short fg = (short)wrenGetSlotDouble(vm, 2);
short bg = (short)wrenGetSlotDouble(vm, 3);
int res = init_pair(index, fg, bg);
wrenSetSlotDouble(vm, 0, (double)res);
}
void C_attron(WrenVM* vm) {
int index = (int)wrenGetSlotDouble(vm, 1);
int res = attron(COLOR_PAIR(index));
wrenSetSlotDouble(vm, 0, (double)res);
}
void C_attroff(WrenVM* vm) {
int index = (int)wrenGetSlotDouble(vm, 1);
int res = attroff(COLOR_PAIR(index));
wrenSetSlotDouble(vm, 0, (double)res);
}
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_mvaddStr(WrenVM* vm) {
int y = (int)wrenGetSlotDouble(vm, 1);
int x = (int)wrenGetSlotDouble(vm, 2);
const char *str = wrenGetSlotString(vm, 3);
int res = mvaddstr(y, x, str);
wrenSetSlotDouble(vm, 0, (double)res);
}
void C_getch(WrenVM* vm) {
int ch = getch();
wrenSetSlotDouble(vm, 0, (double)ch);
}
void C_refresh(WrenVM* vm) {
int res = refresh();
wrenSetSlotDouble(vm, 0, (double)res);
}
void C_napms(WrenVM* vm) {
int ms = (int)wrenGetSlotDouble(vm, 1);
int res = napms(ms);
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, "useDefaultColors()") == 0) return C_useDefaultColors;
if (isStatic && strcmp(signature, "startColor()") == 0) return C_startColor;
if (isStatic && strcmp(signature, "cbreak()") == 0) return C_cbreak;
if (isStatic && strcmp(signature, "nocbreak()") == 0) return C_nocbreak;
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, "initPair(_,_,_)") == 0) return C_initPair;
if (isStatic && strcmp(signature, "attron(_)") == 0) return C_attron;
if (isStatic && strcmp(signature, "attroff(_)") == 0) return C_attroff;
if (isStatic && strcmp(signature, "move(_,_)") == 0) return C_move;
if (isStatic && strcmp(signature, "mvaddStr(_,_,_)") == 0) return C_mvaddStr;
if (isStatic && strcmp(signature, "getch()") == 0) return C_getch;
if (isStatic && strcmp(signature, "refresh()") == 0) return C_refresh;
if (isStatic && strcmp(signature, "napms(_)") == 0) return C_napms;
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 = "Robots.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;
}