var stdin = "";
var boards = {};
var bnames = [];
var max_tick = 1000;
var space_as_blank = false;
var cylindrical_board = false;
var print_numbers = false;
var libraries = true;
var stopped = false;
var gfx = false;
var front_buffer = null;
var back_buffer = null;
function base36(a){ return a.toString(36).toUpperCase();}
function base16(a){ return ("0"+a.toString(16).toUpperCase()).substr(-2);}
function wto16(arr, i){ return arr[i] << 8 | arr[i+1]; }
function wto32(arr, i){ return arr[i] << 24 | arr[i+1] << 16 | arr[i+2] << 8 | arr[i+3]; }
function getch(){
var p = stdin.substr(0, 1);
stdin = stdin.substr(1);
if(p === '') return -1;
else return p.charCodeAt(0) & 255;
}
function putch(obj, ch){
if(print_numbers)
obj.stdout += ch + ' ';
else
obj.stdout += String.fromCharCode(ch);
}
function longestMatch(search, list){
var best = null, blen = 0;
for(var i = 0, len = list.length; i < len; ++i)
if(list[i].length > blen && search.indexOf(list[i]) === 0)
best = list[i], blen = best.length;
return best;
}
function swapBuffers(){
front_buffer.ctx.drawImage(back_buffer.canvas, 0, 0);
back_buffer.clear();
}
function jsBoard(name, inc, outc, code){
var f = eval('(function(inp, self){return ' + code + ';})');
boards[name] = new Board(name, true, f, inc, outc);
bnames.push(name);
}
function loadDefaultBoards(){
// implement \\ // /\ \/ ++ -- >> << ~~ ]] +n -n ?? ?n ^n =n >n <n as js boards
jsBoard('\\\\', 1, 0, '{37: inp[0]}');
jsBoard('//', 1, 0, '{36: inp[0]}');
jsBoard('/\\', 1, 0, '{36: inp[0], 37: inp[0]}');
jsBoard('\\/', 1, 0, '{}');
jsBoard('++', 1, 1, '{0: (inp[0]+1)&255}');
jsBoard('--', 1, 1, '{0: (inp[0]+255)&255}');
jsBoard('>>', 1, 1, '{0: inp[0]>>1}');
jsBoard('<<', 1, 1, '{0: (inp[0]<<1)&255}');
jsBoard('~~', 1, 1, '{0: (~inp[0])&255}');
jsBoard(']]', 1, 1, '(c=getch())>-1?{0:c}:{37:inp[0]}');
jsBoard('??', 1, 1, '{0: Math.floor(Math.random()*(inp[0]+1))}');
for(var i = 0; i < 36; ++i){
j = base36(i);
jsBoard('+'+j, 1, 1, '{0: (inp[0]+'+i+')&255}');
jsBoard('-'+j, 1, 1, '{0: (inp[0]-'+i+')&255}');
jsBoard('?'+j, 1, 1, '{0: Math.floor(Math.random()*'+(i+1)+')}');
jsBoard('='+j, 1, 1, 'inp[0]=='+i+'?{0: inp[0]}:{37: inp[0]}');
jsBoard('>'+j, 1, 1, 'inp[0]>'+i+'?{0: inp[0]}:{37: inp[0]}');
jsBoard('<'+j, 1, 1, 'inp[0]<'+i+'?{0: inp[0]}:{37: inp[0]}');
if(i < 8){
jsBoard('^'+j, 1, 1, '{0: !!(inp[0]&(1<<'+i+'))}');
}
}
if(gfx){
jsBoard('{}{}{}{}{}', 5, 0, 'back_buffer.set(inp[0], inp[1], inp[2], inp[3], inp[4]),{}');
jsBoard('@f@f@f', 2, 3, 'front_buffer.get(inp[0], inp[1])');
jsBoard('@b@b@b', 2, 3, 'back_buffer.get(inp[0], inp[1])');
jsBoard('><', 1, 0, 'swapBuffers(), {}');
}
if(libraries){
// dec_out.mbl - Dp, Decout
jsBoard('Dp', 1, 0, 'putch(self,Math.floor(inp[0]/100)+0x30),putch(self,Math.floor(inp[0]/10)%10+0x30),putch(self,inp[0]%10+0x30),{}');
jsBoard('Decout', 1, 3, '{0: inp[0]/100, 1: inp[0]/10%10, 2: inp[0]%10}');
// hex_out.mbl - Hp, Hexo
jsBoard('Hp', 1, 0, 's=base16(inp[0]),putch(self,s.charCodeAt(0)),putch(self,s.charCodeAt(1)),{}');
jsBoard('Hexo', 1, 2, 's=base16(inp[0]),{0: s.charCodeAt(0), 1: s.charCodeAt(1)}');
// fourwayincrement.mbl - Fwin
jsBoard('Fwin', 1, 2, '{36: inp[0], 0: (inp[0]+1)&255, 1: (inp[0]+1)&255, 37: (inp[0]+2)&255}');
// threewaysplit.mbl - 3W
jsBoard('3W', 1, 1, '{0: inp[0], 36: inp[0], 37: inp[0]}');
// bitwise_operations.mbl - Bitx, Bdif, Borr, Band, Bxor, Bnor
jsBoard('Bitx', 2, 1, 'inp[1]<8?{0: !!(inp[0] & (1 << inp[1]))}:{}');
jsBoard('Bdif', 2, 1, 'b=inp[0]^inp[1],{0: !!(b&1)+!!(b&2)+!!(b&4)+!!(b&8)+!!(b&16)+!!(b&32)+!!(b&64)+!!(b&128)}');
jsBoard('Borr', 2, 1, '{0: inp[0]|inp[1]}');
jsBoard('Band', 2, 1, '{0: inp[0]&inp[1]}');
jsBoard('Bxor', 2, 1, '{0: inp[0]^inp[1]}');
jsBoard('Bnor', 2, 1, '{0: ~(inp[0]|inp[1])}');
// logical_operations.mbl - Tf, Nt, Lorr, Land, Lnor, Lxor, Cmpr, Eqal, Gteq, Lteq, Grtr, Less, Sort
jsBoard('Tf', 1, 1, '{0: (inp[0]>0)|0}');
jsBoard('Nt', 1, 1, '{0: (!inp[0])|0}');
jsBoard('Lorr', 2, 1, '{0: (inp[0]||inp[1])|0}');
jsBoard('Land', 2, 1, '{0: (inp[0]&&inp[1])|0}');
jsBoard('Lnor', 2, 1, '{0: !(inp[0]||inp[1])|0}');
jsBoard('Lxor', 2, 1, '{0: (!inp[0]!=!inp[1])|0}');
jsBoard('Cmpr', 2, 1, '{0: inp[0]>inp[1]?1:inp[0]<inp[1]?-1:0}');
jsBoard('Eqal', 2, 1, '{0: (inp[0] == inp[1])|0}');
jsBoard('Gteq', 2, 1, '{0: (inp[0] >= inp[1])|0}');
jsBoard('Lteq', 2, 1, '{0: (inp[0] <= inp[1])|0}');
jsBoard('Grtr', 2, 1, '{0: (inp[0] > inp[1])|0}');
jsBoard('Less', 2, 1, '{0: (inp[0] < inp[1])|0}');
jsBoard('Sort', 2, 2, '{0: Math.min(inp[0],inp[1]), 1: Math.max(inp[0],inp[1])}');
// replace_input.mbl - Replac
jsBoard('Replac', 3, 1, '{0: inp[0]==inp[1]?inp[2]:inp[0]}');
// adder.mbl - Plus
jsBoard('Plus', 2, 1, '{0: (inp[0] + inp[1])&255}');
// arithmetic.mbl - Subt, Subo, Subful, Addo, Addful, Mult
jsBoard('Subt', 2, 1, '{0: (inp[0] - inp[1])&255}');
jsBoard('Subo', 2, 1, '{0: (inp[0] - inp[1])&255, 36: (inp[0] < inp[1])|0}');
jsBoard('Subful', 3, 1, 'a=(inp[0] - inp[1])&255,{0: (a + 256 - inp[2])&255, 36: (inp[0]<inp[1])+(a<inp[2])}');
jsBoard('Addo', 2, 1, 'a=inp[0]+inp[1],{0: a&255, 36: (a>255)|0}');
jsBoard('Addful', 3, 1, 'a=inp[0]+inp[1]+inp[2],{0: a&255, 36: (a>255)|0}');
jsBoard('Mult', 2, 1, '{0: (inp[0]*inp[1])&255}');
// wide_devices.mbl - Wideadditionfunc, Widesubtractfunc, Wbitleft, Wbitrght, Wbitfetchx, Mulx, Doblmult, Widemultiplyfunc
jsBoard('Wideadditionfunc', 8, 4, 'c=(wto32(inp,0)+wto32(inp,4))&0xFFFFFFFF,{0: (c&0xFF000000)>>>24, 1: (c&0x00FF0000)>>>16, 2: (c&0x0000FF00)>>>8, 3: (c&0x000000FF)}');
jsBoard('Widesubtractfunc', 8, 4, 'c=(wto32(inp,0)-wto32(inp,4))&0xFFFFFFFF,{0: (c&0xFF000000)>>>24, 1: (c&0x00FF0000)>>>16, 2: (c&0x0000FF00)>>>8, 3: (c&0x000000FF)}');
jsBoard('Wbitleft', 4, 4, 'c=(wto32(inp,0)<<1)&0xFFFFFFFF,{0: (c&0xFF000000)>>>24, 1: (c&0x00FF0000)>>>16, 2: (c&0x0000FF00)>>>8, 3: (c&0x000000FF)}');
jsBoard('Wbitrght', 4, 4, 'c=wto32(inp,0)>>>1,{0: (c&0xFF000000)>>>24, 1: (c&0x00FF0000)>>>16, 2: (c&0x0000FF00)>>>8, 3: (c&0x000000FF)}');
jsBoard('Wbitfetchx', 5, 1, 'inp[4]<32?{0:!!(wto32(inp,0)&(1<<inp[4]))}:{}');
jsBoard('Mulx', 2, 2, 'c=(inp[0]*inp[1])&0xFFFF,{0: (c&0xFF00)>>>8, 1: (c&0x00FF)}');
jsBoard('Doblmult', 4, 4, 'c=(wto16(inp,0)*wto16(inp,2))&0xFFFFFFFF,{0: (c&0xFF000000)>>>24, 1: (c&0x00FF0000)>>>16, 2: (c&0x0000FF00)>>>8, 3: (c&0x000000FF)}');
jsBoard('Widemultiplyfunc', 8, 4, 'c=(wto32(inp,0)*wto32(inp,4))&0xFFFFFFFF,{0: (c&0xFF000000)>>>24, 1: (c&0x00FF0000)>>>16, 2: (c&0x0000FF00)>>>8, 3: (c&0x000000FF)}');
}
}
// most devices are implemented as js subboards
var CTypes = {
PORTAL: 1,
SYNCHRONISER: 2,
INPUT: 3,
OUTPUT: 4,
TERMINATE: 5,
SUBROUTINE: 6,
LITERAL: 7,
};
function Cell(type,value){
this.type = type;
this.value = value;
}
Cell.prototype.copy = function(other){
this.type = other.type;
this.value = other.value;
};
function Board(name, js, jsref, jsinc, jsoutc){
this.name = name;
this.stdout = "";
if(!js){
this.cells = [];
this.marbles = [];
this.cols = 0;
this.rows = 0;
this.inputs = [];
this.outputs = [];
this.syncs = [];
this.portals = [];
this.terminators = [];
for(var i = 0; i < 36; ++i){
this.inputs[i] = [];
this.outputs[i] = [];
this.syncs[i] = [];
this.portals[i] = [];
}
this.outputs[36] = []; // {<
this.outputs[37] = []; // {>
this.subroutines = []; // [r0,c0,board name,size,inputs,outputs]
this.type = 0;
this.inc = 0;
this.outc = 0;
}else{
this.func = jsref;
this.inc = jsinc;
this.outc = jsoutc;
this.type = 1;
}
}
Board.prototype.set = function(row,col,cell){
if(row >= this.rows){
for(var r = this.rows; r <= row; ++r){
this.cells[r] = [];
this.marbles[r] = [];
}
}
this.rows = Math.max(this.rows, row + 1);
this.cols = Math.max(this.cols, col + 1);
if(!cell){
this.cells[row][col] = null;
return;
}
if(!this.cells[row][col])
this.cells[row][col] = new Cell;
this.cells[row][col].copy(cell);
if(cell.type == CTypes.LITERAL){
this.marbles[row][col] = cell.value;
}else{
this.marbles[row][col] = null;
}
};
Board.prototype.get = function(r,c){
return this.cells[r][c];
};
Board.prototype.init = function(){
if(this.type == 0){
var maxin = 0, maxout = 0;
for(var r = 0; r < this.rows; ++r){
for(var c = 0; c < this.cols; ++c){
if(this.cells[r][c] == null) continue;
switch(this.cells[r][c].type){
case CTypes.PORTAL:
this.portals[this.cells[r][c].value].push([r,c]);
break;
case CTypes.SYNCHRONISER:
this.syncs[this.cells[r][c].value].push([r,c]);
break;
case CTypes.INPUT:
this.inputs[this.cells[r][c].value].push([r,c]);
maxin = Math.max(this.cells[r][c].value + 1, maxin);
break;
case CTypes.OUTPUT:
if(this.cells[r][c].value != '<' && this.cells[r][c].value != '>'){
this.outputs[this.cells[r][c].value].push([r,c]);
maxout = Math.max(this.cells[r][c].value + 1, maxout);
}else{
this.outputs[this.cells[r][c].value == '<' ? 36 : 37].push([r,c]);
}
break;
case CTypes.TERMINATE:
this.terminators.push([r,c]);
break;
}
}
}
this.inc = maxin;
this.outc = maxout;
}
var namelen = Math.max(1, this.inc, this.outc) * 2;
this.name = new Array(namelen + 1).join(this.name).substr(0, namelen);
};
Board.prototype.validateSubr = function(names){
if(this.type == 1) return;
for(var r = 0, len = this.cells.length; r < len; ++r){
var str = "", start = -1;
for(var c = 0, rlen = this.cells[r].length; c < rlen; ++c){
if(this.cells[r][c] && this.cells[r][c].type == CTypes.SUBROUTINE){
if(start == -1) start = c;
str += this.cells[r][c].value;
}else if(start != -1){
var match;
while(str.length && (match = longestMatch(str, names))){
var slen = match.length / 2;
this.subroutines.push([r,start,match,slen,boards[match].inc,boards[match].outc]);
start += slen;
str = str.substr(slen * 2);
}
if(str.length){
throw "No subboard could be found near `" + str + "`";
}
start = -1;
str = "";
}
}
var match;
while(str.length && (match = longestMatch(str, names))){
var slen = match.length / 2;
this.subroutines.push([r,start,match,slen,boards[match].inc,boards[match].outc]);
start += slen;
str = str.substr(slen * 2);
}
if(str.length){
throw "No subboard could be found near `" + str + "`";
}
}
};
Board.prototype.runCopy = function(inp){
var b = new Board('');
b.type = 2;
b.ref = this;
b.tickNum = 0;
if(this.type == 0){
for(var r = 0, rlen = this.marbles.length; r < rlen; ++r){
b.marbles[r] = [];
for(var c = 0, clen = this.marbles[r].length; c < clen; ++c){
b.marbles[r][c] = this.marbles[r][c];
}
}
for(var i = 0; i < this.inc; ++i){
if(inp[i] != null){
var k = this.inputs[i];
for(var j = 0, l = k.length; j < l; ++j){
b.marbles[k[j][0]][k[j][1]] = ((parseInt(inp[i])&255)+256)&255;
}
}
}
b.cols = this.cols;
b.rows = this.rows;
b.inc = this.inc;
b.outc = this.outc;
b.stdout = "";
}else{
b.inp = inp;
}
return b;
};
Board.prototype.tick = function(){
if(this.type != 2) throw "Calling Board.tick without Board.runCopy";
if(this.tickNum == -1) throw "Copied board has already run to completion";
if(this.ref.type == 1){
this.tickNum = -1;
this.outp = this.ref.func(this.inp, this);
return moved;
}
var moved = false;
var new_marbles = [];
for(var r = 0; r <= this.rows; ++r)
new_marbles[r] = [];
// subroutines
for(var i = 0, len = this.ref.subroutines.length; i < len; ++i){
var r = this.ref.subroutines[i][0], c = this.ref.subroutines[i][1],
name = this.ref.subroutines[i][2], sz = this.ref.subroutines[i][3],
inc = this.ref.subroutines[i][4], outc = this.ref.subroutines[i][5];
var all = true, inp = [];
for(var j = 0; j < inc; ++j){
if(this.marbles[r][c+j] == null && (boards[name].type == 1 || boards[name].inputs[j].length > 0)){
all = false; break;
}else{
inp[j] = this.marbles[r][c+j];
}
}
if(all){
var cb = boards[name].runCopy(inp);
while(cb.tickNum != -1 && cb.tickNum < max_tick) cb.tick();
if(cb.tickNum != -1) throw "Max tick count exceeded running board `" + name + "`";
var outp = cb.out();
if(cb.stdout != "") moved = true;
for(var j = 0; j < outc; ++j){
if(outp[j] != null){
new_marbles[r+1][c+j] = ((new_marbles[r+1][c+j]||0)+(outp[j]))&255;
moved = true;
}
}
if(outp[36] != null){ // left
var left = c-1;
if(left < 0 && cylindrical_board){
left = this.cols - 1;
}
if(left >= 0){
new_marbles[r][left] = ((new_marbles[r][left]||0)+(outp[36]))&255;
moved = true;
}
}
if(outp[37] != null){ // right
var right = c+sz;
if(right >= this.cols && cylindrical_board){
right = 0;
}
if(right < this.cols){
new_marbles[r][right] = ((new_marbles[r][right]||0)+(outp[37]))&255;
moved = true;
}
}
this.stdout += cb.stdout;
}else{
for(var j = 0; j < inc; ++j){
if(this.marbles[r][c+j] != null){
new_marbles[r][c+j] = ((new_marbles[r][c+j]||0)+(this.marbles[r][c+j]))&255;
}
}
}
}
// synchronisers
for(var i = 0; i < 36; ++i){
if(this.ref.syncs[i].length){
var all = true;
for(var j = 0, len = this.ref.syncs[i].length; j < len; ++j){
if(this.marbles[this.ref.syncs[i][j][0]][this.ref.syncs[i][j][1]] == null){
all = false; break;
}
}
if(all){
for(var j = 0, len = this.ref.syncs[i].length; j < len; ++j){
var r = this.ref.syncs[i][j][0];
var c = this.ref.syncs[i][j][1];
new_marbles[r+1][c] = this.marbles[r][c];
moved = true;
}
}else{
for(var j = 0, len = this.ref.syncs[i].length; j < len; ++j){
var r = this.ref.syncs[i][j][0], c = this.ref.syncs[i][j][1];
if(this.marbles[r][c] != null){
new_marbles[r][c] = ((new_marbles[r][c]||0)+( this.marbles[r][c]))&255;
}
}
}
}
}
// input literal null move, output does not
for(var r = 0; r < this.rows; ++r){
for(var c = 0; c < this.cols; ++c){
if(this.marbles[r][c] != null){
var type = this.ref.cells[r][c] && this.ref.cells[r][c].type;
if(!type || type == CTypes.INPUT || type == CTypes.LITERAL){
new_marbles[r+1][c] = ((new_marbles[r+1][c]||0)+(this.marbles[r][c]))&255;
moved = true;
}else if(type == CTypes.OUTPUT){
new_marbles[r][c] = ((new_marbles[r][c]||0)+(this.marbles[r][c]))&255;
}
}
}
}
// shift portal
for(var i = 0; i < 36; ++i){
if(this.ref.portals[i].length){
var p = this.ref.portals[i];
if(p.length == 1){
var r = p[0][0], c = p[0][1];
if(this.marbles[r][c] != null){
new_marbles[r+1][c] = ((new_marbles[r+1][c]||0)+( this.marbles[r][c]))&255;
moved = true;
}
}else{
var q = [];
for(var j = 0, l = p.length; j < l; ++j){
if(this.marbles[p[j][0]][p[j][1]] != null){
// generate output portal - any other portal except the input
var toWhere = Math.floor(Math.random() * (l-1));
if(toWhere >= j) ++toWhere;
var r = p[j][0], c = p[j][1];
q[toWhere] = ((q[toWhere]||0)+(this.marbles[r][c]))&255;
moved = true;
}
}
for(var j = 0, l = p.length; j < l; ++j){
if(q[j] != null){
var r = p[j][0] + 1, c = p[j][1];
new_marbles[r][c] = q[j];
}
}
}
}
}
// check stdout
if(new_marbles[new_marbles.length-1].length){
var r = this.rows;
for(var i = 0, l = new_marbles[r].length; i < l; ++i){
if(new_marbles[r][i] != null){
putch(this, new_marbles[r][i]);
moved = true;
}
}
}
new_marbles.splice(this.rows);
if(!moved){
this.tickNum = -1;
return moved;
}
this.marbles = new_marbles;
// check terminator
for(var i = 0, len = this.ref.terminators.length; i < len; ++i){
var r = this.ref.terminators[i][0], c = this.ref.terminators[i][1];
if(new_marbles[r][c] != null){
this.tickNum = -1;
return moved;
}
}
// check output
if(this.outc){
var allOuts = true;
for(var i = 0; i < 38; ++i){
var o = this.ref.outputs[i];
if(o.length){
var occupied = false;
for(var j = 0, len = o.length; j < len; ++j){
if(new_marbles[o[j][0]][o[j][1]] != null){
occupied = true;
break;
}
}
if(!occupied){
allOuts = false; break;
}
}
}
if(allOuts){
this.tickNum = -1;
return moved;
}
}
++this.tickNum;
return moved;
};
Board.prototype.out = function(){
if(this.type != 2) throw "Calling Board.out without Board.runCopy";
if(this.tickNum != -1) throw "Copied board hasn't run to completion yet";
if(this.ref.type == 1) return this.outp;
var outp = {};
for(var i = 0; i < 38; ++i){
if(this.ref.outputs[i].length){
outp[i] = 0;
var o = this.ref.outputs[i], isFilled = false;
for(var j = 0, len = o.length; j < len; ++j){
var r = o[j][0], c = o[j][1];
isFilled = isFilled || this.marbles[r][c] != null;
outp[i] = ((outp[i])+( this.marbles[r][c] || 0))&255;
}
if(!isFilled)
outp[i] = null;
}
}
return outp;
};
function DrawBuffer(canvas){
this.canvas = canvas;
this.ctx = this.canvas.getContext('2d');
this.ctx.fillStyle = 'rgb(0,0,0)';
this.ctx.fillRect(0, 0, 256, 256);
}
DrawBuffer.prototype.clear = function(){
this.ctx.fillStyle = 'rgb(0,0,0)';
this.ctx.fillRect(0, 0, 256, 256);
};
DrawBuffer.prototype.set = function(x, y, r, g, b){
this.ctx.fillStyle = 'rgb(' + r + ',' + g + ',' + b + ')';
this.ctx.fillRect(x, y, 1, 1);
};
DrawBuffer.prototype.get = function(x, y){
return this.ctx.getImageData(x, y, 1, 1).data.splice(0, 3);
};
// spaces: is an empty cell denoted with whitespace?
function parseMblSrc(src,spaces){
var lines = (':MB\n'+src).split('\n');
var sb = []; // start lines of new mb subboards
for(var i = lines.length; i-- > 0;){
// strip mid-line spaces if possible
if(!spaces){
lines[i] = lines[i].trim();
lines[i] = lines[i].replace(/\s/g,'');
}
// index of comment
var o = lines[i].indexOf('#');
// remove comments
if(o > 0){
lines[i] = lines[i].substr(0, o).trim();
}else if(lines[i].length == 0 || o == 0){
if(lines[i].indexOf('include') == 1){
throw "#include not supported";
}
lines.splice(i, 1);
}
}
for(var i = lines.length; i-- > 0;){
// identify subboards
if(lines[i].charAt(0) == ':'){
sb.push(i);
}
}
sb.sort(function(a,b){return a-b;});
var mbname = '';
for(var i = 0, len = sb.length; i < len; ++i){
var name = lines[sb[i]].substr(1).trim();
var board;
board = new Board(name, false);
var endl;
if(i == len - 1) endl = lines.length;
else endl = sb[i+1];
for(var j = sb[i]+1; j < endl; ++j){
var r = j - sb[i] - 1;
if(lines[j].length % 2 != 0){
throw "Error near `" + lines[j] + "`";
}
var cells = lines[j].match(/../g);
for(var k = 0, clen = cells.length; k < clen; ++k){
var val;
if(val = cells[k].match(/^@([0-9A-Z])$/)){
board.set(r, k, new Cell(CTypes.PORTAL, parseInt(val[1], 36)));
}else if(val = cells[k].match(/^&([0-9A-Z])$/)){
board.set(r, k, new Cell(CTypes.SYNCHRONISER, parseInt(val[1], 36)));
}else if(val = cells[k].match(/^}([0-9A-Z])$/)){
board.set(r, k, new Cell(CTypes.INPUT, parseInt(val[1], 36)));
}else if(val = cells[k].match(/^{([0-9A-Z<>])$/)){
var value;
if(val[1] == '<' || val[1] == '>') value = val[1];
else value = parseInt(val[1], 36);
board.set(r, k, new Cell(CTypes.OUTPUT, value));
}else if(cells[k] == '!!'){
board.set(r, k, new Cell(CTypes.TERMINATE, 0));
}else if(val = cells[k].match(/^[0-9A-F]{2}$/)){
board.set(r, k, new Cell(CTypes.LITERAL, parseInt(cells[k], 16)));
}else if(cells[k].match(/^[ \.]{2}$/)){
board.set(r, k, null);
}else{
board.set(r, k, new Cell(CTypes.SUBROUTINE, cells[k]));
}
}
}
board.init();
if(name == 'MB')
mbname = board.name;
name = board.name;
bnames.push(name);
boards[name] = board;
}
// validate and connect subr
for(var p in boards){
boards[p].validateSubr(bnames);
}
return mbname;
}
function run(){
// normal init
stopped = false;
max_tick = document.getElementById('mb-ticks').value;
space_as_blank = document.getElementById('mb-spaces').checked;
cylindrical_board = document.getElementById('mb-cylinder').checked;
print_numbers = document.getElementById('mb-numprint').checked;
libraries = document.getElementById('mb-lib').checked;
gfx = document.getElementById('mb-gfx').checked;
src = document.getElementById('mb-src').value;
stdin = document.getElementById('mb-in').value;
boards = {};
bnames = [];
loadDefaultBoards();
if(gfx){
// prepare draw buffers
front_buffer = new DrawBuffer(document.getElementById('mb-fb'));
back_buffer = new DrawBuffer(document.getElementById('mb-bb'));
}else{
if(front_buffer){
front_buffer.clear();
back_buffer.clear();
front_buffer = null;
back_buffer = null;
}
}
try{
var mb = parseMblSrc(src, space_as_blank);
var rc = boards[mb].runCopy(document.getElementById('mb-args').value.split(' '));
var tmp = function(){
try{
if(stopped) throw "Board execution stopped.";
else if(rc.tickNum != -1 && rc.tickNum < max_tick){
rc.tick();
document.getElementById('mb-out').value = rc.stdout;
document.getElementById('mb-out').scrollTop = document.getElementById('mb-out').scrollHeight;
setTimeout(tmp, 0);
}else if(rc.tickNum == -1){
document.getElementById('mb-out').value = rc.stdout;
document.getElementById('mb-out').scrollTop = document.getElementById('mb-out').scrollHeight;
document.getElementById('mb-return').value = rc.out()[0] || 0;
}else throw "Max tick count exceeded running main board.";
}catch(e){
document.getElementById('mb-out').value = rc.stdout + '\n' + e;
document.getElementById('mb-out').scrollTop = document.getElementById('mb-out').scrollHeight;
}
};
setTimeout(tmp, 0);
}catch(e){
document.getElementById('mb-out').value = (rc ? rc.stdout: '') + '\n' + e;
document.getElementById('mb-out').scrollTop = document.getElementById('mb-out').scrollHeight;
}
}
function stop(){
stopped = true;
}
<div style="font-size: 12px;font-family: Helvetica, Arial, sans-serif;">
<div style="float: left;">
Marbelous Source:<br />
<textarea id="mb-src" rows="4" cols="35">48 65 6C 6C 6F 20 57 6F 72 6C 64 21</textarea><br />
Arguments: <br />
<input id="mb-args" size="33" /> <br />
STDIN: <br />
<textarea id="mb-in" rows="2" cols="35"></textarea><br />
<span style="float: left">
Max Ticks: <input id="mb-ticks" type="number" min="1" style="width: 60px" value="1000" />
</span>
<span style="float: right">
<input type="button" onclick="run()" value="Run Code" style="" />
<input type="button" onclick="stop()" value="Stop" style="" />
</span>
</div>
<div style="float: left; margin-left: 15px;">
<div style="margin-bottom: 10px">
<input type="checkbox" id="mb-spaces" />Using spaces for blank cells<br />
<input type="checkbox" id="mb-cylinder" />Cylindrical Board<br />
<input type="checkbox" id="mb-numprint" />Display output as decimal numbers<br />
<input type="checkbox" id="mb-lib" checked="true" />Include Libraries<br />
<input type="checkbox" id="mb-gfx" />Use Draw Buffers<br />
</div>
<div>
STDOUT:<br />
<textarea id="mb-out" rows="3" cols="35"></textarea><br />
Return Code: <input id="mb-return" />
</div>
</div>
<div style="clear: both; text-align: center; width: 550px; padding-top: 10px;" id="mb-draw-buffers">
<div style="float: left; width: 256px;">
Front Buffer:
<canvas style="height: 256px; width: 256px; background: black;" width="256" height="256" id="mb-fb"></canvas>
</div>
<div style="float: right; width: 256px;">
Back Buffer:
<canvas style="height: 256px; width: 256px; background: black;" width="256" height="256" id="mb-bb"></canvas>
</div>
</div>
</div>