16
\$\begingroup\$

Simply put, your goal is to create a complete program that modifies its own source code until every character of the source is different than what it started as.

Please include the beginning source as well as the ending source in your post, as well as a description. E.g. Describe what (else) your program does, the language you used, your strategy, etc.

Rules

  • Your program must halt sometime after the modification is complete.
  • It must actually modify its own, currently running source code (not necessarily the file you passed to the interpreter, it modifies its instructions), not print a new program or write a new file.
  • Standard loopholes are disallowed.
  • Shortest program wins.

  • If your language can modify its own file and execute a new compiler process, but cannot modify its own (currently running) source code, you may write such a program instead at a +20% bytes penalty, rounded up. Real self-modifying languages should have an advantage.

Edit: If your program halts with errors, please specify it as such (and maybe say what the errors are.)

\$\endgroup\$
  • 7
    \$\begingroup\$ Do I understand correctly that the program should modify its own source while it is running, in a way that potentially affects its behavior? This would rule out most non-esoteric languages. Or is it allowed to modify the source and launch a new interpreter/compiler process on it? \$\endgroup\$ – Zgarb Oct 7 '15 at 18:38
  • \$\begingroup\$ @Zgarb It must actually modify its own, currently running source code. Yes, that rules out most languages. \$\endgroup\$ – mbomb007 Oct 7 '15 at 18:39
  • 8
    \$\begingroup\$ @mbomb007 That's bad. \$\endgroup\$ – mınxomaτ Oct 7 '15 at 18:41
  • 1
    \$\begingroup\$ @mbomb007 It's says nowhere in you challenge that it has to run the modified source code. \$\endgroup\$ – mınxomaτ Oct 7 '15 at 18:42
  • 1
    \$\begingroup\$ Also, no it doesn't make this challenge trivial, it'll still good scoped. You ruled out too many languages with this. \$\endgroup\$ – mınxomaτ Oct 7 '15 at 18:44

17 Answers 17

19
\$\begingroup\$

///, 1 byte

/

The program finds a / (the start of a pattern-replacement group), and removes it in preparation to make the replacement. Then it reaches EOF, so it gives up and halts.

\$\endgroup\$
  • \$\begingroup\$ The is the earliest answer with 1 byte, so it's the winner. \$\endgroup\$ – mbomb007 Oct 15 '15 at 15:40
22
\$\begingroup\$

Labyrinth, 2 bytes

>@

The > rotates the source so that it becomes

@>

The instruction pointer is now in a dead end and turns around to hit the @ which terminates the program.

Of course, <@ would also work.

\$\endgroup\$
12
\$\begingroup\$

Python 2, 225 bytes

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)

The ending source code is a string of "0"s whose length is equal to the number of bytes in the original compiled code object.

The code finds the running code object, sys._getframe().f_code.co_code, and creates a structure which represents python string objects. It then gets the memory that the code actually takes and replaces it with "0"*len(c).

When ran, the program exits with the following traceback:

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

This shows that the overwrite was successful and the program dies because 0 isn't a valid opcode.

I'm surprised that this is even possible in python, frame objects are read-only, I can't create new ones. The only complicated thing this does is change an immutable object (a string).

\$\endgroup\$
  • \$\begingroup\$ Not sure if this quite meets the requirements that EVERY character must be different. The "1" in the original source code would still be a "1" in the mangled code... \$\endgroup\$ – Darrel Hoffman Oct 9 '15 at 13:05
  • \$\begingroup\$ Well actually, the "1" string in the code isn't actually part of the 'code', its just a constant that's referred to in the bytecode. What I'm actually changing is the compiled python virtual machine opcodes, not the constants or variables. So what I'm changing isn't the source code per say, just the compiled code. I could change the source code as stored but that wouldn't actually affect the code at runtime because it would have already been compiled. If you wanted, I could post this in a 'compiled Python 2.7 opcodes with constants', but that would be silly IMO. \$\endgroup\$ – Blue Oct 9 '15 at 16:31
  • \$\begingroup\$ And also, I can't look at the compiled code because by changing it to see inside, I'm actually changing the code, meaning I don't actually see the code. So really, I have no idea if the code really replaces every character, just that it changes most(?) of them \$\endgroup\$ – Blue Oct 9 '15 at 16:32
  • \$\begingroup\$ To get around the issue of the 1 not being changed in the compiled code, you could change the "1" to <backtick>1+1<backtick> for only 2 more bytes \$\endgroup\$ – Mego Apr 28 '16 at 1:59
  • \$\begingroup\$ Not that I see (compiled with 2.7.10). Unfortunately, the 1+1 from my suggestion gets turned into a 2 in the compiled version... The compiler is too smart for its own good! \$\endgroup\$ – Mego Apr 28 '16 at 5:53
11
\$\begingroup\$

evil, 1 byte

q

evil has several memory stores - one is the source code itself and one is the wheel which is a circular queue which is initialised to a single zero. q swaps the source code and the wheel, so it replaces the source with a null-byte. However, only lower-case letters are actual operators in evil, so that character is simply a no-op and the program terminates.

\$\endgroup\$
6
\$\begingroup\$

MSM, 8 bytes

'.qp.;.;

Transforms the source code to pqpqpqpq

MSM operates on a list of strings. Commands are taken from the left and they treat the right side as a stack. MSM always works on it's own source.

Execution trace:

'.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      
\$\endgroup\$
6
\$\begingroup\$

Malbolge, 1 or 2 bytes.

D

The Malbolge language "encrypts" each instruction after executing it, so this letter (Malbolge NOP) will become an ! (which is also a nop), and then terminate. For some reason, the Malbolge interpreter I use requires two bytes to run, giving DC (both of which are nops) becoming !U (both of which are also nops)

Edit: The initial state of Malbolge memory depends on the last two characters in the code, so it is not well defined for one character programs. (Though this code doesn't care about the initial state of memory)

\$\endgroup\$
5
\$\begingroup\$

x86 asm - 6 bytes

not sure if "until every character of the source is different than what it started as" refers to each byte, each nemonic, or general modification. if I'm invalid I can change the xor to a rep xor so each bit changes values but was hoping not to do that to save 6 more bytes to stay at least a little bit comparable to these specialty golf languages.

All this does is change a c2 to a c3 retn by getting live address of eip and xoring 5 bytes in front.

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
\$\endgroup\$
5
\$\begingroup\$

SMBF, 92 bytes

Can be golfed, and I'll probably work more on it later.

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

Explanation

The program generates the following commands at the end of its tape to erase itself, so it has to generate the following values on the tape:

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

Make a bunch of 91s, with nulls (shown as _) between to use for temp values.

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

code__91_91_91_91_91_91_
   ^

Adjust the values by the differences

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

The tape following execution will be all zeros, with the exception of the generated code [_[_-_]_<_].

Note:

This program made me realize that my Python interpreter for SMBF has a bug or two, and I haven't figured out a fix yet. It's fixed now.

\$\endgroup\$
4
\$\begingroup\$

Emacs Lisp 22 bytes

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

Run from 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)

Function now evaluates to nil.

Alternately (unbind itself) 30 bytes

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

Evaluate and errors as void-function. Function existed prior to being run.

\$\endgroup\$
4
\$\begingroup\$

Redcode, 7 bytes, 1 instruction (Just an example. Not competing)

This is a trivial example.

Moves the next memory location onto itself, then halts (because the entire memory is initialized to DAT 0 0, which halts the program when executed.)

MOV 1 0
\$\endgroup\$
  • 2
    \$\begingroup\$ Why are you counting this as instructions instead of bytes? \$\endgroup\$ – Martin Ender Oct 7 '15 at 19:29
  • \$\begingroup\$ Because I don't know how many bytes it is. I think that's dependent on memory size, or implementation?... \$\endgroup\$ – mbomb007 Oct 7 '15 at 19:31
  • 4
    \$\begingroup\$ I'd count by ASCII characters if you don't know how it's implemented. \$\endgroup\$ – lirtosiast Oct 7 '15 at 19:38
  • 1
    \$\begingroup\$ From the Wikipedia page: Each Redcode instruction occupies exactly one memory slot and takes exactly one cycle to execute. ... The memory is addressed in units of one instruction. \$\endgroup\$ – mbomb007 Oct 7 '15 at 19:47
  • 3
    \$\begingroup\$ All code-golf posts are scored in bytes. Since there is no Redcode machine code, we must use the characters in the "assembly source", not what it assembles to. \$\endgroup\$ – lirtosiast Oct 7 '15 at 20:31
3
\$\begingroup\$

Powershell 65 bytes

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

Define a function that rewrites itself to null.

Evaluate it once and it eliminates itself.

Alternately (deletes itself from memory) 36 bytes

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

Calling it first removes it then attempts to evaluate recursively. Erroring out as an unknown command.

\$\endgroup\$
3
\$\begingroup\$

MIXAL, 6 bytes (counting 2 tabs)

    STZ    0

The program starts at memory location 0 and then writes 0 to memory location 0, thus erasing itself. The machine halts automatically.

This is the assembly language for Donald Knuth's hypothetical MIX computer, which may be assembled and run using GNU MIX development kit (https://www.gnu.org/software/mdk/).

\$\endgroup\$
3
\$\begingroup\$

><>, 40 34 30 bytes

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

Try it here!

Explanation:

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 " "

Basically this puts a bunch of 3 character blocks in the stack like so: (ypos, xpos, ASCII character) which gets reversed at the end so the final 'p' command reads (character, xpos, ypos) and sets that position in the code to that character. The first character is manually set as '<', so that the code ends up being '>p<' at the end to loop the command. Then every other character is overwritten as a ' ' including the p character. The ' ' is actually "ASCII CHAR 0" which is NOT a NOP and will give an error when read.

Also there have to be an odd(?) number of characters before the 'p' command or else it wont be looped back into a last time and overwritten.

\$\endgroup\$
2
\$\begingroup\$

Batch, 11 bytes

@echo>%0&&*

Modifies source code to 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.

The @ is there so the command isn't echoed, but mostly so the two echos don't line up.

\$\endgroup\$
  • \$\begingroup\$ the @ can be removed, because ECHO (uppercase) != echo (lowercase) \$\endgroup\$ – pppery Jun 13 '16 at 19:21
  • \$\begingroup\$ @ppperry The two echos can't line up. \$\endgroup\$ – ericw31415 Jun 16 '16 at 0:18
  • \$\begingroup\$ But they're different cases. \$\endgroup\$ – pppery Jun 16 '16 at 0:21
2
\$\begingroup\$

Jolf, 4 bytes, noncompeting

₯S₯C

This ₯Sets the ₯Code element's value to the input, undefined as none is given. Try it here!

\$\endgroup\$
0
\$\begingroup\$

(Filesystem) Befunge 98, 46 bytes

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

Note that this program creates and manipulates a file named a. How it works:

  1. The code creates a file named a containing the entire code (out to 256 characters in each dimension) shifted one space upward and two the left.
  2. This program then reads the file named a as one line, replacing the entire first line with the contents of the a file.
  3. The second line, which has been copied in front of the IP, is executed
  4. Which reads the a file into the second line shifted two places to the right.

As a side effect, the ending source code isn't even valid Befunge! (because it contains newlines as data in a single line)

\$\endgroup\$
0
\$\begingroup\$

Python 2, 238 bytes + 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"):])

Basically, this toggles the current file encoding of the python source between ascii and utf-8, thus essentially changing every character of the source!

\$\endgroup\$
  • \$\begingroup\$ There are some extra spaces that can be removed. ) as -> )as, ) else -> )else, "utf-8"if, 'w',encoding. \$\endgroup\$ – mbomb007 Jun 13 '16 at 18:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.