นักเลงวันศุกร์: จัดลำดับรายชื่อสเปกตรัมสเปกตรัม ZX ใหม่ของฉัน


15

การเขียนโปรแกรมภาษาแรกที่ผมได้สัมผัสกับเป็นซินแคลขั้นพื้นฐาน เช่นเดียวกับภาษาขั้นพื้นฐานจำนวนมากก็ต้องใช้ทุกสายรหัสที่มาเป็นเลข

ด้วยเหตุนี้การใช้GO TOคำสั่งจึงเป็นไปตามสำนวนและการดำเนินการข้ามไปยังหมายเลขบรรทัดที่กำหนด (ไม่มีป้ายกำกับ)

นอกจากนี้ยังมีGO SUBคำสั่งที่เกี่ยวข้องซึ่งสามารถใช้เป็นการเรียกใช้ฟังก์ชันพื้นฐาน อีกครั้งการดำเนินการกระโดดไปหมายเลขบรรทัดที่กำหนด แต่เมื่อมีคำสั่งถึงการดำเนินการกระโดดกลับไปสอนต่อไปหลังจากที่RETURNGO SUB

ในทำนองเดียวกันRUNคำสั่งจะรีสตาร์ทการทำงานของโปรแกรมที่บรรทัดที่กำหนด

ทุกคนที่ใช้เวลาใด ๆ ในล่าม BASIC ที่มีหมายเลขบรรทัดจะได้เรียนรู้ที่จะใช้รูปแบบการกำหนดหมายเลขโดยมีช่องว่างอยู่ นี่คือเพื่อให้ง่ายต่อการแทรกบรรทัดของรหัสใหม่ อย่างไรก็ตามถึงแม้คุณจะยังคงพบว่าตัวเองต้องการแทรกบรรทัดใหม่ในระหว่างหมายเลขที่ต่อเนื่องกัน


ให้รายการ BASIC ที่มีหมายเลขบรรทัดเป็นอินพุตเอาต์พุตโปรแกรมเดียวกัน แต่เรียงลำดับใหม่เพื่อให้หมายเลขบรรทัดเริ่มต้นที่ 10 และเพิ่มขึ้นทีละขั้นตอนที่ 10 รายการอินพุตอาจมีGO TOหรือGO SUBคำสั่งดังนั้นตัวเลขที่เกี่ยวข้องกับสิ่งเหล่านี้ต้องถูกปรับด้วย

  • GO TOและGO SUBคำสั่งอย่างใดอย่างหนึ่งในสายของตัวเองหรือที่ส่วนท้ายของIF THENเส้น มันปลอดภัยที่จะพูด^(\d+) .*GO (TO|SUB) (\d+)$ก็เพียงพอที่จะจับคู่สายดังกล่าว คำสั่งเหล่านี้ในเครื่องหมายคำพูดควรถูกละเว้น

  • RUNคำสั่งจะอยู่ในบรรทัดของตัวเองเสมอ ในกรณีนี้หมายเลขบรรทัดเป็นตัวเลือก ถ้ามันหายไปล่ามก็เริ่มที่ด้านบนของโปรแกรม

  • ถ้าGO TO, GO SUBหรือRUNคำสั่งอ้างอิงบรรทัดที่ไม่มีอยู่, มันจะข้ามไปยังบรรทัดที่กำหนดถัดไปแทน การป้อนข้อมูลของคุณจำเป็นต้องจัดการกับสิ่งนี้และให้แน่ใจว่าการอ้างอิงบรรทัดดังกล่าวได้รับการแก้ไขเพื่อให้พวกเขาชี้ไปที่บรรทัดที่ถูกต้อง พฤติกรรมอาจไม่ได้กำหนดหากหมายเลขบรรทัดหลังจากสิ้นสุดโปรแกรมได้รับในหนึ่งในคำสั่งเหล่านี้

  • หมายเลขบรรทัดจะเป็นจำนวนเต็มบวก 1 ถึง 9999 เสมอ (ตามคู่มือ) ซึ่งหมายความว่าโปรแกรมอินพุตจะไม่มีบรรทัดมากกว่า 999 บรรทัด

  • บรรทัดอินพุตจะถูกกำหนดหมายเลขตามลำดับจากน้อยไปหามากเสมอ

  • สำหรับวัตถุประสงค์ของการท้าทายรายการอินพุตจะมี ASCII ที่พิมพ์ได้เท่านั้น คุณไม่ต้องกังวลกับชุดตัวละคร ZX ต้องบอกว่าถ้ารายการของคุณเขียนจริงใน ZX ขั้นพื้นฐานหรือ Z80 ที่เหมาะสมประกอบ / รหัสเครื่อง (และมีการเลียนแบบออกมี ) แล้วคุณอาจเลือกสำหรับการป้อนข้อมูลของคุณจะถูกเข้ารหัสในZX ชุดตัวอักษรแทน

  • คุณไม่สามารถใช้ไลบรารีหรือยูทิลิตี้ที่จัดลำดับใหม่เพื่อจุดประสงค์นี้โดยเฉพาะ

อินพุตตัวอย่าง:

1 REM "A rearranged guessing game"
2 INPUT A: CLS
3 INPUT "Guess the number ", B
10 IF A=B THEN PRINT "Correct": STOP
100 IF A<B THEN GO SUB 125
120 IF A>B THEN GO SUB 122
121 GO TO 3
125 PRINT "Try again"
126 RETURN
127 REM "An example of GO TO 7 and GO SUB 13 in quotes"

ตัวอย่างผลลัพธ์:

10 REM "A rearranged guessing game"
20 INPUT A: CLS
30 INPUT "Guess the number ", B
40 IF A=B THEN PRINT "Correct": STOP
50 IF A<B THEN GO SUB 80
60 IF A>B THEN GO SUB 80
70 GO TO 30
80 PRINT "Try again"
90 RETURN
100 REM "An example of GO TO 7 and GO SUB 13 in quotes"

ฉันต้องการเชื่อมโยงกับคู่มือ ZX BASIC สิ่งที่ดีที่สุดที่ฉันสามารถค้นพบได้คือhttp://www.worldofspectrum.org/ZXBasicManual/index.htmlแต่สิ่งนี้ดูเหมือนจะเป็นลิงก์ที่ตายแล้ว เครื่อง Wayback มีสำเนาแม้ว่า


7
ขอแสดงความยินดีกับการถามคำถามที่ 5,000 อีกด้วย!
FryAmTheEggman

1
เวลาที่คิดถึง - พีซีเครื่องแรกของฉันคือ Spectrum 48K และหนึ่งในโปรแกรมการประกอบครั้งแรกของฉันคือการเปลี่ยนหมายเลข
edc65

2
@ edc65 คุณยังมีรหัสแอสเซมบลีของคุณหรือไม่ ถ้าเป็นเช่นนั้นคุณจะยินดีมากที่จะโพสต์มันเป็นคำตอบ!
Digital Trauma

1
กรณีทดสอบควรมีอย่างน้อยหนึ่ง goto / gosub ในสตริงตัวอักษร
Peter Taylor

1
ผมพบว่าการกล่าวถึง: ZX81 ช่วยให้ GOTOs คำนวณและ GOSUBs เช่นเดียวกับในGOTO 100 + A*10และภาคผนวก C ของคู่มือ ZX สเปกตรัมรายการGO TOเป็นยอมรับการแสดงออกเชิงตัวเลข (ไม่มีข้อ จำกัด ที่จะคงที่) นี่คือการอภิปรายเกี่ยวกับข้อดีของการคำนวณGOTOบน ZX80 และ ZX81 BTW ฉันไม่รู้ว่าทำไมพื้นที่เพิ่มเข้ามาในรุ่น Spectrum
Toby Speight

คำตอบ:


5

JavaScript (ES6) 177

แก้ไขเพิ่มการสแกน (ค่าใช้จ่าย) สำหรับหมายเลขบรรทัดที่ถูกต้องถัดไป

l=>l.split`
`.map((x,i)=>([,n,t]=x.match(/(\d+)(.*)/),l[n]=10*-~i,t),l=[]).map((x,i)=>10*-~i+x.replace(/(UN |GO TO |UB )(\d+)$/,(a,b,c)=>(l.some((v,i)=>i<c?0:a=b+v),a))).join`
`

ทดสอบ

f=l=>
  l.split`\n`
  .map((x,i)=>([,n,t]=x.match(/(\d+)(.*)/),l[n]=10*-~i,t),l=[])
  .map((x,i)=>10*-~i+x.replace(/(UN |GO TO |UB )(\d+)$/,(a,b,c)=>(l.some((v,i)=>i<c?0:a=b+v),a)))
  .join`\n`
        
//TEST
console.log=x=>O.textContent+=x+'\n'
  
test=`1 REM "A rearranged guessing game"
2 INPUT A: CLS
3 INPUT "Guess the number ", B
10 IF A=B THEN PRINT "Correct": STOP
100 IF A<B THEN GO SUB 125
120 IF A>B THEN GO SUB 122
121 GO TO 3
125 PRINT "Try again"
126 RETURN`
console.log(test+'\n\n'+f(test))
<pre id=O></pre>


1
ดูดี. +1 ของฉันย่อมาจาก :)
Digital Trauma

2

Perl 6, 147 145 144 142 ไบต์

{my%a;.trans(/^^(\d+)/=>{%a{$0}=$+=10}).trans(/:s<!after \"\N*>(UN |GO TO |UB )(\d+)<!before \N*\">/=>{$0~%a{%a.keys».Num.grep(*>=$1).min}})}

นี่อาจเป็นเรื่องที่ต้องลงเล่นกอล์ฟสักหน่อย

ขยาย

my &f = -> $s { 
    my %line-map; # This will map the old line numbers to the new ones

    $s.trans(/^^(\d+)/                    # This .trans creates the line number map
             => { %line-map{$0} = $+=10 } # as well as replaces the actual line numbers
            )\
      # This .trans replaces all the line numbers for each GO TO, GO SUB, RUN
      .trans(/:s<!after \"\N*>(UN |GO TO |UB )(\d+)<!before \N*\">/ 
             => {$0 ~ %line-map{%line-map.keys».Num.grep(*>=$1).min} } 
            )
}

.minไม่มีเหตุผลที่จะใช้วิธีการ ใช้{min %line-map.keys».Num.grep:*>=$1แทน
Ven

1

Visual Basic สำหรับแอปพลิเคชัน 288 ไบต์

ฉันไม่สามารถต้านทานการแก้ปัญหาในภาษาพื้นฐาน อาจทำงานกับ Visual Basic 6 / .NET หรือตัวแปรสมัยใหม่อื่น ๆ ที่มีการเปลี่ยนแปลงเล็กน้อย

Sub n(t,a)
f=Chr(10)
u=Chr(0)
Open t For Input As 1
a=f &Input(LOF(1),1)&f
Close
j=10
For i=1 To 9999
q=f &j &u
g=" GO TO "
w=i &f
m=j &f
a=Replace(Replace(Replace(Replace(a,g &w,g &m),f &i &" ",q),"B "&w,"B "&m),"UN "&w,"UN "&m)
If InStr(1,a,q)Then j=j+10
Next
a=Replace(a,u," ")
End Sub

ฉันใช้ตัวแปรหนึ่งตัวอักษรจำนวนมากเพื่อความกระชับ นอกจากนี้ฉันยังกำจัดช่องว่างที่ไม่จำเป็นทั้งหมด (VBE ขยายโดยอัตโนมัติเมื่อนำเข้า) จำนวนไบต์เป็นไฟล์. BAS สุดท้ายโดยมี CHR (10) เป็นบรรทัดใหม่

รูทีนย่อยที่สามารถเรียกใช้จากหน้าต่างทันทีของ VBE เปิดโปรแกรม Sinclair BASIC (พารามิเตอร์แรกคือพา ธ ไปยังไฟล์ ASCII - โดยมี CHR (10) เป็นบรรทัดใหม่ - ประกอบด้วยโปรแกรม), เปลี่ยนหมายเลขบรรทัดและเขียนผลลัพธ์ไปยังตัวแปร Variant (พารามิเตอร์ตัวที่สอง)

ความคิดที่จะย้ำกับตัวเลขที่มาสายเป็นไปได้ทั้งหมดเรียงลำดับและสำหรับแต่ละคนแทนในครั้งเดียวหมายเลขบรรทัดที่ตรงกันทั้งหมดรวมทั้งGO TO, GO SUBและRUNการอ้างอิงที่มีจำนวนเส้นเป้าหมายใช้ได้ต่อไป การใช้วิธีการนี้เราไม่ต้องการตารางการแปลใด ๆ หมายเลขบรรทัดเป้าหมายจะเพิ่มขึ้นทุกครั้งที่พบการจับคู่ในหมายเลขบรรทัดต้นทางดังนั้นการอ้างอิงบรรทัด "ผิด" จะถูกปรับโดยอัตโนมัติเป็นหมายเลขที่ถูกต้องถัดไป อักขระขึ้นบรรทัดใหม่ใช้เป็นเครื่องหมายของจุดเริ่มต้นและจุดสิ้นสุดของบรรทัดและ CHR (0) - ไม่เคยใช้ในโปรแกรมเนื่องจากไม่สามารถพิมพ์ได้ - ใช้เป็นเครื่องหมายชั่วคราวเพื่อหลีกเลี่ยงการจัดเรียงบรรทัดเดียวกันหลายครั้ง

ข้อสังเกตบางส่วน:

  • เพื่อความกระชับเราใช้สตริงที่เล็กที่สุดเท่าที่จะเป็นไปได้สำหรับการจับคู่กับข้อความกระโดด การใช้ end-of-line บนสตริงการค้นหาของเราเราจะไม่เสี่ยงต่อการรวมถึง occcurrences หรือฟังก์ชั่นผู้ใช้ (ซึ่งมักใช้วงเล็บใน Sinclair) GO TOต้องการสตริงที่ใหญ่กว่าเนื่องจากFOR ... TOโครงสร้าง (เช่นการเปรียบเทียบ50 FOR X=AGO TO 100และ50 GO TO 100)

  • รหัสไม่รองรับคำสั่งในรูปแบบGO TO200(โดยไม่มีช่องว่าง) แม้ว่าคู่มือ ZX จะบอกว่ามันเป็นรหัสที่ถูกต้องในหลาย ๆ ตัวอย่าง (มันจะมีค่าใช้จ่ายมากกว่าหนึ่งสิบไบต์เพื่อจัดการกับมัน)

  • รหัสจะเพิ่มขึ้นบรรทัดใหม่ที่จุดเริ่มต้นและอีกบรรทัดในตอนท้ายของโปรแกรม ฉันสามารถทำความสะอาดสิ่งนี้ได้ในตอนท้าย (อีกสิบไบต์ขึ้นไป) แต่คิดว่า ZX น่าจะไม่สนใจบรรทัดว่างเปล่า

ด้านล่างเป็นเวอร์ชันที่สามารถอ่านได้มากขึ้น:

Sub Renumber(ByVal ProgramPath As String, ByRef Program As Variant)

    Open ProgramPath For Input As #1
    Program = Chr(10) & Input(LOF(1), 1) & Chr(10)
    Close

    NewNumber = 10
    For OldNumber = 1 To 9999
        Program = Replace(Program, " GO TO" & OldNumber & Chr(10), " GO TO" & NewNumber & Chr(10)) 'self-explaining
        Program = Replace(Program, Chr(10) & OldNumber & " ", Chr(10) & NewNumber & Chr(0)) 'matches line number (and replaces whistespace with Chr(0) to avoid re-replacing
        Program = Replace(Program, "B " & OldNumber & Chr(10), "B " & NewNumber & Chr(10)) 'matches GO SUB
        Program = Replace(Program, "UN " & OldNumber & Chr(10), "UN " & NewNumber & Chr(10)) 'matches RUN
        If InStr(1, Program, Chr(10) & NewNumber & Chr(0)) Then NewNumber = NewNumber + 10 'if there is such a line, increment NewNumber
Next
Program = Replace(Program, Chr(0), " ") 'replace back Chr(0) with whitespace
End Sub

BTW ซึ่งเป็นโซลูชั่น QBasic นั้นใช้เวลานานกว่านี้มากเนื่องจาก QBasic ไม่มีฟังก์ชั่นการเปลี่ยนสตริงในตัวเท่าที่ฉันจำได้
DLosc

ฉันคิดว่าคุณพูดถูก ... ลืมไปเลย
dnep

1

Pip -rn , 63 ไบต์

Ygn:#{_<aFIy}*t+tgR`(RUN|GO (SUB|TO)) (\d+)$`{b.s.(nd)}R`^\d+`n

ลองออนไลน์!

คำอธิบาย

ติดตั้ง

-rธงอ่านทั้งหมดของ stdin gและเก็บไว้เป็นรายการของสายในตัวแปรท้องถิ่น ตัวแปรส่วนกลางtเป็น preinitialized 10 และตัวแปรทั่วโลกsจะ preinitialized " "ไป

Yg

แสดงรายการของบรรทัดgลงในตัวแปรส่วนกลางyเพื่อให้สามารถใช้งานได้ภายในฟังก์ชันที่เรากำลังจะกำหนด

ฟังก์ชั่นการแปลหมายเลขบรรทัด

เราสร้างฟังก์ชั่นที่แมปจากหมายเลขบรรทัดใด ๆ ในรูปแบบการกำหนดหมายเลขดั้งเดิม (รวมถึงหมายเลขที่ไม่มีอยู่) กับหมายเลขบรรทัดที่สอดคล้องกันในรูปแบบการกำหนดหมายเลขใหม่

สมมติว่าเรามีสายเหล่านี้:

1 INPUT A
4 PRINT A
9 IF A=1 THEN GO TO 3

เราต้องการแมป 1 ถึง 10, 2-4 ถึง 20 และ 5-9 ถึง 30 หากเรามีรายการหมายเลขบรรทัดดั้งเดิม ([1; 4; 9] ) เราสามารถใช้การดำเนินการตัวกรองเพื่อค้นหาจำนวนตัวเลขเหล่านี้น้อยลง กว่าหมายเลขบรรทัดที่เราพยายามแปลง คูณผลลัพธ์นั้นด้วย 10 และเพิ่ม 10 และเรามีคำตอบที่ต้องการ

ตัวอย่างเช่นเมื่อแปลง 9 มีหมายเลขบรรทัดสอง (1 และ 4) น้อยกว่า 9 2 * 10 + 10 ให้ 30 เมื่อแปลง 3 มีหมายเลขบรรทัดหนึ่ง (1) น้อยกว่า 3 1 * 10 + 10 ให้ 20

นี่คือรหัส (แก้ไขเล็กน้อยเพื่อให้อ่านง่ายขึ้น):

n:{#(_<aFIy)*t+t}
  {             }  Lambda function with parameter a:
        FIy         Filter y (the list of program lines) for
     _<a             lines that are numerically less than a
                    (In a numeric context, only the first run of digits on the line is considered)
   #(      )        Number of items in the filtered list
            *t+t    Times 10, plus 10
n:                 Assign that function to global variable n

ทดแทนแม่: GO TO, GO SUBและRUN

ส่วนที่เหลือของโปรแกรมเป็นนิพจน์เดียวที่ใช้gและดำเนินการแทนที่ regex สองสามตัว (ซึ่ง vectorize, ใช้กับแต่ละบรรทัดในg)

นี่คือการเปลี่ยนครั้งแรก:

g R `(RUN|GO (SUB|TO)) (\d+)$` {b.s.(nd)}

regex ตรงใด ๆRUN, GO SUBและGO TOตามด้วยตัวเลขตามด้วยจุดสิ้นสุดของบรรทัด สิ่งนี้ทำให้แน่ใจได้ว่ามันไม่ตรงกับสตริงภายในและไม่ตรงกันRUNโดยไม่มีหมายเลขบรรทัด

ลำดับของกลุ่มการจับกุมนั้นสำคัญ กลุ่มแรกจับคำสั่ง (หนึ่งRUN, GO SUBหรือGO TO) กลุ่มที่สองถ้าใช้จับอย่างใดอย่างหนึ่งหรือSUB TOเราไม่จำเป็นต้องจับส่วนนี้ แต่กลุ่มที่ไม่มีการจับจะต้องใช้ไบต์พิเศษ จากนั้นกลุ่มที่สามจะจับหมายเลขบรรทัด

เราใช้ฟังก์ชั่นการโทรกลับเพื่อทดแทน ด้วยฟังก์ชั่โทรกลับใน Pip, การแข่งขันทั้งหมดเป็นอาร์กิวเมนต์แรกaและกลุ่มที่จับเพื่อเป็นข้อโต้แย้งที่ตามมาb, c, และd eดังนั้นเราจึงมีคำสั่งในกลุ่มแรกที่จะไปในและหมายเลขบรรทัดในกลุ่มที่สามซึ่งจะไปในb dการเปลี่ยนแปลงเพียง (nd)แต่เราต้องการที่จะทำให้คือการผ่านหมายเลขบรรทัดผ่านฟังก์ชั่นแปลงของเราซึ่งเรียกเสียงกระเพื่อมสไตล์: จากนั้นเราก็ทำการต่อสิ่งนั้นเข้าด้วยกันด้วยbและเว้นวรรคแล้วคืนมัน

การแทนที่ครั้งที่สอง: หมายเลขบรรทัด

สิ่งที่เหลือไว้สำหรับการแปลงคือหมายเลขบรรทัดที่จุดเริ่มต้นของบรรทัด

(...) R `^\d+` n

regex ตรงกับการทำงานของตัวเลขที่จุดเริ่มต้นของบรรทัด อีกครั้งเราใช้ฟังก์ชั่นการโทรกลับ; เวลานี้ฟังก์ชั่นการแปลงnตัวเองก็เพียงพอแล้วเนื่องจากการแข่งขันทั้งหมด (อาร์กิวเมนต์แรกa ) คือจำนวนที่เราต้องการแปลง

เนื่องจากนี่เป็นนิพจน์สุดท้ายในโปรแกรม Pip จะพิมพ์ผลลัพธ์อัตโนมัติ การ-nตั้งค่าสถานะคั่นรายการผลลัพธ์ด้วยการขึ้นบรรทัดใหม่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.