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>
I wonder if such snippet can send the source to an external server that would transpile it to JS then send it back... Would need to insert back the JS into the answer. Maybe doable... – PhiLho – 2015-02-04T12:35:05.787
Are we allowed to add languages written after the creation of this post? – Beta Decay – 2015-08-29T22:06:54.147
@BetaDecay Sure. Though I don't think I'll be changing the accepted answer. – Calvin's Hobbies – 2015-09-05T22:04:24.250
I'd like to see one for Retina, honestly. An online interpreter would be pretty useful. – mbomb007 – 2015-09-16T21:50:32.453
Also, if anyone wants to make a snippet for Ruby, there's already a client-side JS interpreter available.
– mbomb007 – 2015-09-16T21:59:48.3201
Slightly off-topic but relevant, https://repl.it runs with their own client-side JavaScript interpreters for [Python3, Ruby, Scheme, Lua, Java, QBasic, Forth, APL, Go, C, C++, Bloop, Emoticon, LOLCODE, BrainFuck, Unlambda, PHP, and various JavaScript derivatives].
– TessellatingHeckler – 2015-10-08T18:24:28.027Not exactly an answer of its own, but something to add to all of these. – cat – 2015-12-16T03:09:10.870
2It wouldn't be very fun, but the more practical answer for harder languages like Python would probably be to simply outsource it. – Sp3000 – 2014-10-21T09:37:52.497
7I have no idea how to run these snippets using the stack exchange app. – Jerry Jeremiah – 2014-10-21T10:10:14.127
1
I hope someone tackles C with this challenge. Here's a head start: http://stackoverflow.com/questions/6142193/c-interpreter-written-in-javascript
– Adam Davis – 2014-10-21T15:19:28.5474Food for thought... – James Williams – 2014-10-21T17:18:31.980
1@Sp3000: Or look for libraries... like below. – ArtOfCode – 2014-10-21T21:37:05.197
I tried doing for CJam, but it gave various CSP insecure errors :( . – Optimizer – 2014-10-21T23:02:15.310
Would be awesome if someone could do OCaml. There's already http://try.ocamlpro.com/ (source at https://github.com/OCamlPro/tryocaml), and js_of_ocaml, an OCaml to javascript compiler.
– ReyCharles – 2014-10-22T11:39:16.373What is the bounty winning criteria ? "Larger array of languages" - Do you mean that the same person post answers for more languages ? – Optimizer – 2014-10-23T19:55:48.497
@Optimizer It doesn't matter who posts it, I just want to see more languages than the 4 we currently have. The winner will be chosen at my discretion. It is like to be the person who obviously put the most effort in. – Calvin's Hobbies – 2014-10-23T20:02:47.380
I've been working on writing a Befunge-93 interpreter today. It's close to done, so I'm hoping to post it soon. I noticed my old interpreter was flawed, so I decided to start from scratch. – Ingo Bürk – 2014-10-25T15:54:29.983
Coming to think about it: aren't answers relying on external resources sort of defying the purpose here? They are in no way "future-proof". If they're okay I'll find a PHP proxy to fire a POST request to the Golfscript parser and parse it's output. :) – Ingo Bürk – 2014-10-27T18:56:54.537
1I've been wanting to do a self-contained Python 3 builtins-only snippet, but my (broken) parser already takes up 10k, packed... – Sp3000 – 2014-10-30T14:04:09.787
1@IngoBürk The external interpreters are kind of against the point of self-contentedness (and I'm more likely to give my bounty to a local interpreter) but they can still be quite useful. – Calvin's Hobbies – 2014-10-30T21:02:04.230
I am planning on doing a partial C++ to Python 3 after this semester is over, featuring the most common things (input/output, random numbers, loops, if/ternary if, ...). If someone will write a Python 3 interpreter, we can chain them together. – None – 2014-10-31T17:00:12.207