永続的に自己修正するコード


14

現在、ほとんどの言語にはコードを「自己修正」する非常に簡単な方法があることがわかっています。ただし、実際にコードを変更してその一部をディスク上で編集する場合はどうでしょうか?

あなたの目標は、数字を出力するコードを作成し、フィボナッチ数列の次の数字で数字を置き換えるように独自のファイルを編集することです:

$ ./program
1
$ ./program
1
$ ./program
2
$ ./program
3
$ ./program
5
[etc...]

ルール

  1. コードの「外側」に番号を保存することはできません。コメントなし、スクリプトに終了するよう指示せず、EOFなしなど
  2. コードが任意のファイル名で機能する場合、バイト量から2を引き$BYTESNOW ($ORIGINALBYTES - 2)、タイトルを記述します。(ファイル名は、任意の英数字ファイルパスの範囲内であると想定されます。)
  3. コードは、外部の配管支援なしで、出力をファイルに単独で書き込む必要があります。
  4. コードは1または0から開始できます。関係ありません。

8
次回は、代わりにSandboxにアイデアを投稿し、フィードバックを受け取るために数日間そこに投稿を残してください。
ジョンファンミン

2
プログラミング言語のインタプリタを呼び出すことでプログラムを呼び出すことは許可されていますperl6 programか(例:)、それを呼び出すためにシバン行を含める必要があり./programますか?
smls

1
また、-2バイトのボーナスを使いたくない場合は、シングルバイトのファイル名を選択できますか、それをする必要programがあり、現在の作業ディレクトリにあると仮定できますか?
SMLS

多数が暗黙的に指数表記に変換し始めたときに失敗することを許可できますか?
パトリックロバーツ

なぜ2バイトのボーナスしかないのですか?ほとんどの言語、たとえば。Lua、の"a"代わりに行う方が簡単ですarg[0]。それは価値がないようです。
アタコ

回答:


7

バッシュ、 52 47(49-2)バイト

編集:

  • 0ではなく1から始めて、5バイトを節約しました。ありがとう@Leo!

ゴルフ

A=$[1+0]
echo $A
sed -ri "s/\w+\+(\w+)/\1+$A/" $0

テスト

>for i in `seq 10`
> do
> ./fibo
> done
1
1
2
3
5
8
13
21
34
55

2
[-1 + 1]ではなく[1 + 0]から開始することで1バイト節約できると思います(チャレンジの4番目のルールを参照)
レオ

2
実際、-?正規表現からを削除することで、さらに多くのバイトを節約できます。そして、あなたはそこにいるので、最初のキャプチャグループを削除することもできます:)
レオ

@レオそれはいいアドバイスです、ありがとう!
ツェッペリン

2

Python 2、118 111バイト(113-2)

a,b=0,1;print a
f=open(__file__,'r+')
s=f.read()
s=s.replace(s[4:s.find(';')],`b`+','+`a+b`)
f.seek(0)
f.write(s)

任意の有効なファイル名で機能します。ここで説明することはあまりありません。コード自体は非常に冗長です。

思い出させてくれたFlipTackのおかげで、close()必須ではありません。


1
ステートメントのf=open(...)代わりに使用することはできませんwithか?
FlipTack

2

バッチ、81バイト

@call:c
@set/az=x+y
@echo %x%
@echo>>%0 @set/ax=%z%,y=%x%
:c
@set/ax=0,y=1

注:末尾の改行は重要です。拡張機能を含むフルネームを使用してスクリプトを呼び出す必要があります。出力は0から始まります。

Batchはファイルを現実的に編集できないため、ファイルの最後に余分な行を追加するだけで、最終的に印刷する次の番号がわかります。>>%0私は数字で、それよりも前にすることはできませんので、配置はバイトが保存されます。


1

C、142バイト(144-2)

void main(int x,char**a){FILE*f=fopen(*a,"r+");fseek(f,27,0);char n=fgetc(f),m=fgetc(f);fseek(f,27,0);printf("%d\n",fputc(fputc(m,f)?n+m:1,f));}

とても簡単です。最初に読み取り、2つの文字をヘッダーの位置0x1Aに保存します。データを保存するためのより安全な場所を見つけるためにもっと深く調べたかもしれませんが、GCC 4.2ishでコンパイルされたOSXを実行しているマシンで動作し、非常に移植性が高いとは思えません。また、charsに基づいているため、13回目の反復後にオーバーフローします。

出力は次のとおりです。

1
1
2
3
5
8
13
21
34
55

1

Node.js、152 137バイト(139-2)

バイト数の一部ではなく、明確にするために改行で区切られています。

f=_=>require('fs').writeFileSync(__filename,
`f=${f};f()`.replace(/(\d[^,]*),(\d[^\)]*)/,
(m,a,b)=>`${b=+b},${+a+b}`),console.log((0,1)));
f()

説明:

f=_=>                          // define `f` as function with a single unused argument `_`
  require('fs').writeFileSync( // import the standard filesystem module and overwrite file
    __filename,                // string var containing path of file for current module
    `f=${f};f()`.replace(      // template string containing source of entire script
      /(\d[^,]*),(\d[^\)]*)/,  // regexp to match and group the numbers in this script
      (m,a,b)=>                // replace function with arguments match, group a, group b
        `${b=+b},${+a+b}`      // template string incrementing fibonacci numbers in place
    ),                         // end replace()
    console.log(               // prints to stdout, `undefined` passed to argument
      (0,1)                    // comma separated group returns value of last expression
    )                          // end console.log()
  )                            // end fs.writeFileSync()
;                              // end statement defining `f` as arrow function
f()                            // run function to modify script and print fibonacci number

使用法:

// assuming above script is stored in program.js
$ node program
1
$ node program
1
$ node program
2
$ node program
3
$ node program
5
...

1

パイソン3.6、96 91(93-2)バイト

a,b=0,1
f=open(__file__,"r+");next(f);f.write(f"a,b={b,a+b}\n{next(f)}{f.seek(0)}");print(b)

ファイル名をハードコーディングすると、5バイト(88バイト)節約できます。

a,b=0,1
f=open("f","r+");next(f);f.write(f"a,b={b,a+b}\n{next(f)}{f.seek(0)}");print(b)

@Artyerのおかげで数バイト節約


1
これはどうですか(88バイト)a,b=0,1 f=open('f','r+');next(f);f.write(f'a,b={b,a+b}\n{next(f)}{f.seek(0)}');print(b)#
Artyer

1

bash + Unixユーティリティ、43バイト(45-2)

dc -e9k5v1+2/z^5v/.5+0k1/p;sed -i s/z/z1+/ $0

これを初めて実行すると、dcを使用して、Binet式を介して最初のフィボナッチ数を計算します。sedを呼び出すたびに、dcに渡す文字列を変更してプログラムを変更します。この変更により、dcは式の指数に1を追加するように指示されます。これにより、フィボナッチ数列の次の数が毎回計算されます。

テスト

> for k in {1..10}
> do
> ./fib
> done
1
1
2
3
5
8
13
21
34
55

どのように機能するかを説明するために、この時点で55が印刷された後、プログラムは次のように変更されています。

dc -e9k5v1+2/z1+1+1+1+1+1+1+1+1+1+^5v/.5+0k1/p;sed -i s/z/z1+/ $0

もう一度実行すると

> ./fib
89

プログラムは次のようになります。

dc -e9k5v1+2/z1+1+1+1+1+1+1+1+1+1+1+^5v/.5+0k1/p;sed -i s/z/z1+/ $0

私はこれが好き !よくやった !
ツェッペリン

@zeppelinありがとうございます。これにより、以前のバージョンの問題を回避できます。
ミッチェルスペクター

1

SmileBASIC 3、99バイト(101 -2)

任意のファイル名で機能するため、-2バイトのボーナス。

A=0B=1F$="TXT:"+PRGNAME$()S$=LOAD(F$)SAVE F$,SUBST$(S$,0,INSTR(S$,"F"),FORMAT$("A=%DB=%D",B,A+B))?A+B

これは機能しますが、どういうわけか壊れたものと同じサイズになってしまいました!


ボーナスを行わないと、はるかに短くなります
12Me21

特定のファイル名を強制すると、私は変人のように感じます。私はとにかく半分これらの答えを破ってる
snail_

LOADダイアログをオフにしないほうがずっと悪いと思います。
12Me21

スロット1にロードし、PRGEDITコマンドを使用して最初の行を置き換える(および後に改行を追加するA=0B=1)場合、実際には短くなります。またA=0、最初も必要ありません。
12Me21

0

R、145バイト(147-2)

a=c(1,1)
cat(a[1])
R=readLines(f<-sub("^.+=","",grep("^--f",commandArgs(F),v=T)))
cat(c(sprintf("a=c(%i,%i)",a[2],sum(a)),R[-1]),file=f,sep="\n")

(末尾に改行があります)。任意の有効なファイル名で機能します。


0

Perl 6の67 62バイト(64から2)

say (1,1,*+*...*)[1];$*PROGRAM.&{.spurt: .slurp.&{S/\[<(\d+/{$/+1}/}}

say 0+1;$*PROGRAM.&{.spurt: .slurp.&{S/(\d+).(\d+)/$1+{$0+$1}/}}

0

スタック、非競合、65(67-2)バイト

ファイルIOに関するいくつかの問題は、最新の一連のコミットで修正されました。したがって、競合しません。

2:>
:sum\tail...\stack:0#out repr LF+program LF split last+d0\write

これがgithubへのリンクです。

実行例

(わかりやすくするために実際のパスは省略しました。)

C:\
λ type permanently-self-modifying-code.stk
2:>
:sum\last\stack:0#out repr LF+program LF split last+d0\write
C:\
λ stacked permanently-self-modifying-code.stk
1

C:\
λ stacked permanently-self-modifying-code.stk
1

C:\
λ stacked permanently-self-modifying-code.stk
2

C:\
λ stacked permanently-self-modifying-code.stk
3

C:\
λ stacked permanently-self-modifying-code.stk
5

C:\
λ stacked permanently-self-modifying-code.stk
8

説明

これがどのように機能するかは、数値のペアを取得してシーケンスを開始し(2:>この場合は整数範囲[0, 2)(0 1))、次にそれらに対してフィボナッチ変換を実行します。

:sum\last\                     top of stack: (x y)
:              duplicate.             stack: ((x y) (x y))
 sum           sum of TOs.            stack: ((x y) x+y)
    \          swap order.            stack: (x+y (x y))
     last      obtain last element.   stack: (x+y y)
         \     swap order.            stack: (y x+y)

実行のたびに、この変換はスタックの最上部で実行されます。次に、スタックがスタックにプッシュされ、複製され、その最初のメンバーが取得されます(stack:0#)。この項目は出力され、目的のフィボナッチ数です。repr次に、スタックの表現を取得し、改行を追加します。次に、プログラムはスタックにプッシュされ、改行で分割されます。次に、最後のメンバー(最後の行)を取得し、これを前述の文字列に追加します。最後に、プッシュd0(ファイル自体d。ollarsign 0== と考えてください$0)して書き込みます。



0

Clojureは、209の 204 195バイト

0 1(let[u #(apply str %)a"./src/s.clj"p #(Long/parseLong(u %))l(fn[v](split-with #(Character/isDigit %)v))c(slurp a)[n[_ & r]](l c)[m r](l r)b(+(p n)(p m))](println b)(spit a(str(p m)" "b(u r))))

-5バイト。整数ではなく長い数値として解析するように切り替え、いくつかの欠落したスペースを削除します。

-9バイト、2番目の数字の間のスペースを削除して (let...)(これまでで最も高価なスペース)の。

説明については、事前に作成されたコードのコメントを参照してください。

再度テストし、一致しないブラケットエラーをスローしなくなりました。最大7540113804746346429まで動作し、その時点で整数オーバーフロー例外をスローします。

また、これはソースコードが「./src/s.clj」にあることを前提としています。

0 1 ; Starting numbers
(let [; The first 4 entires are shortcuts to functions and data that are used more than once
      u #(apply str %) ; Turns a list into a string
      a "./src/s.clj" ; Current location
      p #(Integer/parseInt (u %)) ; Integer parsing shortcut
      ; Used to split a string on digits to parse them out
      l (fn [v] (split-with #(Character/isDigit %) v))
      src (slurp a) ; Get the source
      [n [_ & r]] (l src) ; Use deconstructuring to grab the first number
      [m r] (l r) ; Same as above, grabbing the second number
      n' (+ (p n) (p m)) ; Parse the 2 numbers, and add them
      ; Put everything back together, only this time with the new numbers
      k (str (p m) " " n' (u r))]
  (println n') ; Print the new number
  (spit a k)) ; Overwrite the old source
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.