diff --git a/www/data/css/styles.css b/www/data/css/styles.css index 5245f6c..03617c6 100644 --- a/www/data/css/styles.css +++ b/www/data/css/styles.css @@ -94,7 +94,7 @@ body { #headerdiv .tabrow .tab_github { background-color: #4078c0; border-left: 1px solid #111; - border-right: 1px solid #111; + border-right: none; color: black; } #headerdiv .tabrow .tab_github:hover { background-color: #c9510c; @@ -220,7 +220,7 @@ html, body { padding: 8px; } .bc_markdown code { - font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-family: Consolas, Monaco, "Courier New", Menlo, monospace; direction: ltr; text-align: left; white-space: pre; @@ -344,4 +344,81 @@ html, body { .euler_pnl_cell_notexist { background: #CCCCCC; } +.bfjoust_runner_owner { + border: 1px solid #888; + background: #F8F8F8; + padding: 6px; } + .bfjoust_runner_owner .hsplit { + display: flex; + flex-direction: row; + flex-wrap: nowrap; } + .bfjoust_runner_owner .hsplit_1 { + flex: 1; + margin: 4px; } + .bfjoust_runner_owner .hsplit_2 { + flex: 1; + margin: 4px; } + .bfjoust_runner_owner textarea { + font-family: Consolas, Monaco, "Courier New", Menlo, monospace; + display: block; } + .bfjoust_runner_owner .source { + height: 350px; } + .bfjoust_runner_owner .sink { + height: 100px; } + .bfjoust_runner_owner .bottomelem { + height: 200px; } + @media (max-width: 767px) { + .bfjoust_runner_owner .hsplit { + display: block; } + .bfjoust_runner_owner .hsplit_1 { + display: block; + width: calc(100% - 8px); } + .bfjoust_runner_owner .hsplit_2 { + display: block; + width: calc(100% - 8px); } + .bfjoust_runner_owner textarea { + margin-left: auto; + margin-right: auto; } } + .bfjoust_runner_owner #commandpanel { + text-align: center; + background-color: lightgray; + border-radius: 3px; + border: 1px solid gray; + display: table; + width: calc(100% - 8px); + margin: 4px; + padding: 5px 0; } + .bfjoust_runner_owner #commandpanel a { + color: #FFF; + background-color: #000; + border-radius: 3px; + padding: 4px 8px; + text-decoration: none; } + .bfjoust_runner_owner #commandpanel a:hover { + text-decoration: none; + background-color: #666; } + .bfjoust_runner_owner #commandpanel #a_run { + background-color: #080; } + .bfjoust_runner_owner #commandpanel #a_run:hover { + text-decoration: none; + background-color: #666; } + .bfjoust_runner_owner #commandpanel #a_stop { + background-color: #F00; } + .bfjoust_runner_owner #commandpanel #a_stop:hover { + text-decoration: none; + background-color: #666; } + .bfjoust_runner_owner #commandpanel #a_arena { + background-color: #F80; } + .bfjoust_runner_owner #commandpanel #a_arena:hover { + text-decoration: none; + background-color: #666; } + .bfjoust_runner_owner #run_size { + width: 40px; } + .bfjoust_runner_owner #run_speed { + width: 70px; } + .bfjoust_runner_owner #board { + background-color: #FFF; + border-radius: 6px; + border: 1px solid #CCC; } + /*# sourceMappingURL=styles.css.map */ diff --git a/www/data/css/styles.scss b/www/data/css/styles.scss index ab88641..fd1ed1b 100644 --- a/www/data/css/styles.scss +++ b/www/data/css/styles.scss @@ -6,4 +6,5 @@ @import 'styles_bloglist'; @import 'styles_blogview'; -@import 'styles_eulerpanel'; \ No newline at end of file +@import 'styles_eulerpanel'; +@import 'styles_bfjoustrunner'; \ No newline at end of file diff --git a/www/data/css/styles_bfjoustrunner.scss b/www/data/css/styles_bfjoustrunner.scss new file mode 100644 index 0000000..fc71a78 --- /dev/null +++ b/www/data/css/styles_bfjoustrunner.scss @@ -0,0 +1,84 @@ +@import 'styles_config'; + +.bfjoust_runner_owner { + + border: 1px solid #888; + background: #F8F8F8; + padding: 6px; + + .hsplit { + display:flex; + flex-direction: row; + flex-wrap: nowrap; + } + + .hsplit_1 { flex: 1; margin: 4px; } + .hsplit_2 { flex: 1; margin: 4px; } + + textarea { font-family: $FONT_CODE; display:block; } + + .source { height: 350px; } + .sink { height: 100px; } + .bottomelem { height: 200px; } + + @media (max-width: 767px) { + .hsplit { display:block; } + .hsplit_1 { display:block; width: calc(100% - 8px); } + .hsplit_2 { display:block; width: calc(100% - 8px); } + textarea { margin-left: auto; margin-right: auto; } + } + + #commandpanel { + text-align: center; + background-color: lightgray; + + border-radius: 3px; + border: 1px solid gray; + + display: table; + width: calc(100% - 8px);; + + margin: 4px; + padding: 5px 0; + + a { + color: #FFF; + background-color: #000; + border-radius: 3px; + padding: 4px 8px; + text-decoration: none; + &:hover { text-decoration: none; background-color: #666; } + } + + #a_run { + background-color: #080; + &:hover { text-decoration: none; background-color: #666; } + } + + #a_stop { + background-color: #F00; + &:hover { text-decoration: none; background-color: #666; } + } + + #a_arena { + background-color: #F80; + &:hover { text-decoration: none; background-color: #666; } + } + } + + #run_size { + width: 40px; + } + + #run_speed { + width: 70px; + } + + #board { + background-color: #FFF; + border-radius: 6px; + + border:1px solid #CCC; + } + +} \ No newline at end of file diff --git a/www/data/css/styles_blogview.scss b/www/data/css/styles_blogview.scss index 1517850..f1ca04e 100644 --- a/www/data/css/styles_blogview.scss +++ b/www/data/css/styles_blogview.scss @@ -19,7 +19,7 @@ } .bc_markdown code { - font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-family: $FONT_CODE; direction: ltr; text-align: left; white-space: pre; @@ -42,7 +42,7 @@ word-break: break-all; word-wrap: break-word; white-space: pre-wrap; - background-color: #F8F8F8; + background-color: $COL_BACKGROUND_3; color: black; border: 1px solid rgba(0,0,0,.15); -webkit-border-radius: 2px; diff --git a/www/data/css/styles_config.scss b/www/data/css/styles_config.scss index 3e05e6a..982b514 100644 --- a/www/data/css/styles_config.scss +++ b/www/data/css/styles_config.scss @@ -1,7 +1,9 @@ -$COL_BACKGROUND: #EEE; +$COL_BACKGROUND: #EEE; $COL_BACKGROUND_2: #E0E0E0; -$COL_TEXT_NORMAL: #CCC; -$COL_TEXT_DARK: #333; -$COL_TRANSPARENT: #FFFFFF00; +$COL_BACKGROUND_3: #F8F8F8; +$COL_TEXT_NORMAL: #CCC; +$COL_TEXT_DARK: #333; +$COL_TRANSPARENT: #FFFFFF00; -$FONT_HEADER: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; \ No newline at end of file +$FONT_HEADER: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; +$FONT_CODE: Consolas, Monaco, "Courier New", Menlo, monospace; \ No newline at end of file diff --git a/www/data/css/styles_header.scss b/www/data/css/styles_header.scss index 99fe265..65b940d 100644 --- a/www/data/css/styles_header.scss +++ b/www/data/css/styles_header.scss @@ -57,7 +57,7 @@ .tab_github { background-color: #4078c0; border-left: 1px solid #111; - border-right: 1px solid #111; + border-right: none; color: black; &:hover { diff --git a/www/data/javascript/blogpost_BFJoustBot_script.js b/www/data/javascript/blogpost_BFJoustBot_script.js new file mode 100644 index 0000000..4ac8d74 --- /dev/null +++ b/www/data/javascript/blogpost_BFJoustBot_script.js @@ -0,0 +1,924 @@ +if (!window.console) { + window.console = { + log: function() {} + }; +} + +function inheritPrototype(childObject, parentObject) { + var copyOfParent = Object.create(parentObject.prototype); + copyOfParent.constructor = childObject; + childObject.prototype = copyOfParent; +} + +function matchWinnerToChar(w) { + switch (w) { + case MatchWinner.ABORT: + return '#'; + case MatchWinner.PLAYER_1: + return '1'; + case MatchWinner.DRAW: + return 'X'; + case MatchWinner.PLAYER_2: + return '2'; + case MatchWinner.UNDEFINIED: + return '?'; + default: + throw "non-enum value in MatchWinnerToChar(" + w + ")"; + } +} + +Array.prototype.contains = function(obj) { + var i = this.length; + while (i--) { + if (this[i] === obj) { + return true; + } + } + return false; +}; + +Array.prototype.last = function() { + return this[this.length - 1]; +}; + +Array.prototype.peek = function() { + return this[this.length - 1]; +}; + +String.prototype.reps = function( num ) { + return new Array( num + 1 ).join( this ); +}; + +var RepetitionState = { + OPEN: 10, + CLOSED: 11, + AWAITING_NUMBER: 12, + FINISHED: 13 +}; +var RepetitionMode = { + UNDEFINIED: 10, + ITERATIVE: 11, + RECURSIVE: 12 +}; +var MatchWinner = { + UNDEFINIED: 0, + PLAYER_1: 10, + DRAW: 15, + PLAYER_2: 20, + ABORT: -1 +}; + +var BF_CHARS = ['+', '-', '<', '>', '[', ']', '.']; +var PP_CHARS = ['(', ')', '*', '{', '}', '%', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; +var NM_CHARS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + + +//###################################################### + +function BFPart() {} + +BFPart.prototype.constructor = BFPart; +BFPart.prototype.append = function(part) { + throw "abstract"; +}; +BFPart.prototype.toProgram = function() { + throw "abstract"; +}; +BFPart.prototype.finish = function() { + throw "abstract"; +}; + +//###################################################### + +function BFCommand(c) { + this.cmd = c; + + BFPart.call(this); +} + +inheritPrototype(BFCommand, BFPart); + +BFCommand.prototype.constructor = BFCommand; +BFCommand.prototype.append = function(part) { + throw "Invalid Appendix"; +}; + +BFCommand.prototype.toProgram = function() { + return this.cmd; +}; + +BFCommand.prototype.finish = function() { + // void +}; + +//###################################################### + +function BFConcat() { + this.list = [] + + BFPart.call(this); +} + +inheritPrototype(BFConcat, BFPart); + +BFConcat.prototype.constructor = BFConcat; + +BFConcat.prototype.append = function(part) { + if (this.list.length > 0) + this.list.last().finish(); + + this.list.push(part); +}; + +BFConcat.prototype.toProgram = function() { + return this.list.map(function(x) { + return x.toProgram(); + }).join(""); +}; + +BFConcat.prototype.finish = function() { + if (this.list.length > 0) + this.list.last().finish(); +}; + +BFConcat.prototype.splitAroundCenter = function() { + var left = new BFConcat(); + var center = null; + var right = new BFConcat(); + + var i = 0; + for (; i < this.list.length; i++) { + if (this.list[i] instanceof BFCenterLiteral) { + center = this.list[i]; + break; + } else { + left.append(this.list[i]); + } + } + + i++; + + for (; i < this.list.length; i++) { + if (this.list[i] instanceof BFCenterLiteral) { + throw "Two much {} in Repetition found"; + } else { + right.append(this.list[i]); + } + } + + if (center === null) + throw "No {} in Repetition found"; + + return [left, center, right]; +}; + +//###################################################### + +function BFCenterLiteral() { + BFConcat.call(this); +} + +inheritPrototype(BFCenterLiteral, BFConcat); + +BFCenterLiteral.prototype.constructor = BFCenterLiteral; + +//###################################################### + +function BFRepetition() { + this.state = RepetitionState.OPEN; + this.mode = RepetitionMode.UNDEFINIED; + this.parts = new BFConcat(); + this.count = 0; + + BFPart.call(this); +} + +inheritPrototype(BFRepetition, BFPart); + +BFRepetition.prototype.constructor = BFCommand; +BFRepetition.prototype.append = function(part) { + this.parts.append(part); +}; + +BFRepetition.prototype.toProgram = function() { + if (this.mode == RepetitionMode.ITERATIVE) { + return new Array(this.count + 1).join(this.parts.toProgram()); + } else if (this.mode == RepetitionMode.RECURSIVE) { + var split = this.parts.splitAroundCenter(); + + var left = new Array(this.count + 1).join(split[0].toProgram()); + var center = split[1].toProgram(); + var right = new Array(this.count + 1).join(split[2].toProgram()); + + return left + center + right; + } else { + throw "RepMode not definied"; + } +}; + +BFRepetition.prototype.close = function() { + if (this.state == RepetitionState.CLOSED) return; + + if (this.state != RepetitionState.OPEN) + throw ("state != OPEN, state == " + this.state); + + this.state = RepetitionState.CLOSED; +}; + +BFRepetition.prototype.startNumberWaiting = function(md) { + this.mode = md; + + if (this.state == RepetitionState.AWAITING_NUMBER) return; + + if (this.state != RepetitionState.CLOSED) + throw ("state != CLOSED, state == " + this.state); + + this.state = RepetitionState.AWAITING_NUMBER; +}; + +BFRepetition.prototype.finish = function() { + if (this.state == RepetitionState.FINISHED) return; + + if (this.state != RepetitionState.AWAITING_NUMBER) + throw ("state != AWAITING_NUMBER, state == " + this.state); + + this.state = RepetitionState.FINISHED; +}; + +BFRepetition.prototype.addNumber = function(p) { + this.count *= 10; + this.count += p; +}; + +//###################################################### + +function BFProg (_code) { + this.code_position = 0; + this.board_position = 0; + this.inverted = false; // + <-> - + this.active = true; + this.code = _code; +} + +BFProg.prototype.constructor = BFProg; + +BFProg.prototype.step = function(match, invertboard) { + //console.log(this.code_position + " #> " + this.getCommand() + " (" + match.get(this.board_position, invertboard) + ")"); + switch(this.getCommand()) { + case '+': + match.inc(this.board_position, invertboard); + break; + + case '-': + match.dec(this.board_position, invertboard); + break; + + case '<': + this.board_position--; + break; + + case '>': + this.board_position++; + break; + + case '.': + // Do nothing + break; + + case '[': + if (match.get(this.board_position, invertboard) == 0) { + this.skip_forward(); + this.code_position--; // reverse effect of next move + } + break; + + case ']': + this.skip_backward(); + this.code_position--; // reverse effect of next move + break; + + default: + throw "Unknown Char in prog: " + this.code.charAt(this.position); + } + this.move(); +} + +BFProg.prototype.move = function() { + if (this.code_position < this.code.length - 1) + this.code_position++; + else { + if (this.active) console.log("END OF CODE REACHED"); + this.active = false; + } + +} + +BFProg.prototype.skip_forward = function() { + var depth = 0; + + do { + var chr = this.code.charAt(this.code_position); + if (chr == '[') + depth++ + else if (chr == ']') + depth--; + + this.code_position++; + + + } while (depth > 0) +} + +BFProg.prototype.skip_backward = function() { + var depth = -1; + + do { + this.code_position--; + + var chr = this.code.charAt(this.code_position); + if (chr == '[') + depth++ + else if (chr == ']') + depth--; + + + } while (depth < 0) +} + +BFProg.prototype.getCommand = function() { + if (this.active) { + switch(this.code.charAt(this.code_position)) { + case '+': return this.inverted ? '-' : '+'; + case '-': return this.inverted ? '+' : '-'; + case '<': return '<'; + case '>': return '>'; + case '.': return '.'; + case '[': return '['; + case ']': return ']'; + default: throw "Unknown Char in prog: " + this.code.charAt(this.code_position); + } + } else { + return '.'; + } +} + +BFProg.prototype.isFlowCommand = function() { + if (this.active) { + switch(this.code.charAt(this.code_position)) { + case '+': return false; + case '-': return false; + case '<': return true; + case '>': return true; + case '.': return false; + case '[': return true; + case ']': return true; + default: throw "Unknown Char in prog: " + this.code.charAt(this.code_position); + } + } else { + return '.'; + } +} + +BFProg.prototype.getBoardPos = function(invertboard, size) { + if (invertboard) + return (size - 1) - this.board_position; + else + return this.board_position; +} + +BFProg.prototype.isOOB = function(size) { + return this.board_position < 0 || this.board_position >= size; +} + +//###################################################### + +function BFMatch (_size, _prog1, _prog2) { + this.size = _size; + this.prog1 = _prog1; + this.prog2 = _prog2; + + this.flagZeroed1 = 0; + this.flagZeroed2 = 0; + this.roundCount = 0; + this.winner = MatchWinner.UNDEFINIED; + this._intervalID = -1 + + this.map = new Array(_size); + for(var i = 0; i < _size; i++) this.map[i] = 0; + this.map[0] = 128; + this.map[this.map.length - 1] = 128; +} + +BFMatch.prototype.constructor = BFMatch; + +BFMatch.prototype.calc = function() { + for(;;) { + this.roundCount++; + + if (this.prog2.isFlowCommand()) { // Flow-cmd first -> reverse order + this.prog2.step(this, true); + this.prog1.step(this, false); + } else { + this.prog1.step(this, false); + this.prog2.step(this, true); + } + + this.stepFlag(); + this.stepWinner(); + + if (this.winner != MatchWinner.UNDEFINIED) + break; + } + + return this.winner; +} + +BFMatch.prototype.start = function(canvas, width, height, speed) { + this.param_canvas = canvas; + this.param_width = width; + this.param_height = height; + + this._intervalID = setInterval(this.tick.bind(this), speed); +}; + +BFMatch.prototype.stop = function(winner) { + if (winner == MatchWinner.UNDEFINIED) + throw ("can't stop on undef"); + + if (this._intervalID != -1) { + clearInterval(this._intervalID); + this._intervalID = -1 + } + + console.log("Match stopped winner: " + winner); + + switch (winner) { + case MatchWinner.PLAYER_1: + this.winner = MatchWinner.PLAYER_1; + break; + case MatchWinner.DRAW: + this.winner = MatchWinner.DRAW; + break; + case MatchWinner.PLAYER_2: + this.winner = MatchWinner.PLAYER_2; + break; + case MatchWinner.ABORT: + this.winner = MatchWinner.ABORT; + break; + default: + throw ( "no-enum value in stop()" ); + } +}; + +BFMatch.prototype.tick = function() { + this.step(); + this.draw(this.param_canvas, this.param_width, this.param_height); +}; + +BFMatch.prototype.step = function() { + this.roundCount++; + + if (this.prog2.isFlowCommand()) { // Flow-cmd first -> reverse order + this.prog2.step(this, true); + this.prog1.step(this, false); + } else { + this.prog1.step(this, false); + this.prog2.step(this, true); + } + + this.stepFlag(); + this.stepWinner(); + + if (this.winner == MatchWinner.PLAYER_1) + alert('Player 1 (left) won'); + else if (this.winner == MatchWinner.PLAYER_2) + alert('Player 2 (right) won'); + else if (this.winner == MatchWinner.DRAW) + alert('Draw'); +}; + +BFMatch.prototype.stepFlag = function() { + if (this.map[0] == 0) + this.flagZeroed1++; + else + this.flagZeroed1 = 0; + + if (this.map[this.size - 1] == 0) + this.flagZeroed2++; + else + this.flagZeroed2 = 0; +} + +BFMatch.prototype.getFlagWeight = function(fg) { + if (fg == MatchWinner.PLAYER_1) { + return Math.abs(this.map[0]); + } else if (fg == MatchWinner.PLAYER_2) { + return Math.abs(this.map[this.size - 1]); + } else { + throw "Unknown player: " + fg; + } +} + +BFMatch.prototype.stepWinner = function() { + if (this.roundCount > 100000 && this.getFlagWeight(MatchWinner.PLAYER_1) == this.getFlagWeight(MatchWinner.PLAYER_2)) + this.stop(MatchWinner.DRAW); + + if ((this.prog1.isOOB(this.size) || this.flagZeroed1 >= 2) && (this.prog2.isOOB(this.size) || this.flagZeroed2 >= 2)) + this.stop(MatchWinner.DRAW); + + if (this.prog1.isOOB(this.size) || this.flagZeroed1 >= 2) + this.stop(MatchWinner.PLAYER_2); + + if (this.prog2.isOOB(this.size) || this.flagZeroed2 >= 2) + this.stop(MatchWinner.PLAYER_1); + + if (this.roundCount > 100000 && this.getFlagWeight(MatchWinner.PLAYER_1) > this.getFlagWeight(MatchWinner.PLAYER_2)) + this.stop(MatchWinner.PLAYER_1); + + if (this.roundCount > 100000 && this.getFlagWeight(MatchWinner.PLAYER_1) < this.getFlagWeight(MatchWinner.PLAYER_2)) + this.stop(MatchWinner.PLAYER_2); +} + +BFMatch.prototype.inc = function(idx, invertboard) { + if (invertboard) idx = (this.size - 1) - idx; + + this.map[idx]++; + this.map[idx] = (this.map[idx] + 127 + 256) % 256 - 127; +} + +BFMatch.prototype.dec = function(idx, invertboard) { + if (invertboard) idx = (this.size - 1) - idx; + + this.map[idx]--; + this.map[idx] = (this.map[idx] + 127 + 256) % 256 - 127; +} + +BFMatch.prototype.get = function(idx, invertboard) { + if (invertboard) idx = (this.size - 1) - idx; + + return this.map[idx]; +} + +BFMatch.prototype.draw = function(canvas, width, height) { + var BORDER = 4; + var PADDING = 2; + + var cell_width = (((width - 2*BORDER) + PADDING) / this.size) - PADDING; + var cell_height = cell_width * 3/4; + var max_height = (height - 2*BORDER - cell_height) / 2; + + cell_width = Math.floor(cell_width); + cell_height = Math.floor(cell_height); + max_height = Math.floor(max_height); + + canvas.lineWidth = 1; + + + canvas.fillStyle="#FFFFFF"; + canvas.fillRect(0, 0, width, height); + canvas.fillStyle="#000000"; + + for (var i = 0; i < this.size; i++) { + var cell_value = this.map[i]; + + var x = Math.floor(BORDER + i*(cell_width + PADDING)) + 0.5; + var y = Math.floor(height/2 - cell_height/2) + 0.5; + + canvas.fillStyle="#F3F3F3"; + canvas.beginPath(); + canvas.rect(x, y, cell_width, cell_height); + canvas.closePath(); + canvas.fill(); + canvas.stroke(); + + if (this.prog1.getBoardPos(false, this.size) == i) { + canvas.fillStyle="#F00"; + canvas.beginPath(); + canvas.moveTo(x, y); + canvas.lineTo(x + cell_height/2, y + cell_height/2); + canvas.lineTo(x, y + cell_height); + canvas.lineTo(x, y); + canvas.closePath(); + canvas.fill(); + canvas.stroke(); + } + + if (this.prog2.getBoardPos(true, this.size) == i) { + canvas.fillStyle="#00F"; + canvas.beginPath(); + canvas.moveTo(x + cell_width, y); + canvas.lineTo(x + cell_width - cell_height/2, y + cell_height/2); + canvas.lineTo(x + cell_width, y + cell_height); + canvas.lineTo(x + cell_width, y); + canvas.closePath(); + canvas.fill(); + canvas.stroke(); + } + + if (i == 0) + canvas.fillStyle="#F00"; + else if (i == this.size - 1) + canvas.fillStyle="#00F"; + else + canvas.fillStyle="#484D51"; + if (cell_value < 0) { + canvas.beginPath(); + canvas.rect(x, + y + cell_height, + cell_width, + -Math.floor(max_height * cell_value/128)); + canvas.closePath(); + canvas.fill(); + canvas.stroke(); + } else if (cell_value > 0) { + canvas.beginPath(); + canvas.rect(x, + y, + cell_width, + -Math.ceil(max_height * cell_value/128)); + canvas.closePath(); + canvas.fill(); + canvas.stroke(); + } + } +} + +//###################################################### +//###################################################### +//###################################################### + +function expand(input) { + var root = new BFConcat(); + var stack = []; + stack.push(root); + var linep = 1; + var charp = 1; + + for (var i = 0; i < input.length; i++) { + var c = input.charAt(i); + var next = ((i + 1) == input.length) ? (' ') : (input.charAt(i + 1)); + + if (c == '\n') { + linep++; + charp = 0; + } + charp++; + + if (BF_CHARS.contains(c)) { + stack.peek().append(new BFCommand(c)); + } else if (c == '(') { + var rep = new BFRepetition(); + stack.peek().append(rep); + stack.push(rep); + } else if (c == ')' && stack.peek() instanceof BFRepetition && stack.peek().state == RepetitionState.OPEN) { + stack.peek().close(); + + if (next != '*' && next != '%') { + stack.peek().startNumberWaiting(RepetitionMode.ITERATIVE); + stack.peek().addNumber(1); + stack.peek().finish(); + stack.pop(); + } + } else if (c == '{' && stack.peek() instanceof BFRepetition) { + var rep = new BFCenterLiteral(); + stack.peek().append(rep); + stack.push(rep); + } else if (c == '}' && stack.peek() instanceof BFCenterLiteral) { + stack.pop(); + } else if (c == '*' && stack.peek() instanceof BFRepetition) { + var rep = stack.peek(); + + rep.startNumberWaiting(RepetitionMode.ITERATIVE); + } else if (c == '%' && stack.peek() instanceof BFRepetition) { + var rep = stack.peek(); + + rep.startNumberWaiting(RepetitionMode.RECURSIVE); + } else if (NM_CHARS.contains(c) && stack.peek() instanceof BFRepetition && stack.peek().state == RepetitionState.AWAITING_NUMBER) { + var rep = stack.peek(); + + rep.addNumber(c - '0'); + + if (!NM_CHARS.contains(next)) + stack.pop(); + } else { + console.log("Ignore Char: '" + c + "'"); + } + } + + + if (stack.peek() !== root) + throw ("Stack not unwinded" + stack); + + return root.toProgram(); +} + +//###################################################### + +function getCollapseCount(code, width) { + var count = 0; + var piece = code.substr(0, width); + + for(var pos = 0; pos <= code.length; pos += width) { + if (code.substr(pos, width) == piece) + count++; + else + return count; + } + + return count; +} + +function isSquareBracketHill(code) { + var height = 0; + + for(var p = 0; p < code.length; p++) { + if (code.charAt(p) == '[') height++; + else if (code.charAt(p) == ']') height--; + + if (height < 0) return false; + } + + return height == 0; +} + +function collapse(code) { + if (code.length == 0) return code; + + var maxImprovement = 0; + var maxImpWidth = -1; + var maxImpRep = -1; + + for(var i = 1; i < (code.length/2 + 1); i++) { + var width = i; + + if (! isSquareBracketHill(code.substr(0, width))) continue; + + var rep = getCollapseCount(code, width); + + if (width * rep > width + 4 && (width * rep - (width + 4)) > maxImprovement) { + maxImprovement = (width * rep - (width + 4)); + maxImpWidth = width; + maxImpRep = rep + } + } + + if (maxImpWidth > 0) + return "(" + collapse(code.substr(0, maxImpWidth)) + ")*" + maxImpRep + collapse(code.substr(maxImpRep * maxImpWidth, code.length)); + else + return code.substr(0, 1) + collapse(code.substr(1, code.length)); +} + +//###################################################### + +document.getElementById("a_expand").onclick = onExpandClicked; +document.getElementById("a_collapse").onclick = onCollapseClicked; +document.getElementById("a_run").onclick = onRunClicked; +document.getElementById("a_stop").onclick = onStopClicked; +document.getElementById("a_arena").onclick = onArenaClicked; + +function onExpandClicked() { + var source1 = document.getElementById("source_1"); + var sink1 = document.getElementById("sink_1"); + var source2 = document.getElementById("source_2"); + var sink2 = document.getElementById("sink_2"); + + sink1.value = expand(source1.value); + sink2.value = expand(source2.value); + + return false; +} + +function onCollapseClicked() { + { + var source = document.getElementById("source_1"); + var sink = document.getElementById("sink_1"); + sink.value = collapse(expand(source.value)); + } + + { + var source = document.getElementById("source_2"); + var sink = document.getElementById("sink_2"); + sink.value = collapse(expand(source.value)); + } + + return false; +} + +var match = null; + +function onRunClicked() { + + if (match != null) { + match.stop(MatchWinner.ABORT); + match = null; + } + + var param_size = parseInt( document.getElementById("run_size").value ); + var param_speed = parseInt( document.getElementById("run_speed").value ); + var source1 = document.getElementById("source_1"); + var code1 = expand(source1.value); + var source2 = document.getElementById("source_2"); + var code2 = expand(source2.value); + var brd = document.getElementById("board"); + var ctx = brd.getContext("2d"); + + brd.setAttribute('width', brd.offsetWidth); + brd.setAttribute('height', brd.offsetHeight); + + match = new BFMatch(param_size, new BFProg(code1), new BFProg(code2)); + + document.getElementById("sink_1").value = code1; + document.getElementById("sink_2").value = code2; + + match.start(ctx, brd.width, brd.height, param_speed); + + return false; +} + +function onStopClicked() { + + if (match == null) return false; + + document.getElementById("sink_1").value = ''; + document.getElementById("sink_2").value = ''; + + var canvas = document.getElementById("board").getContext("2d"); + canvas.fillStyle="#FFFFFF"; + canvas.fillRect(0, 0, document.getElementById("board").width, document.getElementById("board").height) + + match.stop(MatchWinner.ABORT); + match = null; + + return false; +} + +function onArenaClicked() { + + if (match != null) { + match.stop(MatchWinner.ABORT); + match = null; + } + + var source1 = document.getElementById("source_1"); + var code1 = expand(source1.value); + var source2 = document.getElementById("source_2"); + var code2 = expand(source2.value); + + var result = new Array(31); + for (var i = 0; i < 31; i++) result[i] = new Array(2); + var result_p1 = 0; + var result_draw = 0; + var result_p2 = 0; + + for (var msize = 10; msize <= 30 ; msize++) { + var p1 = new BFProg(code1); + var p2 = new BFProg(code2); + + match = new BFMatch(msize, p1, p2); + + result[msize][0] = match.calc(); + + if (result[msize][0] == MatchWinner.PLAYER_1) result_p1++; + if (result[msize][0] == MatchWinner.DRAW) result_draw++; + if (result[msize][0] == MatchWinner.PLAYER_2) result_p2++; + + //----------------------------------------- + + var p1 = new BFProg(code1); + var p2 = new BFProg(code2); + p2.inverted = true; + + var match = new BFMatch(msize, p1, p2); + + result[msize][1] = match.calc(); + + if (result[msize][1] == MatchWinner.PLAYER_1) result_p1++; + if (result[msize][1] == MatchWinner.DRAW) result_draw++; + if (result[msize][1] == MatchWinner.PLAYER_2) result_p2++; + } + + var log = ""; + + log += "Wins Player 1 (left) :" + result_p1 + '\n'; + log += "Draws :" + result_draw + '\n'; + log += "Wins Player 2 (left) :" + result_p2 + '\n'; + log += "" + '\n'; + + log += " ".reps(9) + "|"; + for (var i = 10; i <= 30; i++) log += ' ' + i; + log += '\n'; + + log += "-".reps(9) + "|" + "-".reps(3 * 21) + '\n'; + + log += "Normal | "; + for (var i = 10; i <= 30; i++) log += matchWinnerToChar(result[i][0]) + " "; + log += "\n"; + + log += "Inverted | "; + for (var i = 10; i <= 30; i++) log += matchWinnerToChar(result[i][1]) + " "; + log += "\n"; + + document.getElementById("log").value = log; + + return false; +} \ No newline at end of file diff --git a/www/fragments/bfjoust_runner.php b/www/fragments/bfjoust_runner.php new file mode 100644 index 0000000..5fd8d57 --- /dev/null +++ b/www/fragments/bfjoust_runner.php @@ -0,0 +1,47 @@ + + +