우로 보로스는 이번 주에 디자인 한에 솔랑입니다. 스핀 할 시간입니다!
i.1+!57*(\m1(M\1).96>.@32*-.80=\.78=3*\.66=3*\.82=5*\81=9*++++\2*1\-*+
)L!4*(4Sn1(
단일 문자 명령 1 의 각 줄은 우로 보로스 스네이크를 나타내며, 실행은 헤드 (시작)에서 테일 (끝)까지 진행하고 헤드로 다시 루프됩니다. (
및 )
명령에 따라서 명령이 실행 얻을 무엇을 변경, 당신은 꼬리의 일부를 먹거나을 역류 할 수 있습니다. 명령 포인터를 삼킨 경우 뱀이 죽습니다 (실행 중지). Ouroboros 프로그램은 동시에 실행되는 하나 이상의 뱀으로 구성됩니다. 각 뱀에는 자체 스택이 있으며 공유 스택도 있습니다.
1 Ouroboros를 여러 2D 언어와 구별하는 한 가지 예외 : 수학을하거나 0을 먼저 누르지 않고도 여러 자리 숫자를 간단하게 작성할 수 있습니다.
뱀 1
첫 번째 뱀은 문자 ( i
)를 읽고 -1 / EOF ( .1+!
) 인지 확인합니다 . 그렇다면 꼬리의 대부분을 M
( 57*(
) 까지 포함하여 먹습니다 .
그런 다음 뱀은 문자 코드를 스택 위에있는 탈리와 바꾸고 ( \
), 탈리를 공유 스택으로 옮기고 ( m
) 다른 캐릭터를 삼킨다 ( 1(
). 이미 묶음을 삼킨 경우 (
IP가 현재 켜져 있고 죽었다는 것을 삼킨다는 의미 입니다. 그렇지 않으면, 탈리를 뱀 1의 스택으로 다시 옮기고, 그것을 문자 코드와 교체하고, 이전에 삼킨 캐릭터를 역류시킴으로써 실행이 진행됩니다 ( M\1)
).
그런 다음 수학 및 스택 연산을 사용하여 캐릭터에 적절한 점수를 생성합니다. .96>
소문자인지 테스트합니다. 후속 32*-
은 대문자로 변환됩니다. 그런 다음에서 먼 장래 .80=
에 81=9*++++
지도 P
-> 1
, N
-> 3
, 등 마지막으로, \2*1\-*
문자가 소문자로 된 경우 점수를 부정하고, +
실행 집계에 추가합니다. 그런 다음 뱀은 반복해서 다른 문자를 읽습니다.
뱀 2
두 번째 뱀은 역류 작업 ( )
)으로 시작합니다.이 작업 은 처음으로 아무것도 수행하지 않습니다 (아무것도 삼키지 않았고 빈 스택을 터뜨리기 때문에 0
). 그런 다음 공유 스택의 길이를 자체 스택으로 푸시하고 논리적으로 무효화합니다 ( L!
). 1
스택이 비어 있으면 제공 합니다 0
. 뱀은 4를 곱하고 많은 문자를 먹는다 ( 4*(
).
공유 스택이 비어 있으면 뱀이 이제 S
. 그것은 방금 삼킨 캐릭터들을 역류시키고 다시 시작하는 곳으로 밀고 4
되돌아 간다 )
.
그러나 공유 스택에 값이 있으면 문자가 삼키지 않고 실행이 계속됩니다. 뱀은 공유 스택으로 전환하여 숫자를 출력합니다 ( Sn
). 그런 다음 마지막 특성을 삼키고 죽습니다 ( 1(
).
동기화
두 뱀은 입력이 끝날 때까지 뱀 2가 점검 할 때 공유 스택에 값이 없도록주의해서 동기화해야합니다. 스네이크 1은 루프를 통과 할 때마다 공유 스택에 값을 간단히 넣습니다. 따라서 뱀 2의 L
명령은 뱀 1의 명령 m
과 M
명령 사이에서 실행되어서는 안됩니다 . 다행히도 뱀은 아주 잘 정렬되어 있습니다. 결정적으로 뱀 1의 루프 길이 (70 명령어)는 뱀 2의 루프 배수 (7 명령어)이므로 두 개는 동기화되지 않습니다.
i.1+!57*(\m1(M\1).96>.@32*-.80=\.78=3*\.66=3*\.82=5*\81=9*++++\2*1\-*+
)L!5*(5)L!5*(5)L!5*(5)L!5*(5)L!5*(5)L!5*(5)L!5*(5)L!5*(5)L!5*(5)L!5*(5
|__|
Danger zone
숫자가 그렇게 완벽하게 해결되지 않았다면, 필요에 따라 정렬하기 위해 하나 또는 두 개의 뱀을 공백으로 채웠을 것입니다.
이 모든 것이 매우 좋지만 실제로 작동하고 싶습니다!
다음은 Stack Snippet을 통한 위의 프로그램입니다. 초당 1000 회 작동하더라도 샘플 입력에 대한 답변을 추출하는 데 약 10 초가 걸리지 만 도달합니다!
// Define Stack class
function Stack() {
this.stack = [];
this.length = 0;
}
Stack.prototype.push = function(item) {
this.stack.push(item);
this.length++;
}
Stack.prototype.pop = function() {
var result = 0;
if (this.length > 0) {
result = this.stack.pop();
this.length--;
}
return result;
}
Stack.prototype.top = function() {
var result = 0;
if (this.length > 0) {
result = this.stack[this.length - 1];
}
return result;
}
Stack.prototype.toString = function() {
return "" + this.stack;
}
// Define Snake class
function Snake(code) {
this.code = code;
this.length = this.code.length;
this.ip = 0;
this.ownStack = new Stack();
this.currStack = this.ownStack;
this.alive = true;
this.wait = 0;
this.partialString = this.partialNumber = null;
}
Snake.prototype.step = function() {
if (!this.alive) {
return null;
}
if (this.wait > 0) {
this.wait--;
return null;
}
var instruction = this.code.charAt(this.ip);
var output = null;
if (this.partialString !== null) {
// We're in the middle of a double-quoted string
if (instruction == '"') {
// Close the string and push its character codes in reverse order
for (var i = this.partialString.length - 1; i >= 0; i--) {
this.currStack.push(this.partialString.charCodeAt(i));
}
this.partialString = null;
} else {
this.partialString += instruction;
}
} else if (instruction == '"') {
this.partialString = "";
} else if ("0" <= instruction && instruction <= "9") {
if (this.partialNumber !== null) {
this.partialNumber = this.partialNumber + instruction; // NB: concatenation!
} else {
this.partialNumber = instruction;
}
next = this.code.charAt((this.ip + 1) % this.length);
if (next < "0" || "9" < next) {
// Next instruction is non-numeric, so end number and push it
this.currStack.push(+this.partialNumber);
this.partialNumber = null;
}
} else if ("a" <= instruction && instruction <= "f") {
// a-f push numbers 10 through 15
var value = instruction.charCodeAt(0) - 87;
this.currStack.push(value);
} else if (instruction == "$") {
// Toggle the current stack
if (this.currStack === this.ownStack) {
this.currStack = this.program.sharedStack;
} else {
this.currStack = this.ownStack;
}
} else if (instruction == "s") {
this.currStack = this.ownStack;
} else if (instruction == "S") {
this.currStack = this.program.sharedStack;
} else if (instruction == "l") {
this.currStack.push(this.ownStack.length);
} else if (instruction == "L") {
this.currStack.push(this.program.sharedStack.length);
} else if (instruction == ".") {
var item = this.currStack.pop();
this.currStack.push(item);
this.currStack.push(item);
} else if (instruction == "m") {
var item = this.ownStack.pop();
this.program.sharedStack.push(item);
} else if (instruction == "M") {
var item = this.program.sharedStack.pop();
this.ownStack.push(item);
} else if (instruction == "y") {
var item = this.ownStack.top();
this.program.sharedStack.push(item);
} else if (instruction == "Y") {
var item = this.program.sharedStack.top();
this.ownStack.push(item);
} else if (instruction == "\\") {
var top = this.currStack.pop();
var next = this.currStack.pop()
this.currStack.push(top);
this.currStack.push(next);
} else if (instruction == "@") {
var c = this.currStack.pop();
var b = this.currStack.pop();
var a = this.currStack.pop();
this.currStack.push(c);
this.currStack.push(a);
this.currStack.push(b);
} else if (instruction == ";") {
this.currStack.pop();
} else if (instruction == "+") {
var b = this.currStack.pop();
var a = this.currStack.pop();
this.currStack.push(a + b);
} else if (instruction == "-") {
var b = this.currStack.pop();
var a = this.currStack.pop();
this.currStack.push(a - b);
} else if (instruction == "*") {
var b = this.currStack.pop();
var a = this.currStack.pop();
this.currStack.push(a * b);
} else if (instruction == "/") {
var b = this.currStack.pop();
var a = this.currStack.pop();
this.currStack.push(a / b);
} else if (instruction == "%") {
var b = this.currStack.pop();
var a = this.currStack.pop();
this.currStack.push(a % b);
} else if (instruction == "_") {
this.currStack.push(-this.currStack.pop());
} else if (instruction == "I") {
var value = this.currStack.pop();
if (value < 0) {
this.currStack.push(Math.ceil(value));
} else {
this.currStack.push(Math.floor(value));
}
} else if (instruction == ">") {
var b = this.currStack.pop();
var a = this.currStack.pop();
this.currStack.push(+(a > b));
} else if (instruction == "<") {
var b = this.currStack.pop();
var a = this.currStack.pop();
this.currStack.push(+(a < b));
} else if (instruction == "=") {
var b = this.currStack.pop();
var a = this.currStack.pop();
this.currStack.push(+(a == b));
} else if (instruction == "!") {
this.currStack.push(+!this.currStack.pop());
} else if (instruction == "?") {
this.currStack.push(Math.random());
} else if (instruction == "n") {
output = "" + this.currStack.pop();
} else if (instruction == "o") {
output = String.fromCharCode(this.currStack.pop());
} else if (instruction == "r") {
var input = this.program.io.getNumber();
this.currStack.push(input);
} else if (instruction == "i") {
var input = this.program.io.getChar();
this.currStack.push(input);
} else if (instruction == "(") {
this.length -= Math.floor(this.currStack.pop());
this.length = Math.max(this.length, 0);
} else if (instruction == ")") {
this.length += Math.floor(this.currStack.pop());
this.length = Math.min(this.length, this.code.length);
} else if (instruction == "w") {
this.wait = this.currStack.pop();
}
// Any instruction not covered by the above cases is ignored
if (this.ip >= this.length) {
// We've swallowed the IP, so this snake dies
this.alive = false;
this.program.snakesLiving--;
} else {
// Increment IP and loop if appropriate
this.ip = (this.ip + 1) % this.length;
}
return output;
}
// Define Program class
function Program(source, speed, io) {
this.sharedStack = new Stack();
this.snakes = source.split(/\r?\n/).map(function(snakeCode) {
var snake = new Snake(snakeCode);
snake.program = this;
snake.sharedStack = this.sharedStack;
return snake;
}.bind(this));
this.snakesLiving = this.snakes.length;
this.io = io;
this.speed = speed || 10;
this.halting = false;
}
Program.prototype.run = function() {
if (this.snakesLiving) {
this.step();
this.timeout = window.setTimeout(this.run.bind(this), 1000 / this.speed);
}
}
Program.prototype.step = function() {
for (var s = 0; s < this.snakes.length; s++) {
var output = this.snakes[s].step();
if (output) {
this.io.print(output);
}
}
}
Program.prototype.halt = function() {
window.clearTimeout(this.timeout);
}
var ioFunctions = {
print: function(item) {
var stdout = document.getElementById('stdout');
stdout.value += "" + item;
},
getChar: function() {
if (inputData) {
var inputChar = inputData[0];
inputData = inputData.slice(1);
return inputChar.charCodeAt(0);
} else {
return -1;
}
},
getNumber: function() {
while (inputData && (inputData[0] < "0" || "9" < inputData[0])) {
inputData = inputData.slice(1);
}
if (inputData) {
var inputNumber = inputData.match(/\d+/)[0];
inputData = inputData.slice(inputNumber.length);
return +inputNumber;
} else {
return -1;
}
}
};
var program = null;
var inputData = null;
function resetProgram() {
var stdout = document.getElementById('stdout');
stdout.value = null;
if (program !== null) {
program.halt();
}
program = null;
inputData = null;
}
function initProgram() {
var source = document.getElementById('source'),
stepsPerSecond = document.getElementById('steps-per-second'),
stdin = document.getElementById('stdin');
program = new Program(source.value, +stepsPerSecond.innerHTML, ioFunctions);
inputData = stdin.value;
}
function runBtnClick() {
if (program === null || program.snakesLiving == 0) {
resetProgram();
initProgram();
} else {
program.halt();
var stepsPerSecond = document.getElementById('steps-per-second');
program.speed = +stepsPerSecond.innerHTML;
}
program.run();
}
function stepBtnClick() {
if (program === null) {
initProgram();
} else {
program.halt();
}
program.step();
}
.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;
}
h1 {
text-align: center;
font-family: Georgia, 'Times New Roman', serif;
}
a {
text-decoration: none;
}
input,
textarea {
box-sizing: border-box;
}
textarea {
display: block;
white-space: pre;
overflow: auto;
height: 40px;
width: 100%;
max-width: 100%;
min-height: 25px;
}
span[contenteditable] {
padding: 2px 6px;
background: #cc7801;
color: #fff;
}
#stdout-container,
#stdin-container {
height: auto;
padding: 6px 0;
}
#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;
}
<!--
Designed and written 2015 by D. Loscutoff
Much of the HTML and CSS was taken from this Befunge interpreter by Ingo Bürk: http://codegolf.stackexchange.com/a/40331/16766
-->
<div class="container">
<textarea id="source" placeholder="Enter your program here" wrap="off">i.1+!57*(\m1(M\1).96>.@32*-.80=\.78=3*\.66=3*\.82=5*\81=9*++++\2*1\-*+
)L!4*(4Sn1(</textarea>
<div id="source-display-wrapper">
<div id="source-display"></div>
</div>
</div>
<div id="stdin-container" class="container">
<textarea id="stdin" placeholder="Input" wrap="off">5k2/ppp5/4P3/3R3p/6P1/1K2Nr2/PP3P2/8</textarea>
</div>
<div id="controls-container" class="container clearfix">
<input type="button" id="run" class="control so-box" value="Run" onclick="runBtnClick()" />
<input type="button" id="pause" class="control so-box" value="Pause" onclick="program.halt()" />
<input type="button" id="step" class="control so-box" value="Step" onclick="stepBtnClick()" />
<input type="button" id="reset" class="control so-box" value="Reset" onclick="resetProgram()" />
</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 Second: <span id="steps-per-second" contenteditable>1000</span>
</div>
</div>