JSFiddle - React, Tailwind, and code Playground
HTML
<div class="container">
<textarea id="source" placeholder="Enter your Befunge-93 program here" wrap="off">"39-egnufeB">:#,_@</textarea>
<div id="source-display-wrapper">
<div id="source-display"></div>
</div>
</div>
<div id="controls-container" class="container clearfix">
<input type="button" id="execute" class="control so-box" value="► Execute" />
<input type="button" id="step" class="control so-box" value="Step" />
<input type="button" id="reset" class="control so-box" value="Reset" />
</div>
<div id="stdout-container" class="container">
<textarea id="stdout" placeholder="Output" wrap="off" readonly></textarea>
</div>
<div id="options-container" class="container">
<div class="option so-box">Steps per Tick: <span id="steps-per-tick" contenteditable>500</span>
</div>
<div class="option so-box">Board Size: <span id="board-width" contenteditable>80</span> x <span id="board-height" contenteditable>25</span>
</div>
</div>
CSS
.container {
width: 100%;
}
.so-box {
font-family:'Helvetica Neue', Arial, sans-serif;
font-weight: bold;
color: #fff;
text-align: center;
padding: .3em .7em;
font-size: 1em;
line-height: 1.1;
border: 1px solid #c47b07;
-webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.3), 0 2px 0 rgba(255, 255, 255, 0.15) inset;
text-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
background: #f88912;
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.3), 0 2px 0 rgba(255, 255, 255, 0.15) inset;
}
.control {
display: inline-block;
border-radius: 6px;
float: left;
margin-right: 25px;
cursor: pointer;
}
.option {
padding: 10px 20px;
margin-right: 25px;
float: left;
}
input, textarea {
box-sizing: border-box;
}
textarea {
display: block;
white-space: pre;
overflow: auto;
height: 75px;
width: 100%;
max-width: 100%;
min-height: 25px;
}
span[contenteditable] {
padding: 2px 6px;
background: #cc7801;
color: #fff;
}
#controls-container, #options-container {
height: auto;
padding: 6px 0;
}
#stdout {
height: 50px;
}
#reset {
float: right;
}
#source-display-wrapper {
display: none;
width: 100%;
height: 100%;
overflow: auto;
border: 1px solid black;
box-sizing: border-box;
}
#source-display {
font-family: monospace;
white-space: pre;
padding: 2px;
}
.activeToken {
background: #f88912;
}
.clearfix:after {
content:".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.clearfix {
display: inline-block;
}
* html .clearfix {
height: 1%;
}
.clearfix {
display: block;
}
JavaScript
function BefungeBoard(source, constraints) {
constraints = constraints || {
width: 80,
height: 25
};
this.constraints = constraints;
this.grid = source.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/).map(function (line) {
return (line + String.repeat(' ', constraints.width - line.length)).split('');
});
for (var i = this.grid.length; i < constraints.height; i++) {
this.grid[i] = String.repeat(' ', constraints.width).split('');
}
this.pointer = {
x: 0,
y: 0
};
this.direction = Direction.RIGHT;
}
BefungeBoard.prototype.nextPosition = function () {
var vector = this.direction.toVector(),
nextPosition = {
x: this.pointer.x + vector[0],
y: this.pointer.y + vector[1]
};
nextPosition.x = nextPosition.x < 0 ? this.constraints.width - 1 : nextPosition.x;
nextPosition.y = nextPosition.y < 0 ? this.constraints.height - 1 : nextPosition.y;
nextPosition.x = nextPosition.x >= this.constraints.width ? 0 : nextPosition.x;
nextPosition.y = nextPosition.y >= this.constraints.height ? 0 : nextPosition.y;
return nextPosition;
};
BefungeBoard.prototype.advance = function () {
this.pointer = this.nextPosition();
if (this.onAdvance) {
this.onAdvance.call(null, this.pointer);
}
};
BefungeBoard.prototype.currentToken = function () {
return this.grid[this.pointer.y][this.pointer.x];
};
BefungeBoard.prototype.nextToken = function () {
var nextPosition = this.nextPosition();
return this.grid[nextPosition.y][nextPosition.x];
};
var Direction = (function () {
var vectors = [
[1, 0],
[-1, 0],
[0, -1],
[0, 1]
];
function Direction(value) {
this.value = value;
}
Direction.prototype.toVector = function () {
return vectors[this.value];
};
return {
UP: new Direction(2),
DOWN: new Direction(3),
RIGHT: new...