自残程序


16

简而言之,您的目标是创建一个完整的程序,程序可以修改其自身的源代码,直到源代码的每个字符都与开始时的字符不同为止。

请在您的帖子中包括开始来源和结束来源,以及说明。例如,描述程序的功能(其他),使用的语言,策略等。

规则

  • 修改完成后,您的程序必须暂停。
  • 它实际上必须修改自己的,当前正在运行的源代码(不一定是传递给解释器的文件,而是修改其指令),而不是打印新程序或编写新文件。
  • 不允许出现标准漏洞。
  • 最短的程序获胜。

  • 如果您的语言可以修改自己的文件并执行新的编译器过程,但不能修改自己的(当前正在运行的)源代码,则可以编写这样的程序,而不是将其舍去+ 20%字节。真正的自我修改语言应该具有优势。

编辑:如果您的程序因错误而暂停,请这样指定(并说出错误是什么。)


7
我是否正确理解该程序在运行时应修改其自身的源代码,从而可能影响其行为?这将排除大多数非深奥的语言。还是允许修改源并在其上启动新的解释器/编译器过程?
Zgarb 2015年

@Zgarb 它实际上必须修改自己的当前正在运行的源代码。是的,这排除了大多数语言。
mbomb007

8
@ mbomb007太糟糕了。
mınxomaτ

1
@ mbomb007挑战运行修改后的源代码的人无处不在。
mınxomaτ

1
另外,不,它不会使这项挑战变得微不足道,但范围仍然很广。您排除了太多的语言。
mınxomaτ

Answers:


19

///,1个字节

/

程序找到一个/(模式替换组的开始),并删除它以准备进行替换。然后到达EOF,因此放弃并停止。


最早的答案是1字节,因此是获胜者。
mbomb007

22

迷宫,2字节

>@

>源,使之成为旋转

@>

指令指针现在处于死胡同,转过头去撞,@从而终止了程序。

当然<@也可以。


12

Python 2,225字节

import sys
from ctypes import*
c=sys._getframe().f_code.co_code
i=c_int
p=POINTER
class S(Structure):_fields_=zip("r"*9+"v",(i,c_void_p,i,c_char_p,i,p(i),i,c_long,i,c_char*len(c)))
cast(id(c),p(S)).contents.v=`len([])`*len(c)

结束的源代码是一个"0"s 字符串,其长度等于原始编译代码对象中的字节数。

该代码找到正在运行的代码对象,sys._getframe().f_code.co_code并创建一个表示python字符串对象的结构。然后,它将获取代码实际占用的内存,并将其替换为"0"*len(c)

运行后,程序将退出并进行以下回溯:

XXX lineno: 7, opcode: 49
Traceback (most recent call last):
  File "main.py", line 7, in <module>
    cast(id(c),p(S)).contents.v=`1+1`*len(c)
SystemError: unknown opcode

这表明覆盖成功,并且由于0无效的操作码,程序终止。

令我惊讶的是,这甚至可能在python中实现,框架对象是只读的,我无法创建新的对象。这样做唯一复杂的事情就是更改一个不可变的对象(字符串)。


不知道这是否完全符合每个字符都必须不同的要求。原始源代码中的“ 1”在错误代码中仍为“ 1” ...
Darrel Hoffman 2015年

好吧,实际上,"1"代码中的字符串实际上并不是“代码”的一部分,而只是字节码中引用的常量。我实际上要更改的是已编译的python虚拟机操作码,而不是常量或变量。因此,我要更改的不是源代码,而是已编译的代码。我可以更改存储的源代码,但是实际上不会影响运行时的代码,因为它已经被编译了。如果您愿意,我可以将其发布在“带有常量的Python 2.7编译操作码中”,但这将是愚蠢的IMO。
2015年

而且,我无法查看已编译的代码,因为通过将其更改为在内部查看,我实际上是在更改代码,这意味着我实际上看不到代码。因此,我真的不知道代码是否真的替换了每个字符,只是更改了大多数字符?
Blue Blue

要解决编译后的代码中未更改1的问题,可以将更"1"改为<backtick>1+1<backtick>仅再增加2个字节
Mego 2016年

我没有看到(与2.7.10编译)。不幸的是,1+1我的建议2在编译版本中变成了...编译器太聪明了!
Mego

11

邪恶的 1个字节

q

邪恶有几个存储库-一个是源代码本身,一个是转轮,它是一个初始化为零的循环队列。q交换源代码和滚轮,因此它将源代码替换为空字节。但是,只有小写字母才是邪恶的实际运算符,因此字符只是一个无操作符,程序会终止。


6

MSM,8字节

'.qp.;.;

将源代码转换为 pqpqpqpq

MSM对字符串列表进行操作。命令是从左侧获取的,它们将右侧视为堆栈。MSM始终在自己的源上工作。

执行轨迹:

'.qp.;.;                       upon start the source is implicitly split into a
                               list of single char strings

' . q p . ; . ;                ' takes the next element and pushes it on the stack
    q p . ; . ; .              q is not a command so it's pushed
      p . ; . ; . q            same for p
        . ; . ; . q p          . concats the top and next to top element
          ; . ; . pq           ; duplicates the top element
            . ; . pq pq        concat
              ; . pqpq         dup
                . pqpq pqpq    concat
                  pqpqpqpq     MSM stops when there's only one element left      

6

Malbolge,1或2个字节。

D

Malbolge语言在执行完每条指令后会对其进行“加密”,因此该字母(Malbolge NOP)将变成一个!(也是nop),然后终止。由于某种原因,我使用的Malbolge解释器需要运行两个字节,从而使DC(两个都是nops)变为!U(两个都是nops)

编辑:Malbolge内存的初始状态取决于代码中的最后两个字符,因此对于一个字符程序而言,它的定义不是很好。(尽管此代码不关心内存的初始状态)


5

x86 asm -6个字节

不知道“直到源的每个字符都与它开始时的字符不同”是指每个字节,每个向后字符或常规修改。如果我无效,我可以将xor更改为rep xor,以便每个位都更改值,但希望不要这样做,以节省更多的6个字节,以便至少可以与这些专业高尔夫球语言相比。

这一切都是通过获取eip的实时地址并将其前面的5个字节异或来将c2更改为c3 retn。

58          | pop eax                        ; store addr of eip in eax
83 70 05 01 | xor dword ptr ds:[eax + 5], 1  ; c2 ^ 1 = c3 = RETN
c2          | retn                           ; leave

5

SMBF,92字节

可以打高尔夫球,以后我可能会做更多的工作。

>>+>>+>>+>>+>>+>>+[<-[>+<---]>+++++<<]>>>>>--[>-<++++++]>--->>++>+++++[>------<-]>->>++[<<]<

说明

该程序在其磁带的末尾生成以下命令以擦除自身,因此它必须在磁带上生成以下值:

[[-]<]          ASCII: 91 91 45 93 60 93

制作一堆91s,中间使用null(显示为_)以用于临时值。

>>+>>+>>+>>+>>+>>+[<-[>+<---]>+++++<<]

code__91_91_91_91_91_91_
   ^

通过差异调整值

>>>>>--[>-<++++++]>---  Sub 46
>>++                    Add 2
>+++++[>------<-]>-     Sub 31
>>++                    Add 2
[<<]<                   Shift left to the code
code__[_[_-_]_<_]_      Zero out the code
   ^

执行后的磁带将全部为零,但生成的代码除外[_[_-_]_<_]

注意:

这个程序使我意识到我的SMBF的Python解释器有一个或两个错误,但是我还没有找到解决方法。现在已修复。


4

Emacs Lisp 22字节

(defun a()(defun a()))

从REPL运行:

ELISP> (defun a()(defun a()))
a
ELISP> (symbol-function 'a)
(lambda nil
  (defun a nil))

ELISP> (a)
a
ELISP> (symbol-function 'a)
(lambda nil nil)

函数现在计算为nil

交替(自身解除绑定)30个字节

(defun a()(fmakunbound 'a)(a))

评估和错误为void-function。该功能在运行之前就已经存在。


4

Redcode,7字节,1条指令(仅作为示例。不竞争)

这是一个简单的例子。

将下一个内存位置移到其自身,然后暂停(因为整个内存DAT 0 0都已初始化为,这会在执行时暂停程序。)

MOV 1 0

2
为什么将其计为指令而不是字节?
马丁·恩德

因为我不知道它有多少字节。我认为这取决于内存大小或实现方式?...
mbomb007

4
如果您不知道该如何实现,我将按ASCII字符计数。
lirtosiast,2015年

1
在Wikipedia页面上:每条Redcode指令恰好占用一个内存插槽,并且只需花费一个周期即可执行。...存储器以一条指令为单位进行寻址。
mbomb007

3
所有代码高尔夫帖子均以字节计分。由于没有Redcode机器代码,因此我们必须使用“汇编源代码”中的字符,而不是它所汇编的字符。
lirtosiast 2015年

3

Powershell 65字节

function a{si -pat:function:a -va:([scriptblock]::create($null))}

定义一个将其自身重写为null的函数。

对其进行一次评估,然后消除自己。

交替(从内存中删除自身)36个字节

function a{remove-item function:a;a}

首先调用它会删除它,然后尝试递归求值。错误输出为未知命令。


3

MIXAL,6个字节(计算2个标签)

    STZ    0

程序从存储位置0开始,然后将0写入存储位置0,从而擦除自身。机器自动停止。

这是Donald Knuth假设的MIX计算机的汇编语言,可以使用GNU MIX开发工具包(https://www.gnu.org/software/mdk/)进行组装和运行。


3

> <>40 34 30字节

0&00a6*0&1+:&060"c"l=?!.~~r >p

在这里尝试!

说明:

0&          Adds 0 to the registry
00a6*       Adds "0,0,<" to the stack; coords followed by a character
------------loop start (for clarity)
0           0 added to stack
&1+:&       Registry retrieved, increased by 1, duplicated, one put back in registry
0           ASCII character 0 added to stack (just a 0 but will be converted to that character when inserted in the code)
60          6 and 0 added to stack
"c"         The number 99 added to stack (length of code + 1 * 3)
l=?         Code length added to stack, checks if it is equal to 111

!.          If false, pointer jumps back to character (9,0) (loop start position)
~~r >p      If true, removes the 0 and 9, reverses stack, then loops the p command setting
all the characters to a "<" character and the 2nd character to a " "

基本上,这会将一堆3个字符块放在堆栈中,如下所示:(ypos,xpos,ASCII字符),最后将其反转,因此最终的“ p”命令读取(字符,xpos,ypos)并将其设置在堆栈中该字符的代码。第一个字符被手动设置为“ <”,因此代码最后以“> p <”结尾以循环命令。然后,其他所有字符都被覆盖为包括字符p在内的''。“”实际上是“ ASCII CHAR 0”,不是NOP,读取时会出错。

另外,在'p'命令之前必须有奇数个字符(?),否则它将不会循环回到上一次并被覆盖。


2

批处理,11个字节

@echo>%0&&*

修改源代码为 ECHO is on.

@           - don't echo the command.
 echo       - print ECHO is on.
     >%0    - write to own file.
        &&* - execute * command after the above is done, * doesn't exist so program halts.

@那里,所以命令没有回显,但是大多数情况下,这两个命令不会对齐echo


所述@可以被移除,因为ECHO(大写)=! echo(小写)
pppery

@ppperry两个echo不能对齐。
ericw31415

但是它们是不同的情况。
pppery


0

(文件系统)Befunge 98,46字节

ff*:1100'aof0'ai
               21f0'ai@

请注意,此程序将创建并处理名为的文件a。怎么运行的:

  1. 该代码创建了一个名为的文件,a其中包含整个代码(每个维度中最多256个字符),该文件向上移动一个空格,向左移动两个空格。
  2. 然后,该程序读取名为a一行的文件,将整个第一行替换为a文件的内容。
  3. 执行已复制到IP前面的第二行
  4. 读取a文件的第二行向右移动了两个位置。

副作用是,结尾的源代码甚至都不是有效的Befunge!(因为它包含换行符作为一行中的数据)


0

Python 2,238字节+ 20%= 285.6

# coding: utf-8
import codecs
with codecs.open(__file__,'r') as f:
    t = f.read()
n="utf-8" if t.startswith("# coding: ascii") else "ascii"
with codecs.open(__file__,'w', encoding=n) as f:
    f.write(t[0]+" coding: "+n+t[t.find("\n"):])

基本上,这会在ascii和之间切换python源的当前文件编码utf-8,从而实质上更改了源的每个字符!


有一些多余的空间可以删除。) as- > )as) else- > )else"utf-8"if'w',encoding
mbomb007 '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.