<>(()){<>((([][][][][])<(((({}){})(({})({}))[])({}(({})({}({})({}{}(<>)))))[])>{()<{}>}{})<{{}}{}>())}{}<>(<(({()(((<>))<>)}{}{<({}(([][][])((({})({}))[]{})){})>((){[]<({}{})((){[]<({}{}<>((({})({})){}{}){})(<>)>}{}){{}{}<>(<({}{}())>)(<>)}>}{}){(<{}{}{}((<>))<>>)}{}}<>)<{({}[]<({}<>)<>{(<{}>)<>{<>({}[])}{}<>({}<>)(<>)}{}>)}{}<>>)>)<>{(({}[])(){(<{}>)<><(({})[])>[][][][]{()()()()(<{}>)}{}<>}{}<>)<>}<>{}{(({})<({()<<>({}<>)>}{})>([]))((){[](<(({}()()(<>))()()()){(<{}>)<>}>)}{}<>){{}((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[](<{}<>{({}<>)<>}{}(({}))({<{}({}<>)<>>{}(<<>({}[]<>)>)}<><{({}<>)<>}>{})>)}{}){{}{}(<([])>)}>}{}){{}<>{({}<>)<>}{}((({})())<{({}[]<({}<>)<>>)}>{}){({}[]<><({}<><({()<({}[]<({}<>)<>>)>}{}<>)><>)<>({()<({}[]<({}<>)<>>)>}{}<>)>)}<>(<{({}<>)<>}>)}>}{}){{}{}(<(())>)}>}{}){(<{}{}>)<>{({}<>)<>}{}(({}))({<{}({}<>)<>>({})(<<>({}<>)>)}<><{({}<>)<>}>){{}([][][])<>(((<{}>)<>))}}>}{}){{}(<([{}])>)}>}{}){{}((<{}>))}>}{}){{}(({})(<()>)<<>{({}<>)<>}{}({}()<>)<>>)<>(<({}<>)>)<>{({}<>)<>}}{}(<({}<({}<>)<>>{})<>({}<>)>)<>(<({}())>)}{}({}<{({}[]<({}<>)<>>)}{}>){((({}[]<>){(<{}({}<>)>)}{}())<{({}()<({}<>)<>(({})[])>{[][](<{}>)}{})}{}>()){{}(<>)}}{}}{}{({}[]<[{}]>)}{}{({}[]<{}>)}{}
Provalo online!
+4 byte dalla correzione di un bug con la condizione in {...}
monade e -36 byte da vari golf.
1238 byte di codice, +1 byte per il -a
flag (che può essere combinato con il flag di lingua).
Questo ora valuta {...}
zero secondo la specifica della sfida. Nota che Brain-Flak stesso ha valutato {...}
la somma di tutte le esecuzioni dal bugfix del 7 maggio 2016 due giorni prima che questa sfida fosse pubblicata.
Il codice seguente interpreta Brain-Flak Classic correttamente, con {...}
la somma di tutte le esecuzioni. L'unica differenza tra i due interpreti è il posizionamento di un {}
nilad.
<>(()){<>((([][][][][])<(((({}){})(({})({}))[])({}(({})({}({})({}{}(<>)))))[])>{()<{}>}{})<{{}}{}>())}{}<>(<(({()(((<>))<>)}{}{<({}(([][][])((({})({}))[]{})){})>((){[]<({}{})((){[]<({}{}<>((({})({})){}{}){})(<>)>}{}){{}{}<>(<({}{}())>)(<>)}>}{}){(<{}{}{}((<>))<>>)}{}}<>)<{({}[]<({}<>)<>{(<{}>)<>{<>({}[])}{}<>({}<>)(<>)}{}>)}{}<>>)>)<>{(({}[])(){(<{}>)<><(({})[])>[][][][]{()()()()(<{}>)}{}<>}{}<>)<>}<>{}{(({})<({()<<>({}<>)>}{})>([]))((){[](<(({}()()(<>))()()()){(<{}>)<>}>)}{}<>){{}((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[]<({}())((){[](<{}<>{({}<>)<>}{}(({}))({<{}({}<>)<>>{}(<<>({}[]<>)>)}<><{({}<>)<>}>{})>)}{}){{}{}(<([])>)}>}{}){{}<>{({}<>)<>}{}((({})())<{({}[]<({}<>)<>>)}>{}){({}[]<><({}<><({()<({}[]<({}<>)<>>)>}{}<>)><>)<>({()<({}[]<({}<>)<>>)>}{}<>)>)}<>(<{({}<>)<>}>)}>}{}){{}{}(<(())>)}>}{}){(<{}>)<>{({}<>)<>}{}(({}))({<{}({}<>)<>>({})(<<>({}<>)>)}<><{({}<>)<>}>{}){{}([][][])<>(((<{}>)<>))}}>}{}){{}(<([{}])>)}>}{}){{}((<{}>))}>}{}){{}(({})(<()>)<<>{({}<>)<>}{}({}()<>)<>>)<>(<({}<>)>)<>{({}<>)<>}}{}(<({}<({}<>)<>>{})<>({}<>)>)<>(<({}())>)}{}({}<{({}[]<({}<>)<>>)}{}>){((({}[]<>){(<{}({}<>)>)}{}())<{({}()<({}<>)<>(({})[])>{[][](<{}>)}{})}{}>()){{}(<>)}}{}}{}{({}[]<[{}]>)}{}{({}[]<{}>)}{}
Provalo online!
L'input (per entrambi gli interpreti) è il programma Brain-Flak Classic da interpretare, quindi una nuova riga, quindi un elenco di numeri interi separati da spazi. Non viene eseguita alcuna convalida sull'input. La nuova riga è necessaria, anche se il programma o l'input sono vuoti.
Il primo passo è analizzare tutto l'input, iniziando dalle parentesi:
# Move to right stack, and push 1 to allow loop to start
<>(())
{
# While keeping -5 on third stack:
<>((([][][][][])<
# Pop bracket or newline k from left stack, and push 0, k-10, k-40, k-60, k-91, k-123 on right stack
(((({}){})(({})({}))[])({}(({})({}({})({}{}(<>)))))[])
# Search this list for a zero, and push the number of nonzero entries popped minus 5
# (thus replacing the 0 if it was destroyed)
>{()<{}>}{})
# Remove rest of list, and push the same number plus 1
# Result is -4 for {, -3 for [, -2 for <, -1 for (, 0 for newline, or 1 for everything else (assumed closing bracket)
<{{}}{}>())
# Repeat until newline found
}{}<>
Quindi vengono analizzati gli interi. Questo non sarebbe normalmente necessario, ma l'input è stato preso come ASCII. Questo ha un rivestimento d'argento, tuttavia: l'immissione di testo ci consente di determinare l'altezza della pila, il che semplifica le cose quando non abbiamo accesso all'altezza della pila nilad.
I numeri interi vengono analizzati in due numeri nel secondo stack: uno per il valore assoluto e uno per il segno. Questi vengono quindi riportati al primo stack.
Le pile interpretate vengono memorizzate al di sotto del codice nel primo ordine nel seguente ordine: altezza dello stack corrente, stack corrente, altra altezza dello stack, altro stack. A questo punto non è necessario spingere lo 0 per l'altra altezza dello stack, poiché sarà uno zero implicito la prima volta che viene letto.
(<((
# If stack nonempty, register first stack entry.
{()(((<>))<>)}{}
# For each byte k of input:
{
# Push -3, -13, and k-32
<({}(([][][])((({})({}))[]{})){})>
# Evaluate to 1 if space
# If not space (32):
((){[]<
# If not minus (45):
({}{})((){[]<
# Replace top of right stack (n) with 10*n + (k-48)
({}{}<>((({})({})){}{}){})(<>)
# Else (i.e., if minus):
>}{}){
# Remove excess "else" entry and -3
{}{}
# Set sign to negative (and destroy magnitude that shouldn't even be there yet)
<>(<({}{}())>)(<>)}
# Else (i.e., if space):
>}{}){
# Remove working data for byte, and push two more 0s onto right stack
(<{}{}{}((<>))<>>)
# Push number of integers found
}{}}<>)
# For each integer:
<{({}[]<
# Move magnitude back to left stack
({}<>)<>
# If sign is negative, negate
{(<{}>)<>{<>({}[])}{}<>({}<>)(<>)}{}
>)}{}
# Push stack height onto stack
<>>)
# Push 0
>)
La rappresentazione del codice viene ora spostata di nuovo nello stack di sinistra. Per facilitare le cose in seguito, sottraggiamo 4 dalle parentesi di apertura di nilad, in modo che ogni operazione abbia un numero intero univoco compreso tra -1 e -8.
# For each bracket in the code:
<>{
# Push k-1 and evaluate to k
(({}[])()
# If not closing bracket:
{
# Check next bracket (previously checked, since we started at the end here)
(<{}>)<><(({})[])>
# Subtract 4 if next bracket is closing bracket
# Inverting this condition would save 8 bytes here, but cost 12 bytes later.
[][][][]{()()()()(<{}>)}{}
<>}{}
# Push result onto left stack
<>)
<>}<>{}
La parte principale del programma è in realtà l'interpretazione delle istruzioni. All'inizio di ogni iterazione del ciclo principale, l'istruzione corrente si trova nella parte superiore dello stack di sinistra, tutto ciò che segue è sotto di esso nello stesso stack e tutto ciò che è prima di esso è nello stack di destra. Tendo a visualizzarlo come se avesse un libro aperto su una determinata pagina.
{
(
# Get current instruction
({})
# Move all code to left stack, and track the current position in code
<({()<<>({}<>)>}{})>
# Push -1, signifying that the code will move forward to just before a matching }.
# In most cases, this will become 0 (do nothing special) before it is acted upon
([])
# Push instruction minus 1
)
# If opening bracket:
((){[](<
# Push instruction+1 and instruction+4
(({}()()(<>))()()())
# If instruction+4 is nonzero (not loop monad), replace the earlier -1 with 0 to cancel forward seek
# This would be clearer as {(<{}>)<>(<{}>)<>}, but that would be unnecessarily verbose
{(<{}>)<>}
# Else (i.e., if closing bracket):
>)}{}<>){
# If closing bracket, parse command
# Post-condition for all: if not moving to {, pop two and push evaluation, 0.
# (For nilads, can assume second from top is 0.)
# If moving to {, pop one, push -3, 0, 0.
# Seven nested if/else statements, corresponding to eight possible instruction.
# The "else" statements end with 0 already on the stack, so no need to push a 0 except in the innermost if.
# Each one beyond the first increments the instruction by 1 to compare the result with 0
# Each instruction will pop the instruction, leaving only its evaluation (with a 0 on top).
{}((){[]<
({}())((){[]<
({}())((){[]<
({}())((){[]<
({}())((){[]<
({}())((){[]<
({}())((){[](<
# -7: pop
# Pop instruction to reveal existing 0 evaluation
{}
# Move code out of the way to access stack
<>{({}<>)<>}{}
# Duplicate stack height (only useful if stack height is zero)
(({}))
(
# If stack height nonzero
{
# Save stack height on second stack
<{}({}<>)<>>
# Pop stack
{}
# Move stack height back and subtract 1
(<<>({}[]<>)>)
}
# Move code back to normal position
<><{({}<>)<>}>{}
# Evaluate as popped entry (0 if nothing popped)
)
# (else)
>)}{}){
# -6: -1 nilad
# Just evaluate as -1
{}{}(<([])>)
# (else)
}>}{}){
# -5: swap nilad
# Move code out of the way to access stack
{}<>{({}<>)<>}{}
# Number of integers to move: stack height + 1 (namely, the stack height and every entry in the stack)
((({})())
# Move to second stack
<{({}[]<({}<>)<>>)}>{}
# Do (stack height + 1) times again
){({}[]<><
# Get stack element
({}<><
# Move alternate (interpreted) stack to second (real) stack, and push length on top of it
({()<({}[]<({}<>)<>>)>}{}<>)
# Push current stack element below alternate stack
><>)
# Move alternate stack back above newly pushed element
<>({()<({}[]<({}<>)<>>)>}{}<>)
>)}
# Move code back to normal position
<>(<{({}<>)<>}>)
# (else)
}>}{}){
# -4: 1
# Just evaluate to 1
{}{}(<(())>)
# (else)
}>}{}){
# -3: loop
# Create zero on stack while keeping existing evaluation
# This becomes (<{}{}>) in the version that meets the challenge spec
(<{}>)
# Move code out of the way to access stack
<>{({}<>)<>}{}
# Duplicate stack height
(({}))
(
# If stack height nonzero
{
# Save stack height on second stack
<{}({}<>)<>>
# Peek at top of stack
({})
# Move stack height back
(<<>({}<>)>)
}
# Move code back to normal position
<><{({}<>)<>}>
# Look at peeked entry
# Remove the {} in the version meeting the challenge spec
{})
# If peeked entry is nonzero
{
# Replace -3 instruction on third stack
{}([][][])
# Replace loop indicator to 0 (to be incremented later to 1)
<>(((<{}>)
# Create dummy third stack entry to pop
<>))
}
# (else)
}>}{}){
# -2: print
# Just print evaluation without modifying it
{}(<([{}])>)
# (else)
}>}{}){
# -1: evaluate as zero
# Just change evaluation to 0
{}((<{}>))
# else
}>}{}){
# 0: push
# Get current evaluation (without modifying it)
{}(({})
# Create zero on stack as barrier
(<()>)
# Move code out of the way to access stack
<<>{({}<>)<>}{}
# Increment stack height and save on other stack
({}()<>)<>
# Push evaluation
>)
# Move stack height back (and push zero)
<>(<({}<>)>)
# Move code back to normal position
<>{({}<>)<>}
}{}
# Update third stack by adding evaluation to previous entry's evaluation
# Previous entry's instruction is saved temporarily on left stack
(<({}<({}<>)<>>{})<>({}<>)>)
# Increment loop indicator
# If instruction was loop monad and top of stack was nonzero, this increments 0 to 1 (search backward)
# Otherwise, this increments -1 to 0 (do nothing)
<>(<({}())>)
}{}
# While holding onto loop indicator
({}<
# Go to immediately after executed symbol
{({}[]<({}<>)<>>)}{}
>)
# If looping behavior:
{
# Switch stack and check if searching forward
((({}[]<>)
# If so:
{
# Move just-executed { back to left stack, and move with it
(<{}({}<>)>)
}{}
# Either way, we are currently looking at the just-executed bracket.
# In addition, the position we wish to move to is on the current stack.
# Push unmodified loop indicator as initial value in search
())
# While value is nonzero:
<{
# Add 1
({}()
# Move current instruction to other stack
<({}<>)<>
# Check whether next instruction is closing bracket
(({})[])>
# If opening bracket, subtract 2 from value
{[][](<{}>)}{}
)
}{}>
# If searching backward, move back to left stack
()){{}(<>)}
}{}
}
Dopo essere uscito dal ciclo principale, tutto il codice è nello stack giusto. Le uniche cose nello stack di sinistra sono uno zero e le due pile interpretate. Produrre l'output corretto è una questione semplice.
# Pop the zero
{}
# Output current stack
{({}[]<[{}]>)}{}
# Discard other stack to avoid implicit printing
{({}[]<{}>)}{}