Program samookaleczania

16

Mówiąc najprościej, Twoim celem jest stworzenie kompletnego programu, który modyfikuje swój własny kod źródłowy, dopóki każda jego postać nie będzie inna niż początkowo.

W swoim poście umieść źródło początkowe oraz źródło końcowe, a także opis. Np. Opisz, co (jeszcze) robi twój program, używany język, twoja strategia itp.

Zasady

  • Twój program musi się zatrzymać po zakończeniu modyfikacji.
  • Musi faktycznie zmodyfikować własny, aktualnie działający kod źródłowy (niekoniecznie plik przekazany do interpretera, modyfikuje instrukcje), nie może drukować nowego programu ani pisać nowego pliku.
  • Standardowe luki są niedozwolone.
  • Najkrótszy program wygrywa.

  • Jeśli twój język może modyfikować własny plik i wykonać nowy proces kompilatora, ale nie może modyfikować własnego (aktualnie działającego) kodu źródłowego, możesz napisać taki program zamiast kary + 20% bajtów, w zaokrągleniu w górę. Prawdziwe samomodyfikujące się języki powinny mieć przewagę.

Edycja : jeśli Twój program zatrzymuje się z błędami, określ go jako taki (i może powiedz, jakie są błędy).

mbomb007
źródło
7
Czy rozumiem poprawnie, że program powinien modyfikować własne źródło podczas działania, w sposób, który potencjalnie wpływa na jego zachowanie? Wykluczałoby to większość nie-ezoterycznych języków. Czy może modyfikować źródło i uruchamiać na nim nowy proces interpretera / kompilatora?
Zgarb,
@Zgarb Musi faktycznie zmodyfikować własny, aktualnie uruchomiony kod źródłowy. Tak, to wyklucza większość języków.
mbomb007,
8
@ mbomb007 To źle.
mınxomaτ
1
@ mbomb007 Mówi, że nigdzie w tobie nie ma wyzwania, aby uruchomić zmodyfikowany kod źródłowy.
mınxomaτ
1
Poza tym nie sprawia, że ​​to wyzwanie jest trywialne, nadal ma dobry zasięg. Dzięki temu wykluczyłeś zbyt wiele języków.
mınxomaτ

Odpowiedzi:

19

/// , 1 bajt

/

Program znajduje /(początek grupy zastępującej wzorce) i usuwa ją w ramach przygotowań do wykonania zamiany. Potem osiąga EOF, więc poddaje się i zatrzymuje.

lirtosiast
źródło
To najwcześniejsza odpowiedź z 1 bajtem, więc jest zwycięzcą.
mbomb007
22

Labirynt , 2 bajty

>@

Do >obraca źródło tak, że staje się

@>

Wskaźnik instrukcji znajduje się teraz w ślepym zaułku i odwraca się, aby nacisnąć ten, @który kończy program.

Oczywiście <@też by działało.

Martin Ender
źródło
12

Python 2, 225 bajtów

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)

Końcowy kod źródłowy to ciąg "0"s, którego długość jest równa liczbie bajtów w oryginalnym skompilowanym obiekcie kodu.

Kod znajduje działający obiekt kodu sys._getframe().f_code.co_codei tworzy strukturę, która reprezentuje obiekty łańcuchowe Pythona. Następnie pobiera pamięć, którą kod faktycznie zajmuje i zastępuje ją "0"*len(c).

Po uruchomieniu program kończy działanie z następującym śledzeniem:

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

To pokazuje, że nadpisanie zakończyło się powodzeniem, a program umiera, ponieważ 0nie jest prawidłowym kodem operacji.

Dziwi mnie, że jest to nawet możliwe w Pythonie, obiekty ramek są tylko do odczytu, nie mogę tworzyć nowych. Jedyną skomplikowaną rzeczą jest zmiana niezmiennego obiektu (łańcucha).

niebieski
źródło
Nie jestem pewien, czy to całkowicie spełnia wymagania, że ​​KAŻDA postać musi być inna. „1” w oryginalnym kodzie źródłowym nadal byłoby „1” w zniekształconym kodzie ...
Darrel Hoffman
Cóż, w rzeczywistości "1"ciąg znaków w kodzie nie jest tak naprawdę częścią „kodu”, a jedynie stałą, do której odwołuje się kod bajtowy. To, co tak naprawdę zmieniam, to skompilowane kody maszyn wirtualnych Pythona, a nie stałe i zmienne. Więc zmieniam nie kod źródłowy, tylko skompilowany kod. Mógłbym zmienić kod źródłowy jako przechowywany, ale tak naprawdę nie wpłynie to na kod w czasie wykonywania, ponieważ zostałby już skompilowany. Jeśli chcesz, mógłbym opublikować to w „skompilowanych kodach Pythona ze stałymi”, ale byłoby to głupie IMO.
Niebieski,
Poza tym nie mogę patrzeć na skompilowany kod, ponieważ zmieniając go, aby zobaczyć wnętrze, zmieniam kod, co oznacza, że ​​tak naprawdę go nie widzę. Tak naprawdę nie mam pojęcia, czy kod naprawdę zastępuje każdy znak, tylko że zmienia większość (?) Z nich
Blue
Aby poruszać się po numerze 1 nie są zmieniane w skompilowanego kodu, można zmienić "1"się <backtick>1+1<backtick>na tylko 2 więcej bajtów
Mego
Nie, że widzę (skompilowane z 2.7.10). Niestety, 1+1z mojej sugestii zmienia się 2w skompilowaną wersję ... Kompilator jest zbyt inteligentny dla własnego dobra!
Mego
11

zło , 1 bajt

q

zło ma kilka magazynów pamięci - jeden to sam kod źródłowy, a drugi to koło, które jest kolistą kolejką, która jest inicjowana do pojedynczego zera. qzamienia kod źródłowy i koło, więc zamienia źródło na bajt zerowy. Jednak tylko małe litery są prawdziwymi operatorami zła, więc znak jest po prostu nieobecny, a program się kończy.

Martin Ender
źródło
6

MSM , 8 bajtów

'.qp.;.;

Przekształca kod źródłowy na pqpqpqpq

MSM działa na liście ciągów. Polecenia są pobierane z lewej strony i traktują prawą stronę jako stos. MSM zawsze działa na własnym źródle.

Śledzenie wykonania:

'.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      
nimi
źródło
6

Malbolge, 1 lub 2 bajty.

D

Język Malbolge „szyfruje” każdą instrukcję po jej wykonaniu, więc ta litera (Malbolge NOP) stanie się !(która jest również nop), a następnie zakończy się. Z jakiegoś powodu interpreter Malbolge, którego używam, wymaga dwóch bajtów do uruchomienia, co daje DC(oba są nops) staje się !U(oba są również nops)

Edycja: Początkowy stan pamięci Malbolge zależy od dwóch ostatnich znaków w kodzie, więc nie jest dobrze zdefiniowany dla programów jednoznakowych. (Chociaż ten kod nie dba o początkowy stan pamięci)

pppery
źródło
5

x86 asm - 6 bajtów

nie jestem pewien, czy „dopóki każda postać źródła nie będzie inna niż to, co się zaczęło jako” odnosi się do każdego bajtu, każdej nemonicznej lub ogólnej modyfikacji. jeśli jestem nieważny, mogę zmienić XOR na XOR Rep, więc każdy bit zmienia wartości, ale miałem nadzieję, że nie zrobię tego, aby zaoszczędzić 6 bajtów, aby pozostać co najmniej trochę porównywalnym z tymi specjalnymi językami golfa.

Wszystko to polega na zmianie c2 na c3 retn poprzez uzyskanie adresu eip na żywo i xoring 5 bajtów z przodu.

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
Pulga
źródło
5

SMBF , 92 bajty

Można grać w golfa, i prawdopodobnie będę pracował nad tym później.

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

Wyjaśnienie

Program generuje następujące polecenia na końcu taśmy, aby się skasować, dlatego musi wygenerować następujące wartości na taśmie:

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

Zrób pęczek 91s, z zerami (pokazanymi jako _) pomiędzy, aby użyć dla wartości temp.

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

code__91_91_91_91_91_91_
   ^

Dostosuj wartości według różnic

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

Taśma po wykonaniu będzie zerami, z wyjątkiem wygenerowanego kodu [_[_-_]_<_].

Uwaga:

Ten program uświadomił mi, że mój interpreter Pythona dla SMBF ma błąd lub dwa, a ja nie znalazłem jeszcze poprawki. Teraz jest naprawione.

mbomb007
źródło
4

Emacs Lisp 22 bajtów

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

Uruchom z 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)

Funkcja ocenia teraz na nil.

Na przemian (cofnij wiązanie) 30 bajtów

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

Ocenić i błędy jak void-function. Funkcja istniała przed uruchomieniem.

Jonathan Leech-Pepin
źródło
4

Redcode , 7 bajtów, 1 instrukcja (tylko przykład. Nie konkuruje)

To jest trywialny przykład.

Przenosi następną lokalizację pamięci na siebie, a następnie zatrzymuje się (ponieważ cała pamięć jest inicjowana DAT 0 0, co powoduje zatrzymanie programu po uruchomieniu).

MOV 1 0
mbomb007
źródło
2
Dlaczego liczysz to jako instrukcje zamiast bajtów?
Martin Ender
Ponieważ nie wiem, ile to bajtów. Myślę, że to zależy od wielkości pamięci lub implementacji? ...
mbomb007
4
Policzyłbym według znaków ASCII, jeśli nie wiesz, jak to jest zaimplementowane.
lirtosiast
1
Ze strony Wikipedii: Każda instrukcja Redcode zajmuje dokładnie jedno gniazdo pamięci i wykonanie dokładnie jednego cyklu. ... Pamięć jest adresowana w jednostkach jednej instrukcji.
mbomb007,
3
Wszystkie słupki do gry w golfa są oceniane w bajtach. Ponieważ nie ma kodu maszynowego Redcode, musimy używać znaków w „źródle asemblera”, a nie w tym, z czym się składa.
lirtosiast
3

Powershell 65 bajtów

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

Zdefiniuj funkcję, która przepisuje się na zero.

Oceń to raz i sam się wyeliminuje.

Na przemian (usuwa się z pamięci) 36 bajtów

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

Wywołanie go najpierw usuwa, a następnie podejmuje próbę oceny rekurencyjnej. Wystąpił błąd jako nieznane polecenie.

Jonathan Leech-Pepin
źródło
3

MIESZALNY, 6 bajtów (licząc 2 karty)

    STZ    0

Program rozpoczyna się w miejscu pamięci 0, a następnie zapisuje 0 w miejscu pamięci 0, usuwając się w ten sposób. Maszyna zatrzymuje się automatycznie.

To jest język asemblera dla hipotetycznego komputera MIX Donalda Knutha, który można złożyć i uruchomić za pomocą zestawu programistycznego GNU MIX ( https://www.gnu.org/software/mdk/ ).

musarithmia
źródło
3

> <> , 40 34 30 bajtów

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

Wypróbuj tutaj!

Wyjaśnienie:

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

Zasadniczo umieszcza na stosie 3 bloki znaków: (ypos, xpos, znak ASCII), który jest odwracany na końcu, więc końcowe polecenie „p” czyta (znak, xpos, ypos) i ustawia tę pozycję w kod do tego znaku. Pierwszy znak jest ręcznie ustawiany jako „<”, dzięki czemu kod kończy się na „> p <” na końcu, aby zapętlić polecenie. Następnie każda inna postać jest nadpisywana jako „”, w tym znak p. „” To tak naprawdę „ASCII CHAR 0”, który NIE jest NOP i spowoduje błąd podczas odczytu.

Musi także istnieć nieparzysta (?) Liczba znaków przed poleceniem „p”, w przeciwnym razie nie zostanie ona zapętlona z powrotem do ostatniego razu i nadpisana.

torcado
źródło
2

Partia, 11 bajtów

@echo>%0&&*

Zmienia kod źródłowy na 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.

@Ma więc polecenie nie jest echem, ale przede wszystkim dlatego oba echos nie w kolejce.

ericw31415
źródło
@mogą być usunięte, ponieważ ECHO(litera)! = echo(małe litery)
pppery
@ppperry Dwa echos nie mogą ustawiać się w szeregu.
ericw31415
Ale to różne przypadki.
pppery
2

Jolf, 4 bajty, niekonkurujące

₯S₯C

Spowoduje to ₯Sprzekazanie ₯Cwartości elementu ody do danych wejściowych, undefinedponieważ żaden nie jest podany. Wypróbuj tutaj!

Conor O'Brien
źródło
0

(System plików) Befunge 98, 46 bajtów

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

Pamiętaj, że ten program tworzy plik o nazwie i manipuluje nim a. Jak to działa:

  1. Kod tworzy plik o nazwie azawierający cały kod (do 256 znaków w każdym wymiarze) przesunął jedną spację w górę i dwie lewe.
  2. Następnie program odczytuje plik o nazwie ajeden wiersz, zastępując cały pierwszy wiersz zawartością apliku.
  3. Druga linia, która została skopiowana przed adresem IP, jest wykonywana
  4. Który czyta aplik do drugiej linii przesunął dwa miejsca w prawo.

Jako efekt uboczny końcowy kod źródłowy nie jest nawet prawidłowy Befunge! (ponieważ zawiera znaki nowej linii jako dane w jednym wierszu)

pppery
źródło
0

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

Zasadniczo przełącza to bieżące kodowanie pliku źródła Pythona pomiędzy asciii utf-8, w ten sposób zasadniczo zmieniając każdy znak źródła!

Prahlad Yeri
źródło
Istnieje kilka dodatkowych spacji, które można usunąć. ) as-> )as, ) else-> )else, "utf-8"if, 'w',encoding.
mbomb007