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>