Програма самопошкодження


16

Простіше кажучи, ваша мета - створити повноцінну програму, яка змінює свій власний вихідний код, поки кожен символ джерела не буде іншим, ніж те, що воно почалося.

Будь ласка, включіть у свій пост початкове джерело, а також кінцеве джерело, а також опис. Наприклад, опишіть, що (ще) робить ваша програма, мову, яку ви використовували, вашу стратегію тощо.

Правила

  • Ваша програма повинна зупинитися десь після завершення модифікації.
  • Він повинен фактично змінювати свій власний поточний вихідний код (не обов'язково файл, який ви передали інтерпретатору, він змінює його інструкції), а не друкувати нову програму чи писати новий файл.
  • Стандартні лазівки заборонені.
  • Найкоротша програма виграє.

  • Якщо ваша мова може змінювати власний файл і виконувати новий процес компіляції, але не може змінити власний (зараз запущений) вихідний код, ви можете написати таку програму замість + 20% байтів, закруглених вгору. Справжні мови, що змінюються, повинні мати перевагу.

Редагувати : Якщо ваша програма зупиняється з помилками, вкажіть її як таку (і, можливо, скажіть, що таке помилки.)


7
Я правильно розумію, що програма повинна змінювати власне джерело під час роботи, таким чином, що потенційно впливає на його поведінку? Це виключає більшість неезотеричних мов. Або дозволено змінювати джерело та запускати новий процес інтерпретатора / компілятора на ньому?
Zgarb

@ Zgarb Він повинен фактично змінити власний вихідний код. Так, це виключає більшість мов.
mbomb007

8
@ mbomb007 Це погано.
mınxomaτ

1
@ mbomb007 Ніде в вашому питанні не сказано, що він повинен запускати модифікований вихідний код.
mınxomaτ

1
Крім того, ні, це не робить цю проблему тривіальною, вона все одно буде добре проаналізована. Ви виключили з цим занадто багато мов.
mınxomaτ

Відповіді:


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" у зіпсованому коді ...
Даррел Гофман

Насправді, "1"рядок у коді насправді не є частиною «коду», це лише константа, про яку йдеться у байт-коді. Те, що я насправді змінюю, - це складені оптоди віртуальної машини python, а не константи чи змінні. Тож те, що я змінюю, - це не вихідний код на сказку, а лише скомпільований код. Я міг би змінити вихідний код як збережений, але це фактично не вплине на код під час виконання, оскільки він би вже був складений. Якщо ви хочете, я можу розмістити це у "складеному Python 2.7 опкоди з константами", але це було б нерозумно IMO.
Блакитний

Крім того, я не можу дивитись на скомпільований код, тому що, змінивши його, щоб побачити всередині, я фактично змінюю код, тобто я насправді не бачу коду. Так що, я навіть не маю уявлення, чи дійсно код замінює кожен символ, тільки що він змінює більшість (?) З них
Blue

Щоб обійти питання про те, що 1 не змінюється у складеному коді, ви можете змінити значення "1"на <backtick>1+1<backtick>лише ще 2 байти
Mego

Не те, що я бачу (складено з 2.7.10). На жаль, 1+1з моєї пропозиції перетворюється на 2компільовану версію ... Компілятор занадто розумний для власного блага!
Мего

11

зло , 1 байт

q

Зло має кілька сховищ пам’яті - один є самим вихідним кодом, а один - колесом , круговою чергою, яка ініціалізується на один нуль. qпідміняє вихідний код і колесо, тому він замінює джерело на нульовий байт. Однак, лише малі літери є дійсними операторами в злі, так що персонаж просто не працює, і програма припиняється.


6

МСМ , 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

Мальбодж, 1 або 2 байти.

D

Мова Malbolge "зашифровує" кожну інструкцію після її виконання, тому цей лист (Malbolge NOP) перетвориться на !(що також є nop), а потім припиниться. Чомусь інтерпретатору Malbolge, який я використовую, потрібно запустити два байти, даючи DC(обидва з них - nops), які стають !U(обидва - також nops)

Редагувати: Початковий стан пам'яті Malbolge залежить від двох останніх символів у коді, тому він недостатньо визначений для однієї символьної програми. (Хоча цей код не стосується початкового стану пам'яті)


5

x86 асм - 6 байт

не впевнений, що "поки кожен символ джерела не відрізняється від того, що він починався як", посилається на кожен байт, кожну немонічну або загальну модифікацію. якщо я недійсний, я можу змінити xor на rep xor, тому кожен біт змінює значення, але сподівався не зробити цього, щоб зберегти ще 6 байт, щоб залишитися хоч трохи порівнянним з цими мовами гольфу спеціальності.

Все це - це змінити c2 на c3 retn, отримавши пряму електронну адресу eip і xoring 5 байтів попереду.

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, з нулями (показано як _), щоб використовувати для тимчасових значень.

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

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
   ^

Стрічка після виконання буде усіма нулями, за винятком згенерованого коду [_[_-_]_<_].

Примітка:

Ця програма дала мені зрозуміти, що мій інтерпретатор Python для SMBF має помилку або дві, і я ще не з'ясував виправлення. Це зараз виправлено.


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

Червоний код , 7 байт, 1 інструкція (лише приклад. Не змагається)

Це тривіальний приклад.

Переміщує наступне місце пам’яті на себе, а потім зупиняє (тому що вся пам'ять ініціалізована до DAT 0 0, що зупиняє програму при виконанні.)

MOV 1 0

2
Чому ви вважаєте це інструкцією замість байтів?
Мартін Ендер

Тому що я не знаю, скільки це байт. Я думаю, це залежить від розміру пам'яті чи реалізації? ...
mbomb007

4
Я б порахував символи ASCII, якщо ви не знаєте, як це реалізовано.
lirtosiast

1
Зі сторінки Вікіпедії: Кожна інструкція Redcode займає рівно один слот пам'яті та виконує рівно один цикл. ... Пам'ять адресується одиницями однієї інструкції.
mbomb007

3
Всі кодові повідомлення про гольф оцінюються в байтах. Оскільки машинного коду Redcode немає, ми повинні використовувати символи в "джерелі збірки", а не те, на що він збирається.
lirtosiast

3

Powershell 65 байт

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

Визначте функцію, яка переписує себе на нуль.

Оцініть його один раз, і він усуває себе.

По черзі (видаляє себе з пам'яті) 36 байт

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

Виклик спочатку видаляє, потім намагається рекурсивно оцінити. Помилка як невідома команда.


3

МІКСАЛ, 6 байт (рахуючи 2 вкладки)

    STZ    0

Програма запускається з місця в пам'яті 0, а потім записує 0 до місця пам'яті 0, тим самим стираючи себе. Машина автоматично зупиняється.

Це мова складання гіпотетичного 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", який НЕ є НОП, і при читанні видасть помилку.

Також перед командою '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"):])

В основному, це перемикає поточний файл, що кодує джерело python, asciiі utf-8, таким чином, істотно змінюючи кожен символ джерела!


Є кілька додаткових пробілів, які можна видалити. ) as-> )as, ) else-> )else, "utf-8"if, 'w',encoding.
mbomb007
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.