รหัสการแก้ไขตัวเองอย่างถาวร


14

ตอนนี้เราทุกคนรู้ว่าภาษาส่วนใหญ่มีวิธีง่าย ๆ ในการ "แก้ไขตัวเอง" รหัส อย่างไรก็ตามจะเกิดอะไรขึ้นถ้าคุณต้องแก้ไขรหัสและแก้ไขบางส่วน ... บนดิสก์

เป้าหมายของคุณคือการสร้างรหัสที่พิมพ์ตัวเลขจากนั้นแก้ไขไฟล์ของตัวเองเพื่อแทนที่ตัวเลขด้วยหมายเลขถัดไปในลำดับฟีโบนักชีดังนี้:

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

กฎระเบียบ

  1. คุณไม่สามารถจัดเก็บหมายเลข "นอก" ของรหัสได้ ไม่มีความคิดเห็นไม่บอกสคริปต์ให้ออกไม่มี EOF ฯลฯ
  2. หากรหัสของคุณทำงานกับชื่อไฟล์ใด ๆ ให้ลบ 2 จากจำนวนไบต์และเขียน$BYTESNOW ($ORIGINALBYTES - 2)ชื่อของคุณ (ชื่อไฟล์จะถือว่าอยู่ในช่วงของพา ธ ไฟล์ตัวอักษรและตัวเลขใด ๆ )
  3. รหัสของคุณจะต้องเขียนผลลัพธ์ไปยังไฟล์ด้วยตัวมันเองโดยไม่ต้องมีการช่วยเหลือจากภายนอก
  4. รหัสของคุณสามารถเริ่มจากหนึ่งหรือศูนย์ มันไม่สำคัญ

8
ครั้งต่อไปโปรดโพสต์ความคิดของคุณในSandboxแทนและโพสต์ทิ้งไว้สองสามวันเพื่อรับข้อเสนอแนะ
JungHwan Min

2
อนุญาตให้เรียกโปรแกรมโดยการเรียกล่ามภาษาโปรแกรม (เช่นperl6 program) หรือต้องรวมสาย Shebang เพื่อให้สามารถเรียกได้ว่าเป็น./program?
smls

1
นอกจากนี้หากเราไม่ต้องการรับโบนัส -2 ไบต์เราสามารถเลือกชื่อไฟล์แบบไบต์เดียวหรือต้องเป็นprogramและเราสามารถสันนิษฐานได้ว่ามันอยู่ในไดเรกทอรีการทำงานปัจจุบันหรือไม่?
smls

มันสามารถได้รับอนุญาตให้ล้มเหลวเมื่อจำนวนมากเริ่มแปลงโดยปริยายเป็นสัญกรณ์เอ็กซ์โพเนนเชียล?
Patrick Roberts

ทำไมโบนัส 2 ไบต์เท่านั้น ภาษาส่วนใหญ่เช่น Lua มีมันง่ายขึ้นเพียงเพื่อทำแทน"a" arg[0]ดูเหมือนจะไม่คุ้มค่า
ATaco

คำตอบ:


7

ทุบตี, 52 47 (49-2) ไบต์

การแก้ไข:

  • บันทึก 5 ไบต์โดยเริ่มต้นด้วย 1 แทน 0 ขอบคุณ @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 + 0] แทน [-1 + 1] (ดูกฎข้อที่ 4 ของการท้าทาย)
Leo

2
ที่จริงแล้วจะทำให้คุณประหยัดได้มากขึ้นโดยการลบออก-?จาก regex และเนื่องจากคุณกำลังมีคุณยังสามารถลบกลุ่มจับครั้งแรก :)
สิงห์

@Leo นั่นเป็นคำแนะนำที่ดีขอบคุณ!
เรือเหาะ

2

Python 2, 118 111 bytes (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

เนื่องจากแบทช์ไม่สามารถแก้ไขไฟล์ตามความเป็นจริงได้ฉันเพียงแค่เพิ่มบรรทัดพิเศษไว้ท้ายไฟล์ดังนั้นในที่สุดมันก็จะรู้ว่าหมายเลขถัดไปที่จะพิมพ์คืออะไร >>%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));}

มันค่อนข้างตรงไปตรงมา ก่อนอื่นให้อ่านจากนั้นบันทึกสองตัวอักษรที่ตำแหน่ง 0x1A ในส่วนหัว ฉันอาจจะมองลึกลงไปเพื่อหาจุดที่ปลอดภัยกว่าในการบันทึกข้อมูล แต่มันเหมาะกับฉันบนเครื่องที่ใช้ OSX ซึ่งคอมไพล์ด้วย GCC 4.2ish และฉันสงสัยว่ามันเป็นอุปกรณ์พกพามาก นอกจากนี้เนื่องจากมันมีพื้นฐานมาจากตัวอักษรมันล้นหลังจากการทำซ้ำที่ 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

Python 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)

hardcoding ชื่อไฟล์จะบันทึก 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 เพื่อคำนวณหมายเลขฟีโบนักชีหมายเลข 1 ผ่านสูตร 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 ขอบคุณ - นี่เป็นการหลีกเลี่ยงปัญหาที่เกิดขึ้นกับรุ่นก่อนหน้านี้ที่เรามี
Mitchell Spector

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

การบังคับใช้ชื่อไฟล์เฉพาะทำให้ฉันรู้สึกเหมือนเป็นคนประหลาด ฉันตอบครึ่งคำตอบเหล่านี้ต่อไป
หอยทาก _

ฉันคิดว่าการไม่ปิดการโหลด LOAD นั้นแย่กว่ามาก
12Me21

มันสั้นกว่าจริงถ้าคุณโหลดลงในสล็อต 1 และใช้PRGEDITคำสั่งเพื่อแทนที่บรรทัดแรก (และเพิ่ม linebreak หลังจาก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)) จากนั้นทำการแปลง Fibonacci กับพวกเขาเช่น:

: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(ไฟล์นั้นคิดว่าdollar sign 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 ไบต์โดยการลบช่องว่างระหว่างหมายเลขที่สองและ(let...)(พื้นที่ที่แพงที่สุดที่เคย!)

ดูความคิดเห็นของรหัส pregolfed สำหรับคำอธิบาย

ทดสอบอีกครั้งและจะไม่โยนข้อผิดพลาดของวงเล็บที่ไม่ตรงกันอีกต่อไป มันทำงานได้สูงถึง 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.