Uma Breve História das Linguagens de Programação 2D: 16 (+2) anos
v19977/2{@{{4{\_______>/02&&&#???? * P+++++1P1P-1P+1E * *
\'\02'oo100@n590@n; * * *
>"8991",,,;5-;,@ * * *
* * * *
\ * ++++++++++++++++++++++++ ++++++++++++++++++++++++ ++O--OO++++++++OX******* *
* #2018O@ * * * * * * *
* * * * * * * *
* * * * * * * *
* **** **** * **** **** * **** **** * **** *****
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * *
* * * **** * * * * **** * * * * **** * * * * ****
* * * * * * * * * * * * * * * *
R"2014"; ***** ******* ****** ******* ****** ******* ****** *******
x
x%"2010"x
x
$'main' \/\/\/\
\-[2005]o-# \++++++\
/++++++/
\++++++\
/++++++/
\/\/\/\++.--..+++.#
S1^2^2^6^8MAOUOAOOF
/K:0:1:@
> "7102"4&o@
| }+++++[>++++++++++<-]>.--..++++++.@
Eu mencionei que gosto de linguagens de programação 2D?
O idioma que (supostamente, consulte a última seção) iniciou tudo. No Befunge, você pode redirecionar o fluxo de controle com <v>^
, mas o agora onipresente espelha \
e /
não era uma coisa ainda. O intérprete Befunge usado no Anarchy Golf ignora comandos desconhecidos. Podemos usar isso para distinguir a família Befunge da família> <>. Portanto, o código executado pelo Befunge é o seguinte:
v
\
>"8991",,,;5-;,@
O "8991"
empurra os caracteres individuais na pilha. ,,,
imprime os três primeiros. Então ;
é desconhecido (que usaremos para diferenciá-lo do Befunge 98), 5-
transforma o 8
em a 3
e ,
imprime isso também antes de @
finalizar o programa.
Escrever essa parte da solução provavelmente levou tanto tempo quanto escrever todas as outras e encaixá-las ...
Wierd conhece apenas dois símbolos: espaço e tudo mais. O ponteiro de instruções tenta seguir o caminho formado pelos caracteres não espaciais, começando na diagonal a partir do canto superior esquerdo e sempre tentando seguir o mais reto possível. As dobras no caminho formam as instruções reais (com os graus do turno determinando qual instrução executar). Portanto, o código visto por Wierd é o seguinte:
v1997 * * *
' * * *
8 * * *
* * * *
* ++++++++++++++++++++++++ ++++++++++++++++++++++++ ++O--OO++++++++OX******* *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* **** **** * **** **** * **** **** * **** *****
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * *
* * * **** * * * * **** * * * * **** * * * * ****
* * * * * * * * * * * * * * * *
***** ******* ****** ******* ****** ******* ****** *******
Na 1997
parte superior, na verdade, não é executado, mas o Wierd nos permite lê-lo a partir do código fonte, que é muito mais curto do que tentar construir os códigos de caracteres para os quatro dígitos em si (mesmo que não pareça. .). Eu não sinto vontade de quebrar tudo isso, mas você pode ver claramente as quatro seções repetidas. O que isso faz é que primeiro armazenemos 1
na pilha e, em seguida, cada uma dessas quatro seções a incrementa 1
e depois ramifique. O ramo inferior empurra outro1
, recupera o caractere de origem nessas coordenadas e o imprime, enquanto a ramificação superior é redirecionada para a próxima seção. Você pode se perguntar por que os finais dos caminhos são desnecessariamente longos, mas isso ocorre quando o Wierd atinge o final de um caminho e tenta pular para um caminho próximo antes de decidir que deve encerrar a ramificação atual. Para evitar isso, precisamos mover essas extremidades suficientemente longe de qualquer outro código.
Befunge recebeu uma atualização bastante conhecida em 1998 com uma especificação muito rigorosa que pode ser generalizada para dimensões arbitrárias (e acho que também topologias arbitrárias). É amplamente compatível com o Befunge, o que facilita bastante a poliglota dos dois. Como o Befunge ainda não tinha espelhos, o caminho executado é o mesmo do Befunge 93:
v
\
>"8991",,,;5-;,@
A diferença é que o Befunge 98 não ignora o ;
. Em vez disso, age como um comentário, em que todos os comandos até o próximo ;
são ignorados. Desta forma, nós não diminuir que 8
a 3
e imprimir o 1998
como é.
2001: Um Espaço Od ... PingPong
2001 é o ano de Piet, mas eu realmente não estava com vontade de poliglotar um arquivo de imagem com todos os outros programas, então aqui está uma linguagem 2D menos conhecida. Parece ter muitos recursos (que não vamos usar). Agradecemos ao Sp3000 por encontrar o intérprete original (que é o único link morto na versão arquivada do site oficial).
O PingPong é um tanto incomum, pois possui apenas espelhos e nenhum <v>^
redirecionador. Então isso se move através do v19977
início e depois atinge o espelho que o envolve até o fundo. O código relevante é então:
v19977/
...
/K:0:1:@
...
O código atual é bastante simples: K
pressiona 20
, os dígitos se pressionam, :
imprimem um número inteiro e @
finalizam o programa.
Este é o primeiro idioma em que as coisas ficam um pouco mais fáceis, porque o SNUSP suporta um ponto de entrada explícito. Esse ponto de entrada é marcado por $
. A julgar por alguns artigos sobre esolangs, essa linguagem inspirou vários outros, mas, infelizmente, no final do dia, é apenas um derivado do Brainfuck. Dito isto, acho que a maneira como isso define a célula atual para 48 é bastante clara (e foi roubada do artigo da esolangs). Aqui está a parte relevante do código:
$'main' \/\/\/\
\++++++\
/++++++/
\++++++\
/++++++/
\/\/\/\++.--..+++.#
São 24 +
segundos e os espelhos enviam o IP através de cada um exatamente duas vezes.
Por alguma razão, essa linguagem não têm os <^>
redirecionadores mas em vez dos habituais v
ele usa %
. Portanto, isso apenas se move pela primeira linha. O código relevante é:
v19977/2{@{{4{\
Nós pressionamos alguns dígitos para começar, realizamos uma divisão. Em seguida, 2{
imprime o 2
, @
limpa a pilha. {{
imprime dois (implícitos) 0
s. 4{
imprime 4
e \
finaliza o programa.
2005 foi uma escolha difícil. Em nenhum outro ano eu encontrei tantas linguagens 2D, e há ADJUST e Archway, as quais começam no canto inferior esquerdo (o que as tornaria adições fáceis). Mas eu gosto do Rail e, como ele tem um ponto de entrada explícito, também não foi difícil de adicionar. O Rail procura um início de linha $'main'
e começa a se mover a sudeste a partir do $
. Isso significa que o código relevante é:
$'main'
\-[2005]o-#
As \
e -
são apenas faixas (no-ops). O [2005]
é uma string literal que é o
impressa antes de #
finalizar o programa.
Um Brainfuck bidimensional. Há outra linguagem interessante para este ano chamada Black, que começa na coordenada (3,3)
(com base em 1) que também tornaria interessante o uso em poliglotas. Não consegui encontrar um intérprete. Então, teremos que trabalhar com outro derivado de BF ...
O interessante sobre este é que ele não formata a grade em linhas com feeds de linha como a maioria das outras linguagens 2D. Em vez disso, |
é usado como o separador de linhas. Como não usei |
em nenhum outro idioma, eu poderia simplesmente colocar um |
na última linha, o que torna o resto do programa uma única linha no que diz respeito ao BF.js. O código relevante é este (transformando |
em um avanço de linha real):
v19977/2{...
}+++++[>++++++++++<-]>.--..++++++.@
O BF.js não usa <v>^
nem espelhos. As únicas maneiras de redirecionar o fluxo de controle são com as {}
quais gire a direção do IP em 90 °. Portanto, esses aparelhos movem o IP para a segunda linha. O restante é uma solução simples da Brainfuck (não particularmente bem treinada) que define uma célula para 50
(código do ponto 2
) e depois imprime 2006
deslocando o valor um pouco. @
finaliza o programa.
Para este ano, eu realmente queria usar o DOBELA, que usa vários pontos de entrada e se parece com o lovechild de Fission e Ziim . Infelizmente, não consegui fazer o intérprete funcionar. Então, aqui está outro derivado de BF (o último, prometo).
Ao contrário do último, este conhece os dois <v>^
e os espelhos, portanto, o código relevante é:
v
\'\
8
\ * ++++++++++++++++++++++++ ++++++++++++++++++++++++ ++O--OO++++++++OX
Este não possui o []
loop de estilo BF usual (em vez disso, você precisaria formar um loop 2D real), então eu decidi codificar o código uma 50
vez que eu tinha uma tonelada de caracteres seguidos do Wierd de qualquer maneira. Observe que o '
e 8
são ignorados, o *
é um trampolim condicional que podemos ignorar e o do O
Brainfuck .
. O X
finaliza o programa.
Provavelmente o Fungeoid mais popular (além do próprio Befunge) pelo menos nessas partes. > <> possui dois <v>^
e espelhos, mas também literais de string, portanto, o código executado é este:
v
\'\02'oo100@n590@n;
A string literal serve principalmente para pular a \
que usamos para o BrainSpace 1.0, mas enquanto estamos nisso, é melhor empurrar os dois primeiros caracteres. oo
os imprime. Em seguida, 100
pressiona três dígitos, @
empurra o de cima para baixo e n
imprime o de 0
baixo. Fazemos a mesma coisa novamente com a 590
qual imprime o arquivo 9
. Se você está se perguntando por que não estou imprimindo 2009
como está, aguarde 2015. ;
finaliza o programa.
Este foi simples, porque tem um ponto de entrada explícito em %
. No entanto, este cria 4 IPs em todas as direções (daí o nome do idioma, suponho), e precisamos nos livrar de 3 deles. Aqui está o código relevante:
x
x%"2010"x
x
Bem, sim. (No Cardinal, o modo de seqüência de caracteres é impresso diretamente em vez de colocar os caracteres em uma pilha.)
Outro idioma com um ponto de entrada explícito (de David Catt, que criou alguns outros esolangs muito legais), desta vez em S
. Isso torna o código relevante nesta parte:
S1^2^2^6^8MAOUOAOOF
RunR é um pouco interessante porque a maioria das operações funciona com uma espécie de registro e os valores precisam ser movidos para a pilha explicitamente para operações binárias. Os dígitos definem os valores do registro para si mesmos e ^
empurram o registro atual para a pilha. Então M
é a multiplicação (o valor dos tempos de registro saltou da pilha), U
é a subtração, a A
adição e a O
saída. F
finaliza o programa.
Como o Wierd, o Ropy tenta seguir seções de caracteres não espaciais, mas aqui as dobras não determinam os comandos. De fato, acontece que o Ropy é mais parecido com o meu próprio labirinto , pois a direção escolhida depende do topo da pilha. No entanto, não precisamos nos preocupar com isso aqui, porque o Ropy apenas se move na primeira linha:
v19977/2{@{{4{\_______>/02&&&#????
Há muitas coisas que podemos ignorar até o >
. Tudo o que precisamos saber é que o topo da pilha será nesse ponto a 4
e haverá 2
abaixo.
>
duplica a 4
, /
é a divisão transformando-o em um 1
. Então nós empurramos 02
. &&&
une os quatro primeiros números da pilha na ordem inversa, dando 2012
. #
gera isso. ????
apenas limpa a pilha porque, caso contrário, a parte superior da pilha também é impressa.
Um ponto de interesse é que o segundo 7
em 19977
foi adicionado por causa da viscosa. A /
divisão no Ropy sim top / second
(oposta à ordem usual em muitos idiomas baseados em pilha), onde 7 / 9
daria 0
. Se tivéssemos um zero no topo da pilha, o Ropy faria algumas coisas selvagens com sua direção de movimento, então precisamos pressionar o outro 7
para garantir que o topo da pilha permaneça positivo e o Ropy continue se movendo para o leste.
Com seus pontos de entrada explícitos, este é fácil. RDLU
crie átomos (ponteiros de instrução) na direção correspondente; portanto, o bit relevante é exatamente isso:
R"2014";
Observe que também existe um U
no código fonte, mas esse átomo acaba atingindo um dos *
do Wierd, que finaliza o programa (e esse átomo leva muito mais tempo do que o R
necessário para imprimir 2014
).
O derivado> <> mais poderoso do Sp3000. É amplamente compatível com> <>, portanto o código executado ainda é:
v
\'\02'oo100@n590@n;
No entanto, a direção de rotação de @
foi alterada, que é o truque padrão para distinguir> <> e Gol> <> em poliglotas, portanto, este é impresso em 15
vez de 09
. Daí a estranheza na segunda metade do programa.
O CSL é bastante interessante, pois os comandos não são executados imediatamente. Em vez disso, cada comando é enviado para uma pilha de comandos e
e E
pode ser usado para executar comandos a partir dele. O código relevante se torna:
v19977/2{@{{4{\_______>/02&&&#???? * P+++++1P1P-1P+1E
Portanto, ele E
executa toda a pilha de comandos, o que significa que as coisas à sua frente são executadas ao contrário. Precisamos apenas olhar para *
:
1+P1-P1P1+++++P*
Eles 1
se empurram para a pilha de dados. +
e -
são decremento / incremento. P
imprime a parte superior da pilha. Em seguida, *
tenta multiplicar os dois principais valores da pilha. No entanto, a pilha está vazia, então isso encerra o programa.
Neste ponto, chegamos aos idiomas que foram lançados após o lançamento deste desafio, então não os estou contando para a pontuação, especialmente desde que eu os criei (mas não com esse desafio em mente). No entanto, eles têm algumas novas semânticas de movimento de IP, o que facilitou sua inserção no poliglota, além de adicionar algo interessante a essa vitrine de linguagens 2D.
Alice foi projetada para ser uma Fungeoid rica em recursos. Uma diferença interessante para a maioria das (mas não todas) outras linguagens 2D é que o IP pode se mover ortogonalmente ou diagonalmente. Alternar entre eles também altera a semântica de quase todos os comandos no idioma. Além disso, Alice suporta os <^>v
setters de direção e \/
espelhos tradicionais , mas os espelhos têm um comportamento muito único em Alice (o que facilita levar o IP da Alice a uma parte do código não utilizada até o momento).
Enquanto a maioria dos idiomas trata \
e /
como se fossem espelhos em um ângulo de 45 °, e o IP como um raio de luz refletido nele, Alice os trata como tendo um ângulo de 67,5 ° (que é mais próximo do ângulo dos glifos de barra reais) , e o IP também se move através do espelho (daí o nome do idioma). Devido a esse ângulo, os espelhos alternam entre os movimentos nas direções ortogonais ou diagonais. Além disso, enquanto no modo Ordinal (ou seja, enquanto o IP se move ao longo das diagonais), a grade não quebra e, em vez disso, o IP ricocheteia nas bordas (enquanto no modo Cardinal ele quebra).
Em suma, o código executado por Alice é o seguinte:
v19
\ \
...
> "7102"4&o@
...
O IP começa no canto superior esquerdo, como de costume, v
envia para o sul. Agora \
, o IP reflete o deslocamento para o noroeste, onde imediatamente salta da borda esquerda da grade (e se move para o nordeste). 1
pode ser ignorado, o IP ricocheteia na borda superior para avançar para o sudeste. Batemos em outro \
que reflete o norte da PI. 9
também pode ser ignorado e, em seguida, o IP passa para a parte inferior da grade. Depois de algumas linhas, o redirecionamos para o leste >
por conveniência. Em seguida, "7102"
pressiona os pontos de código do 2017
, 4&o
imprime esses quatro caracteres e @
finaliza o programa.
O Wumpus é a primeira linguagem 2D em uma grade triangular, que torna o movimento pelo código bastante diferente (e novamente nos permite alcançar facilmente uma parte não utilizada do código). Portanto, em vez de pensar em cada caractere da grade como um pequeno quadrado, pense neles como triângulos alternados para cima e para baixo. O canto superior esquerdo é sempre um triângulo para cima.
O Wumpus não tem setters de direção <^>v
, mas tem espelhos \/
. No entanto, devido à grade triangular, eles funcionam de maneira diferente da maioria dos outros idiomas. O IP é refletido neles como um raio de luz (como de costume), mas você deve pensar neles como tendo um ângulo de 60 °. Portanto, um IP que se move para leste acaba se movendo ao longo do eixo noroeste da grade.
Como outra diferença para a maioria dos outros idiomas, as bordas da grade não são quebradas, mas o IP ricocheteia nas bordas (como se essas células de borda contivessem os espelhos apropriados). Outro pequeno detalhe divertido é que as diagonais na grade triangular realmente parecem escadas no código fonte.
Com isso em mente, o código executado pelo Wumpus é o seguinte (onde eu substituí os espaços .
por uma questão de clareza:
v19977/
02
89
..
..
.....*...#2018O@
O v19977
são apenas lixo que podemos ignorar. /
envia o IP para noroeste, onde ele se move pela 977
(da direita) novamente enquanto salta pela borda superior. Em seguida, o IP se move para sudoeste através dos 2089
vários espaços, antes de atingir a borda esquerda para refletir novamente no leste. *
também é lixo. Finalmente , #2018
empurra 2018
, O
imprime e @
finaliza o programa.
Anos desaparecidos
Finalmente, algumas notas sobre anos que não cobri.
Ao pesquisar linguagens 2D para encontrar linguagens adequadas ao longo dos anos que poderiam ser usadas em uma poliglota, descobri que, ao contrário da crença popular, o Befunge não era a primeira linguagem 2D. Esse título parece pertencer à Biota, que já foi criada em 1991. Infelizmente, o idioma não tem saída, então não pude usá-lo para esse desafio.
Até onde eu sei, nenhuma linguagem 2D foi criada em 1992 e 1995. Isso deixa alguns anos que eu não cobri:
- 1994: Orthagonal foi criado, independentemente da Befunge. As linguagens são semanticamente bastante semelhantes, na verdade, mas Orthagonal não apresenta o código fonte em 2D. Em vez disso, cada linha é uma
(x, y, instruction)
tupla. Até obtive a especificação da linguagem e o intérprete original do criador Jeff Epler, mas, no final, o fato de a sintaxe não ser 2D tornou a linguagem inadequada para esse poliglota.
- 1996: Orthogonal , um sucessor de Orthagonal (criado por outra pessoa) foi criado, mas, para os propósitos deste poliglota, sofre os mesmos problemas que Orthagonal.
- 1999: A única linguagem que pude encontrar foi o autômato celular de Chris Pressey, REDGREEN . Infelizmente, ao contrário de seu antecessor RUBE, ele não parece ter nenhuma semântica de E / S.
- 2000: Há outro autômato celular do Chris Pressey chamado noit o 'mnain worb, mas ele também não possui E / S. Há também o Numberix que eu não tentei executar e não tenho certeza se ele ignoraria caracteres não-hexadecimais no código-fonte.
- 2002: Existe o Clunk sem E / S e ZT cuja especificação de linguagem me aterroriza.
- 2007: Encontrei três idiomas aqui. O Zetaplex é baseado em imagem (não é o caso) e o RubE On Conveyor Belts parece exigir um cabeçalho com um formato bastante estrito, o que prejudicaria a primeira linha do programa. Há também o Cellbrain da Quintopia, mas também parece exigir um cabeçalho específico.
- 2013: Mais uma vez, encontrei três idiomas. A pesca pode ser possível com uma boa quantidade de reestruturação, mas exigiria que o programa iniciasse com uma doca válida. Quipu , da memória, é muito rígido quanto à sua sintaxe para permitir muita poliglota. E Swordfish é outro membro da família> <>, mas infelizmente não consegui encontrar um intérprete. Caso contrário, este provavelmente seria bastante fácil de adicionar.
Se alguém estiver interessado, aqui está a lista completa das linguagens 2D implementadas, ordenadas por anos , tanto quanto pude encontrá-las (no momento em que essa resposta foi publicada). Se houver alguma falta nessa lista, entre em contato no chat, pois eu estaria realmente interessado em uma lista completa.