您的任务(如果希望接受)是编写一个程序/函数,该程序输出/返回其整数输入/参数。棘手的部分是,如果我反转源代码,则输出必须是取反的原始整数。
例子
假设您的源代码为ABC
,其输入为4
。如果我CBA
改为编写并运行它,则输出必须为-4
。
假设您的源代码为ABC
,其输入为-2
。如果我CBA
改为编写并运行它,则输出必须为2
。
输入的0
可能为0
或-0
,但是,如果您确实支持带符号的零,-0
则应为0
。
您的任务(如果希望接受)是编写一个程序/函数,该程序输出/返回其整数输入/参数。棘手的部分是,如果我反转源代码,则输出必须是取反的原始整数。
假设您的源代码为ABC
,其输入为4
。如果我CBA
改为编写并运行它,则输出必须为-4
。
假设您的源代码为ABC
,其输入为-2
。如果我CBA
改为编写并运行它,则输出必须为2
。
输入的0
可能为0
或-0
,但是,如果您确实支持带符号的零,-0
则应为0
。
Answers:
C3 D8 F7
上面的代码字节定义了一个无操作的函数:它只是将控制权返回给调用者。该函数后跟两个将不执行的垃圾字节,因为它们是在返回之后出现的,它们位于“无人区”。在汇编助记符中:
ret ; C3
fdiv st(0), st(7) ; D8 F7
好的,现在有一些巨魔来了,并反转了字节的顺序:
F7 D8 C3
现在,这些字节定义了一个函数,该函数在EAX
寄存器中使用一个整数参数,将其取反,然后将控制权返回给调用方。在汇编助记符中:
neg eax ; F7 D8
ret ; C3
所以...很简单。:-)
注意,我们可以使“取反”指令成为我们想要的任何东西,因为它永远不会以“正向”方向执行,而只会以“反向”方向执行。因此,我们可以遵循相同的模式来任意处理更复杂的东西。例如,这里我们在另一个寄存器中采用一个整数参数(例如,EDI
遵循* nix系统上常用的System V调用约定),将其取反,然后在常规EAX
寄存器中返回它:
C3 ret
D8 F7 fdiv st(0), st(7) ; \ garbage bytes that
F8 clc ; | never get executed,
89 .byte 0x89 ; / so nobody cares
↓↓
89 F8 mov eax, edi
F7 D8 neg eax
C3 ret
S S S N
S N
S T N
T T T T T T N
S T N
N
N
T S N
T N
S S T N
T T S S T T T T T N
T S N
S N
S S S
字母S
(空格),T
(制表符)和N
(换行符)仅作为突出显示而添加。
对我的空白答案进行细微修改,以便我反转源代码,您否定输出!挑战。
说明:
利用内置的退出程序是一个短回文NNN
。
常规程序将:
SSSN # Push 0 to the stack
SNS # Duplicate it
TNTT # Read STDIN as integer, and store it at heap address 0
TTT # Retrieve the input from heap address 0, and push it to the stack
TNST # Pop and print the top of the stack as number
NNN # Exit the program, making everything after it no-ops
反向程序将:
SSSN # Push 0 to the stack
SNS # Duplicate it
TNTT # Read STDIN as integer, and store it at heap address 0
TTT # Retrieve the input from heap address 0, and push it to the stack
SSTTN # Push -1 to the stack
TSSN # Multiply the top two values on the stack together
TNST # Pop and print the top of the stack as number
NNN # Exit the program, making everything after it no-ops
小推数字的其他说明:
S
:启用堆栈操作S
:将数字推入堆栈S
或T
:分别为正/负S
/ T
后跟一个N
:二进制数字,其中S=0
和T=1
即SSTTSTSN
推-10
。对于0
我们,我们不需要显式的S=0
,因此简单SSSN
或SSTN
足够。
#)]}{[(
反转:
([{}])#
注意:仅在支持注释的解释器中有效(例如,在Rain-Flak中有效,但在BrainHack中不适用)
如果我们也交换开/关括号而不仅仅是反转字节,那么我们可以在8个字节中完成此操作而无需使用注释:
({}[{}])
#
开始注释,因此原始版本中的括号将被忽略。
我决定不加评论就放弃。
`+`=scan;""+-0;nacs=`+`
`+`=scan;0-+"";nacs=`+`
在向前版本+
中,代理是二进制运算符,并且-
是一元运算符。
相反,+
变成一元,而变成-
二进制。因此,scan函数采用以下参数:file=""
这意味着stdin和what=0
,它们也是默认值。所以当+
参数为一元时,第一个参数在右边,当参数为二元时,第一个参数在左边。
的
;nacs=`+`
代码的一部分并没有真正有用的功能,因此从某种意义上说,我的代码并没有比使用注释技巧更有效。
+
将其重新定义为一元和二进制形式。我花了一分钟的时间来理解它是如何解析的……没有其他操作员姓名可以完成这项工作。
$#
会给出错误(如果#不是最后一个字符)或什么都不显示
-p
或-n
。我怀疑样板与它有关…
perl -MO=Deparse -p <(echo -n '$_*=$#')
,因为它似乎perl -MO=Deparse -pe '$_*=$#'
增加了换行符
I@-Ov
由于“反手”中指针的性质,使其有点复杂。我认为不可能再缩短哈哈了,事实证明我错了。这不会重复任何指令,并且会在两个程序之间重用输入,输出和终止命令。现在,我认为这是最佳选择,因为您需要所有IO-@
命令才能工作,并且在4字节程序中,您只能执行其中两个命令。
反手中的指针在三个单元格处移动一个刻度,并从该单元格的边界反弹,这意味着常规逻辑是重叠的。但是,您可以使用v
和^
命令。
原始程序执行指令IO-@
,即输入为数字,输出为数字,减去,终止。显然,减法是多余的。在代码中,这些是:
I@-Ov
^ ^ Reflect
^ Reflect again
^
反向程序执行v-I-vO-@
。的v
降低之间的蜱的指针的步骤,和-
从堆栈的底部,这是隐式零中减去。额外的-
命令什么都不做。程序执行像
vO-@I
v Reduce pointer speed to 2
- Subtract zero from zero
I Get input as number and reflect off boundary
- Subtract input from zero
v Reduce pointer speed to 1
O Output as number
- Subtract zero from zero
@ Terminate
n-r0
使用带有-v
选项的堆栈初始化,将输入变量放在此处。
说明
n Prints whatever is on the stack as a number
- Subtract the top 2 elements on the stack.
There aren't 2 elements, so it crashes.
r0 Never gets executed
or reversed:
0 Push a 0 onto the stack
r reverse the stack (now 0, -v)
- Subtract top 2 elements and push result (0-v, ie negated)
n Print as number
The code wraps around and executes again.
It crashes on the - as there is only one
item on the stack: 0.
-mn
,2个字节-X
事实证明,这实际上比Stack Cats中的上一个挑战要容易得多。完整的程序(申请后-m
)是-X-
。X
用于交换磁带头左右的堆栈,即它根本不影响初始堆栈,因此我们可以忽略它。但是然后程序实际上只是--
(两次使栈顶取反),什么也不做。
对于逆向程序,应用-m
给出X-X
。再说一次,X
什么也不做,所以程序实际上就是just -
,它否定了栈的顶部。
唯一的其他2字节解决方案是-=
,但实际上是相同的。唯一的区别是仅=
交换相邻堆栈的顶部,而不交换整个堆栈。
但是再次,使用-m
感觉有点像作弊,因此下面是使用完全镜像程序的解决方案。
-n
,7字节:I<->I:
先前答案的注意事项仍然适用:任何有效的解决方案都需要使用成对的字符和I
。六个可能的解决方案(包含在TIO链接中)几乎都是相同的。-
和_
在此程序中是等效的,:
可以用|
或代替T
(对于非零输入,它们的作用相同,同时对于零输入也适用)。我刚刚选择这一个来解释,因为它是最简单的。
因此请记住,初始堆栈将输入保持在a的顶部-1
(在无限多个零的顶部),而磁带上的所有其他堆栈仅保持零。Stack Cats还具有以下特性:任何偶数长度的程序都不会执行任何操作(前提是它终止了,但是无论如何我们都不能使用循环来进行此挑战)。那么对于任何奇数长度的程序,其中心字符什么都不做,显然也是如此……让我们来看一下:
: Swap the input with the -1 below.
I Move the -1 one stack to the left and turn it into +1.
< Move another stack left (without taking the value).
- Negate the zero on top of that stack (i.e. do nothing).
因此,程序的后半部分恰好撤消了前半部分,因此我们最终将输入重新放在了顶部-1
。
逆程序是:I>-<I:
。让我们看看它如何改变事物:
: Swap the input with the -1 below.
I Move the -1 one stack to the left and turn it into +1.
> Move one stack right, i.e. back onto the initial stack which still holds the input.
- Negate the input.
< Move back to the left where we've parked the 1.
I Move that 1 back onto the initial stack and turn it back into a -1.
: Swap the -1 below the negated input to act as an EOF marker.
@ECHO.%1 2>MER@
@REM>2 1%=-aa/TES@
回显(ECHO.
)输入(%1
)。从技术上讲,第一行的其余部分将重定向STDERR
到名为的文件MER@
,但这不会产生影响。
第二行被注释掉(REM...
)。
@SET/aa-=%1 2>MER@
@REM>2 1%.OHCE@
使用set命令(SET /a
)的算术模式从未定义的变量()中减去(-=
)输入(%1
),该变量a
等于0 - input
。同样,第一行的其余部分在技术上都重定向STDERR
到名为的文件MER@
,但这没有影响。
第二行被注释掉(REM...
)。