स्थायी रूप से स्व-संशोधित कोड


14

अब, हम सभी जानते हैं कि अधिकांश भाषाओं में "स्व-संशोधित" कोड के बहुत सरल तरीके हैं। हालाँकि, क्या होगा अगर आप वास्तव में कोड को संशोधित करने और डिस्क पर ... के कुछ हिस्सों को संपादित करें?

आपका लक्ष्य उस कोड को बनाना है जो एक संख्या को प्रिंट करता है, फिर संख्या को बदलने के लिए अपनी फाइल को संपादित करता है ताकि अगले नंबर पर फिबोनाची अनुक्रम में इस तरह से हो:

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

नियम

  1. आप कोड के बाहर "संख्या" को स्टोर नहीं कर सकते हैं। कोई टिप्पणी नहीं, कोई स्क्रिप्ट को बाहर निकलने के लिए नहीं कह रहा है, कोई ईओएफ इत्यादि नहीं।
  2. यदि आपका कोड किसी फ़ाइल नाम के साथ काम करता है, तो अपनी बाइट राशि से 2 घटाएं और $BYTESNOW ($ORIGINALBYTES - 2)अपने शीर्षक में लिखें । (फ़ाइलनाम को किसी अल्फ़ान्यूमेरिक फ़ाइल पथ की सीमा के भीतर माना जाता है।)
  3. आपका कोड किसी भी बाहरी पाइपिंग सहायता के बिना, फ़ाइल पर आउटपुट को स्वयं लिखना चाहिए।
  4. आपका कोड एक या शून्य से शुरू हो सकता है। इससे कोई फर्क नहीं पड़ता।

8
अगली बार, कृपया सैंडबॉक्स में अपना विचार पोस्ट करें और प्रतिक्रिया प्राप्त करने के लिए कुछ दिनों के लिए पोस्ट छोड़ दें।
जंगवान मिन

2
क्या प्रोग्रामिंग भाषा (जैसे perl6 program) के दुभाषिया को आमंत्रित करके कार्यक्रम को कॉल करने की अनुमति है , या क्या उसे शबंग रेखा को शामिल करना है ताकि इसे कहा जा सके ./program?
SMLS

1
इसके अलावा, अगर हम -2 बाइट्स बोनस के लिए नहीं जाना चाहते हैं, तो क्या हम सिंगल-बाइट फ़ाइल नाम चुन सकते हैं या क्या यह होना चाहिए program, और क्या हम यह मान सकते हैं कि यह वर्तमान वर्किंग डायरेक्टरी में स्थित है?
धूम्रपान करता है

क्या बड़ी संख्या में घातीय संकेतन में परिवर्तित होने पर इसे विफल होने दिया जा सकता है?
पैट्रिक रॉबर्ट्स

केवल 2 बाइट्स बोनस क्यों? अधिकांश भाषाएँ, जैसे। लुआ, "a"इसके बजाय बस करना आसान है arg[0]। यह इसके लायक नहीं लगता है।
एटीको

जवाबों:


7

दे घुमा के, 52 47 (49-2) बाइट्स

संपादन:

  • सहेजा गया 5 बाइट्स, 0. के बजाय 1 के साथ शुरू करके @ धन्यवाद @!

golfed

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 + 0] के बजाय [1 + 0] से शुरू करके 1 बाइट बचा सकते हैं (चुनौती का 4 वाँ नियम देखें)
Leo

2
वास्तव में, यह आपको -?regex से हटाकर और भी अधिक बाइट्स को बचाने में मदद करेगा । और जब से आप वहां हैं, आप पहले कैप्चरिंग ग्रुप को भी हटा सकते हैं :)
सिंह

@ लिओ यह एक अच्छी सलाह है, धन्यवाद!
ज़ेपेलिन

2

अजगर 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 से शुरू होता है।

चूंकि बैच वास्तविक रूप से किसी फ़ाइल को संपादित नहीं कर सकता है, मैं सिर्फ फ़ाइल के अंत में अतिरिक्त लाइनें जोड़ता हूं, इसलिए अंततः यह पता चलेगा कि प्रिंट करने के लिए अगला नंबर कौन सा है। >>%0नियुक्ति एक बाइट क्योंकि मैं इसे अंक के साथ पहले नहीं हो सकती बचाता है।


1

सी, 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

पायथन 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)#
अरेटी

1

बैश + यूनिक्स उपयोगिताओं, 43 बाइट्स (45-2)

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

पहली बार जब इसे चलाया जाता है, तो यह बिन फॉर्मूला के माध्यम से 1 फाइबोनैचि संख्या की गणना करने के लिए डीसी का उपयोग करता है। प्रत्येक कॉल सेड डीसी को पास किए गए स्ट्रिंग को बदलकर कार्यक्रम को संशोधित करता है; यह परिवर्तन सूत्र में प्रतिपादक में एक अतिरिक्त 1 जोड़ने के लिए dc को बताता है, जो इसे हर बार फाइबोनैचि अनुक्रम में अगली संख्या की गणना करने का कारण बनता है।

परीक्षा

> 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

स्माइलबासिक 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

यह एक काम करता है, और यह किसी भी तरह से मेरे टूटे हुए के रूप में एक ही आकार का हो गया!


अगर आप बोनस नहीं करते हैं तो यह बहुत कम है
12M2121

एक विशिष्ट फ़ाइल नाम मजबूर करने से मुझे एक सनकी की तरह महसूस होता है। मैं इन आधे जवाबों को वैसे भी पीट रहा हूं
घोंघा_

मुझे लगता है कि LOAD संवाद को बंद नहीं करना बहुत बुरा है।
12M2121

यह वास्तव में छोटा है यदि आप इसे स्लॉट 1 में लोड करते हैं और PRGEDITपहली पंक्ति को बदलने के लिए कमांड का उपयोग करते हैं (और बाद में एक लाइनब्रेक जोड़ते हैं A=0B=1) और आपको A=0पहली बार भी ज़रूरत नहीं है ।
12M2121

0

आर, 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

पर्ल 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 के बारे में कुछ मुद्दे सबसे हाल की श्रृंखला की कमिट में तय किए गए थे। इस प्रकार, noncompeting।

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कॉलर साइन 0== $0।) और इसे लिखें।



0

क्लोजर, 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...)(अब तक का सबसे महंगा स्पेस!) के बीच के स्पेस को हटाकर ।

विवरण के लिए पहले से कोड की गई टिप्पणियों को देखें।

फिर से परीक्षण किया गया है, और यह अब बेजोड़ ब्रैकेट त्रुटियों को नहीं फेंकता है। यह 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.