Cubix, 238 234 217 151 110 100 байт
Сохранено 14 байтов благодаря ETHProductions
u'^.:s+.;;;\-?W?rsos\(rrOIO:ur>'=o;^u.;;.>$.vUo^'rsu1;;@!\q?s*su;;IOu*+qU../;(*\(s.;<..r:''uq....qu\
Expanded:
u ' ^ . :
s + . ; ;
; \ - ? W
? r s o s
\ ( r r O
I O : u r > ' = o ; ^ u . ; ; . > $ . v
U o ^ ' r s u 1 ; ; @ ! \ q ? s * s u ;
; I O u * + q U . . / ; ( * \ ( s . ; <
. . r : ' ' u q . . . . q u \ . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Попробуйте онлайн!
Попробуй здесь
объяснение
Код состоит из 8 шагов, с двумя циклами. Я перейду код по частям.
Шаг 1 (A ^ B)
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
I O : u . . . . . . . . . . . . . . . .
U o ^ ' . . . . . . . . . . . . . . . .
; I O u . . . . . . / ; ( * \ . . . . .
? ? r : . . . . . . ? . . . \ ? ? ? ? ?
. . . . ? . . . . . ? . . . . . . . . .
? ? ? ? ?
. . . . .
. . . . .
. . . . .
. . . . .
Это куб с удаленными частями, которые не имеют отношения к первому шагу. На вопросительном знаке показаны запреты, которые посетит IP, чтобы сделать его путь более понятным.
IO:'^o;IO:r*(; # Explanation
I # Push the first input (A)
O # output that
: # duplicate it
'^ # Push the character "^"
o # output that
; # pop it from the stack
I # Push the second input (B)
O # output that
: # duplicate
r # rotate top 3 elements
* # Push the product of the top two elements
( # decrease it by one
; # pop it from the stack (making the last
# two operations useless, but doing it
# this way saves 10B)
Теперь стек выглядит так: A, B, A, B
Шаг 2 (подготовка к печати цикла)
Цикл печати принимает 3 аргумента (верхние 3 элементов на стеке): P
, Q
и R
. P
количество повторений, Q
разделитель (код символа) и R
число повторений. К счастью, цикл также заботится о том, что результирующая строка должна заканчиваться R
, а не Q
.
Мы хотим повторить A*
точное B
время, поэтому разделитель есть *
. Обратите внимание, что стек начинается как A, B, A, B
. Я снова удалил все ненужные инструкции. IP начинаются с S
указывающего на север.
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . r . . . . . . . . . . . . . . .
. . . . r . . . . . . . . . . . . . . .
. . . . * . . . . . . . . . . . . . . .
. . . . ' . . . . . . . . . . . . . . .
. . . . S . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
'*rr # Explanation
'* # Push * (Stack: A, B, A, B, *)
rr # Rotate top three elements twice
Стек сейчас A, B, B, *, A
.
Шаг 3/6/8 (цикл печати)
концепция
E . . . . .
? r s o s u
\ ( r r O <
. . . . . S
IP входит в петлю S
, указывая на север, и выходит из петли в E
, снова указывая на север. Для этого объяснения стек установлен в [..., A, B, C]
. Следующие инструкции выполняются. Обратите внимание, что IP не может выйти из цикла до знака вопроса, поэтому первые четыре инструкции всегда будут выполнены.
Orr(?rsos # Explanation
O # Output `C`
rr # Rotate top three elements twice (Stack: [..., B, C, A])
( # Decrease A by one (Stack: [..., B, C, A-1])
? # If top of stack (A) > 0:
r # Rotate top of stack (Stack: [..., A-1, B, C])
s # Swap top elements (Stack: [..., A-1, C, B])
o # Output top of stack (B) as character code
s # Swap top elements (Stack: [..., A-1, B, C]
#
# ... and repeat ...
Реализация
Вот снова куб, с удаленными ненужными частями. IP начинается с S
, указывая на восток.
. . . . .
. . . . .
. . . . .
? r s o s
\ ( r r O
. . . . . S ' = o ; ^ u . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Как видите, IP попадает в четыре инструкции, прежде чем он входит в цикл. Так как символьный код снова удаляется, мы достигаем цикла с тем же стеком, как мы вошли в эту часть.
'=o; # Explanation
'= # Push =
o # Output
; # Pop from stack
Внутри цикла, объяснение выше имеет место.
Шаг 4 (дифференциация IP-адресов)
Поскольку мы используем вышеупомянутый цикл несколько раз, и все они приводят к тому, что IP-адрес заканчивается в одном и том же месте, мы должны различать несколько прогонов. Во-первых, мы можем различить разделитель (первый прогон имеет a *
, тогда как два и три прогона имеют +
разделитель a ). Мы можем различать прогоны 2 и 3, проверяя значение числа, которое повторяется. Если это так, программа должна завершиться.
Первое сравнение
Вот как это выглядит на кубе. IP начинается в S и указывает на север. Стек содержит [..., * or +, A or 1, 0]
. Число 1 показывает, где IP будет заканчиваться, если это первый цикл (указывает на север), а число 2 показывает, где IP будет заканчиваться, если это второй (или третий) цикл (указывает на восток).
u ' . . .
s + . 1 .
; \ - ? 2
S . . . .
. . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
;s'+-? # Explanation
; # Delete top element (0)
s # Swap the top two elements (Stack: 1/A, */+)
'+ # Push the character code of +
- # Subtract the top two elements and push
# that to the stack (Stack: 1/A, */+, +, (*/+)-+)
? # Changes the direction based on the top
# item on the stack. If it's 0 (if (*/+) == +)
# the IP continues going right, otherwise, it
# turns and continues going north.
Если IP в настоящее время в 1
, стек [A, *, +, -1]
. В противном случае стек есть [A or 1, +, +, 0]
. Как вы можете видеть, в стеке второго случая все еще остается неизвестное, поэтому мы должны сделать еще одно сравнение.
Второе сравнение
Поскольку IP прошел шаг 5, стек выглядит следующим образом : [A^(B-1) or nothing, A or 1, +, +, 0]
. Если первый элемент nothing
, второй элемент 1
, и обратное тоже верно. Куб выглядит следующим образом: IP начинается с S и указывает на восток. Если это второй цикл, IP заканчивается в E
направлении на запад. В противном случае программа нажимает @
и завершает работу.
. . . . .
. . . . ;
. . . S W
. . . . .
. . . . .
. . . . . . . . . . . . . ; . . . . . .
. . . . . . . . . E @ ! \ q . . . . . .
. . . . . . . . . . . . ( * . . . . . .
. . . . . . . . . . . . q u . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Выполненные инструкции, которые ничего не делают с потоком управления, перечислены ниже.
;;q*q(!@
;; # Delete top two elements (Stack [A^(B-1)/null, A/1, +])
q # Send top element to the bottom (Stack [+, A^(B-1)/0, A/1])
* # Push product of top two elements
# (Stack [+, A^(B-1)/0, A/1, A^B/0])
q # Send top element to the bottom
# (Stack [A^B/0, +, A^(B-1)/0, A/1])
( # Decrease the top element by 1
# (Stack [A^B/0, +, A^(B-1)/0, (A-1)/0])
! # If (top element == 0):
@ # Stop program
Стек теперь [A^B, +, A^(B-1), A-1]
, при условии, что программа не завершилась.
Шаг 5 (подготовка к «A +» (повторите A ^ (B-1)))
К сожалению, у Cubix нет оператора power, поэтому нам нужен еще один цикл. Однако сначала нам нужно очистить стек, который теперь содержит [B, A, *, +, -1]
.
Убираться
Вот снова куб. Как обычно, IP начинается в S (указывает на север) и заканчивается в E, указывая на запад.
. . . ? .
. . . ; .
. . . S .
. . . . .
. . . . .
. . . . . . . . . . . . . . . . > $ . v
. . . . . . . . . . . . . . . . . . . ;
. . . . . . . . . . . . . . . . . . E <
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
;; # Explanation
;; # Remove top 2 elements (Stack: [B, A, *])
Вычисление A ^ (B-1)
Еще один цикл, который работает примерно так же, как цикл печати, но он немного компактнее. IP начинается S
со стека, указывая на запад [B, A, *]
. IP выходит, E
указывая на север.
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . . . . . . . . . . . E . . . . .
. . . . . . . . . . . . . . ? s * s u .
. . . . . . . . . . . . . . \ ( s . ; S
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Тело цикла следующее.
;s(?s*s # Explanation
; # Pop top element.
s # Shift top elements.
( # Decrease top element by one
? # If not 0:
s # Shift top elements again
* # Multiply
s # Shift back
#
# ... and repeat ...
В результате стек [A, A^(B-1), 0]
.
Очистка стека (снова)
Теперь нам нужно снова попасть в цикл печати, содержащий верхнюю часть стека [..., A^(B-1), +, A]
. Для этого мы выполняем следующее. Вот снова куб,
. . ^ ? :
. . . . .
. . . . .
. . . . .
E . . . .
. . . . . s . . . . . . . . ; . . $ . .
. . . . . + q U . . . . . . S . . s . .
. . . . . ' u q . . . . . . . . . ? . .
. . . . . . . ? . . . . . . . . . ? . .
. . . . . . . ? . . . . . . . . . ? . .
. . ? . .
. . ? . .
. . ? . .
. . ? . .
. . ? . .
;:$sqq'+s # Explanation
; # Delete top element (Stack: [A, A^(B-1)])
: # Copy top element
$s # No-op
qq # Send top two elements to the bottom
# (Stack: [A^(B-1), A^(B-1), A])
'+ # Push +
# (Stack: [A^(B-1), A^(B-1), A, +])
s # Swap top two elements
# (Stack: [A^(B-1), A^(B-1), +, A])
Шаг 7 (подготовка к последнему циклу)
Стек теперь [A^B, +, A^(B-1), A-1]
, IP начинается в S
, идет на запад и заканчивается в E
, идет направо.
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . . E . . . . . . . . . . . . . .
. . . . . . u 1 ; ; S . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Выполненные инструкции:
;;1 # Explanation
;; # Delete top two elements
1 # Push 1
Стек теперь выглядит так [A^B, +, 1]
, и IP собирается войти в цикл печати, так что мы закончили.