Introdução
Forte é uma linguagem esotérica muito peculiar, baseada no conceito de modificação dos valores dos números. Em números fortes, não são constantes, mas variáveis, você pode usar a LET
instrução para atribuir novos valores a eles.
Por exemplo, depois de executar a LET 2=4-1
partir de agora 2
assume o valor de 3
, o que significa que sempre que o valor 2
aparece em uma expressão, ele é "substituído" por 3
. A expressão (1+1)*2
agora seria avaliada como 9
.
Esta instrução em Forte é usada tanto para armazenar informações quanto para controle de fluxo (as linhas são numeradas e, alterando o valor de seus números, você pode determinar a ordem de sua execução). Neste desafio, não trataremos desse segundo aspecto.
O desafio
Você precisa escrever um intérprete para um subconjunto simplificado das LET
expressões de Forte .
Você receberá como entrada uma série de linhas seguindo esta gramática:
<line>::= <number>=<expression>
<expression>::= <number>|<expression>+<number>
Nota: esta gramática não é válida Forte porque não possui números de linhas, LET e parênteses (que são sempre obrigatórios)
Ou seja, você só precisará lidar com somas de computação e atribuir valores a números. Parênteses não estarão presentes na entrada e cada expressão precisará ser avaliada da esquerda para a direita: cuidado para que resultados parciais sejam afetados por redefinições!
Os números sempre serão números inteiros não negativos, até o limite do tipo inteiro nativo do seu idioma (ou 2 ^ 32, o que for maior).
Para cada linha, você deve exibir o resultado da expressão e atribuir esse resultado ao valor (possivelmente reatribuído) do primeiro número, o que afetará como as linhas a seguir serão interpretadas.
Este é o código-golfe , o código mais curto (em bytes) vence!
Outras regras
- O formato de entrada é flexível, você pode, por exemplo, pegar uma única string com novas linhas, uma lista de strings, uma lista de listas de números ... O mesmo vale para a saída, desde que fique claro qual é o resultado de cada expressão em a entrada.
- Você pode enviar uma função, um programa completo ou uma solução para ser executada em um ambiente REPL, chamando-o uma vez para cada linha.
- As brechas padrão são proibidas, em particular você não pode chamar um intérprete externo Forte no seu código.
Exemplos
Tudo isso faz parte da mesma entrada. Após cada linha, a saída esperada em relação a essa linha é mostrada, às vezes com um comentário indicando redesignações relevantes (não parte da saída necessária).
5=4
4
6=5
4 # 5 -> 4
7=1+2+5
7
7=5+2+1
4 # Order of operations matters! 5+2 -> 4+2 -> 6 -> 4
18=5+6+7
12
5=3
3 # Remember: 5 -> 4
10=6+4
3 # 6 -> 4 -> 3, 3+3 = 6 -> 3
0
um número válido?0
é válido ("Os números sempre serão números inteiros não negativos")Respostas:
Gelatina , 28 bytes
Experimente online!
Este é um dos poucos programas Jelly em que parece mais tenso aceitar as informações padrão. É um programa completo (escrever uma função seria mais curto, mas é banido pelas regras do PPCG, porque não seria executado corretamente na segunda vez). O formato de entrada fica assim:
Explicação
Função auxiliar
1Ŀ
(converter um número inteiro para seu valor)De maneira conveniente, essa função auxiliar funcionará corretamente em um único valor ou em uma lista de valores, devido à maneira como
y
é definido. Se mais de um mapeamento for fornecido para um único valor, pegaremos o primeiro mapeamento da tabela. A tabela de mapeamento é armazenada no registro (que é basicamente apenas uma variável; o Jelly possui apenas uma variável).Função auxiliar
2Ŀ
(avalie uma instrução LET)Realmente não queremos um valor de retorno aqui; estamos apenas executando isso por seus efeitos colaterais (atualizando o registro e emitindo o valor atribuído). As funções Jelly sempre retornam um valor, portanto, apenas permitimos que a tabela de mapeamento seja retornada, pois é estressante.
Programa principal
Normalmente,
⁸
nos daria o primeiro argumento da linha de comando quando executado neste contexto, mas não há um (estamos recebendo informações da entrada padrão), portanto, ele é executado em um modo alternativo que nos fornece a cadeia nula. A necessidade de inicializar o registro (de seu valor padrão0
, que travay
) significa que não podemos mencionar implicitamente a entrada do usuário, o que significa que é tão barato retirá-lo da entrada padrão (Ɠ
) quanto seria retirá-lo de um argumento de linha de comando (³
ou⁸
) e ser capaz de acessar o uso alternativo⁸
significa que a forma incomum (para Jelly) de entrada é na verdade um byte mais curto.É possível que isso seja improvável. Ainda não entendi por que a segunda linha precisa dizer,
⁸Ǥ;
e não apenas;@Ç
- as duas devem ser equivalentes, tanto quanto eu entendo Jelly, dada a falta de uso deµ
/ð
/ø
-, mas a última falha por algum motivo. Da mesma forma, existem várias outras maneiras de reorganizar o programa sem perder bytes; portanto, é possível que eu tenha perdido uma maneira de tornar as coisas um pouco mais curtas.Aliás, alterar a
ḷ
última linha para;
fornecer uma visão interessante do funcionamento interno do programa, pois ele exibirá o "histórico do registro" que é implicitamente gerado pelos valores de retorno de2Ḷ
.fonte
Perl 5 , 92 bytes
90 bytes de código +
-pl
sinalizadores.Experimente online!
Eu uso a hashtable
%h
para armazenar o mapeamento entre números.A função (
sub
)f
retorna o número para o qual seu mapa de entrada (ou sua entrada se não estiver mapeado para nenhum número):$h{$a=pop}
recupera o número para o qual a entrada é mapeada. Se não for nenhum, graças a//$a
, o valor de($b=$h{$a=pop}//$a)
é a entrada ($a
). Garantimos que esses valores não sejam a própria entrada para não fazer um loop infinito (!=$a
). Então, chamamos recursivamentef
ou retornamos a entrada.O programa principal consiste em duas etapas:
-
s%(\d+)\+(\d+)%f($1)+f$2%e&&redo
avalia a primeira adição no lado direito, enquanto ainda há uma adição: ela substituix+y
pelo resultado da avaliação def(x)+f(y)
.-
/=/;$_=$h{f$`}=f$'
faz a tarefa:/=/
permite acessar o lado esquerdo com$`
e o lado direito com$'
, em seguida,$h{f$`}=f$'
faz a atribuição. E também atribuímos a ele$_
que é implicitamente impresso após cada linha.fonte
JavaScript (Node.js) , 81 bytes
Experimente online!
Recebe entrada chamando f com o valor a ser atribuído e, em seguida, chamando o resultado disso com uma matriz de valores para adicionar. (ie
f(5)([4])
) Repita para várias linhas.v
é usado como uma função para calcular o valor atual real de um número e também como um objeto para armazenar os valores reais. Primeirov[x]=v[x]||x
garante quev[x]
está definido.v[x]-x
realiza uma comparação para determinar se esse é o número real ou não. Se o número não for mapeado para si mesmo,v(v[x])
tente recursivamente novamente, caso contrário, retornex
.f
executa o cálculo e a atribuição, com curry para salvar um byte, onde a segunda chamada retorna o valor calculado.fonte
Haskell ,
116 113 108106 bytesExperimente online! Cada equação
4=3+1+5
é anotada como tupla(4,[3,1,5])
. A função anônima(id?)
pega uma lista dessas tuplas e retorna uma lista de todos os resultados intermediários.#
é uma função para encontrar um ponto fixo de uma determinada funçãoe
e um valor inicialx
.A função
?
assume uma função de avaliaçãoe
e resolve recursivamente cada equação.foldl1(\a b->e#(e#a+e#b))s
avalia o lado direito de uma equação e salva o resultado emm
, por exemplo, para4=3+1+5
computareval(eval(eval 3 + eval 1) + eval 5)
, onde cadaeval
um é um aplicativo de ponto de correçãoe
. Em seguida, a função eval é modificada para levar em consideração a nova atribuiçãon
:(\x->last$m:[e#x|x/=e#n])
que é a mesma que\x -> if x == eval n then m else eval x
.A função de avaliação inicial é
id
que mapeia cada número inteiro para si mesmo.Obrigado a Ørjan Johansen por uma função de ponto fixo mais curta, economizando 2 bytes!
fonte
last.
(#)e=until((==)=<<e)e
ou(#)=until=<<((==)=<<)
é mais curto.OK, 48 bytes
Uso:
f[5;1 2 3] / 5=1+2+3
Experimente online!
Se você não se importa de ter um limite superior para os números que você pode usar, como usar apenas números
0
através de998
, em seguida, os seguintes sufixos ( 41 bytes ± a poucos dependendo do máximo):Explicação:
;
separa três definições.a
é um dicionário / mapa de números. No primeiro caso, é um dicionário real e vazio[]
, no segundo caso, é uma lista dos números0
para998
.s
é uma função que encontra o número "resultante" quando recebe um número. O/
final da função significa que ela se aplicará a sua própria saída até que a saída pare de mudar.O último bit
f
, significa que:fonte
Python 3,
146132130 bytes14 bytes salvos graças a @Dada
2 bytes salvos graças a @ mbomb007
Experimente online!
Recebe entrada como tuplas de equações [
x = y + z + w
como(x, (y, z, w))
], saídas via gerador.fonte
g
provavelmente poderia ser escritog=lambda x:d.get(x)and d[x]!=x and g(d[x])or x
. E acho que você pode usar 1 espaço para recuar em vez de 2. Isso deve levá-lo a [132 bytes] ( Experimente online! ).