เคล็ดลับสำหรับการเล่นกอล์ฟใน brainfuck


23

คุณมีเคล็ดลับทั่วไปอะไรในการเล่นกอล์ฟใน brainfuck? ฉันกำลังมองหาความคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะเจาะจงกับ brainfuck (เช่น "ลบความคิดเห็น" ไม่ใช่คำตอบ) กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ

คำตอบ:


25

การใส่หนึ่งเคล็ดลับต่อคำตอบจะเป็นคำตอบที่มากเกินไป

  • เรียนรู้ที่จะคิดใน Brainfuck มันแตกต่างจากสิ่งอื่นมาก อ่านและเขียนและเขียนใหม่และเขียนโปรแกรม brainfuck จำนวนมาก ภาษาไม่ได้ให้อะไรมากมายกับคุณดังนั้นจึงเป็นเรื่องสำคัญที่จะต้องใช้สิ่งที่ทำให้คุณยืดหยุ่นและมีประสิทธิภาพ อย่าปล่อยให้สิ่งที่เป็นนามธรรมอยู่ระหว่างคุณกับภาษา - เข้าไปข้างในและต่อสู้กับมัน

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

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

  • ในระดับที่ใหญ่ขึ้นให้พิจารณาและลองใช้อัลกอริทึมที่แตกต่างหลากหลาย ตอนแรกมันจะไม่ชัดเจนว่าอัลกอริทึมใดจะดีที่สุด อาจไม่ชัดเจนว่าแนวทางพื้นฐานแบบใดที่ดีที่สุดและอาจเป็นสิ่งที่แตกต่างจากสิ่งที่ดีที่สุดในภาษาปกติ

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

  • ข้อมูลเดียวกันอาจเป็นสองสิ่งที่แตกต่างกัน (ส่วนใหญ่มักเป็นตัวเลขหรือตัวอักษรและเครื่องหมายตำแหน่งที่ไม่ใช่ศูนย์ แต่ดูrandom.bโดยที่ตัวนับบิตสองเท่าเป็นค่าของเซลล์หนึ่งเซลล์ของหุ่นยนต์อัตโนมัติ)

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

  • ในภาษาส่วนใหญ่คุณใช้คอมไพเลอร์หรือล่ามบ่อยครั้งเพื่อตรวจสอบพฤติกรรมของโปรแกรมของคุณ ภาษา Brainfuck ต้องการการควบคุมแนวคิดที่มากกว่า ถ้าคุณต้องการคอมไพเลอร์เพื่อบอกคุณว่าโปรแกรมของคุณทำอะไรคุณไม่เข้าใจโปรแกรมของคุณมากพอและคุณอาจต้องจ้องมองมันมากกว่านี้ - อย่างน้อยถ้าคุณต้องการมีภาพที่ชัดเจนเพียงพอ แนวคิดที่เป็นรัศมีของโปรแกรมที่คล้ายกันจะดีในสนามกอล์ฟ ด้วยการฝึกฝนคุณจะต้องสร้างโปรแกรมของคุณเป็นโหลกว่ารุ่นก่อนที่จะลองใช้โปรแกรมหนึ่งและคุณจะมั่นใจได้ 95% ว่าโปรแกรมที่สั้นที่สุดของคุณจะทำงานอย่างถูกต้อง

  • โชคดี! มีคนเพียงไม่กี่คนที่อยากเขียน Brainfuck ให้รัดกุม แต่ฉันคิดว่านั่นเป็นวิธีเดียวที่ภาษาจะสามารถแสดงให้เห็นถึงความสนใจอย่างต่อเนื่อง - ในรูปแบบศิลปะที่ไม่ชัดเจน


3
การอ่านสิ่งนี้ทำให้ฉันต้องการลองเขียนโปรแกรมใน Brainfuck ทันที ..
Claudiu

อึศักดิ์สิทธิ์คิดว่าฉันจำชื่อของคุณได้แล้ว แฟนตัวยงของโปรแกรม brainfuck ของคุณโดยเฉพาะล่ามแปลตัวเองในระยะสั้นของคุณ!
Jo King

"คุณอาจสังเกตเห็นเป็นครั้งคราว ... ว่ามีบางส่วนเล็ก ๆ ที่สามารถลบได้ทั้งหมดไม่มีอะไรเพิ่มและสิ่งที่ตามมาจะยังคงทำงานได้อย่างไม่มีที่ติ" นี่เป็นเรื่องจริงโดยเฉพาะอย่างยิ่งสำหรับผู้เริ่มต้น ฉันเคยเขียนเพียงหนึ่งคำตอบใน BF เท่าที่ฉันจำได้ แต่ประวัติการแก้ไขของมันมีอย่างน้อย 3 กรณีที่ฉันเล่นกับโปรแกรมและสุ่มไป "เฮ้โปรแกรมยังใช้งานได้ถ้าฉันเอาบิตนี้ออก! "
ETHproductions

"ลองใช้เลย์เอาต์ที่หลากหลายของคุณในแบบที่คุณอดทน" หรือสามารถบังคับให้เดรัจฉาน : P
Esolanging Fruit

9

เคล็ดลับที่นี่:

ค่าคงที่:

Esolangs หน้าคงมีรายการที่มีประโยชน์อย่างมากในวิธีที่สั้นที่สุดในการสร้างค่าเฉพาะ ฉันพบว่าตัวเองกำลังปรึกษาหน้านี้อย่างน้อยสองครั้งต่อโปรแกรม

จุดเริ่มต้นของทุกสิ่ง:

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

ชุดนี้ติดตั้งเทปในรูปแบบ 3 * n ^ 2 ซึ่งดูเหมือน

3 6 12 24 48 96 192 128 0 0 '

ทำไมสิ่งนี้สำคัญมาก

ลองลงรายการ:

  • 3 และ 6 น่าเบื่อ
  • 12: ปิดถึง 10 (ขึ้นบรรทัดใหม่) หรือ 13 (carriage return) สามารถใช้เป็นเคาน์เตอร์สำหรับ 0-9 ได้
  • 24: ใกล้ถึง 26 จำนวนตัวอักษรในตัวอักษร
  • 48: ASCII สำหรับ 0
  • 96: ปิดถึง 97, ASCII สำหรับ a
  • 196 และ 128: 196-128 = 64 ใกล้กับ 65, ASCII Aสำหรับ

จากอัลกอริทึมนี้เราจะเริ่มต้นทุกลำดับในช่วง ASCII พร้อมกับตัวนับสำหรับแต่ละบรรทัดและบรรทัดใหม่ที่เข้าถึงได้ง่าย

ตัวอย่างการปฏิบัติ:

การพิมพ์ตัวอักษรและตัวเลขตัวพิมพ์ใหญ่และเล็กทั้งหมด

ด้วยอัลกอริทึม:

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

โดยไม่ต้อง:

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

เราใช้ไบต์ส่วนใหญ่ในการเริ่มต้นเทปในตัวอย่างที่สอง บางส่วนมันชดเชยด้วยการเคลื่อนไหวพิเศษในตัวอย่างแรก แต่วิธีนี้มีข้อดีอย่างชัดเจน

สองอัลกอริทึมที่น่าสนใจอื่น ๆ ในหลอดเลือดดำเดียวกัน:

3 * 2 ^ n + 1:

+++[[<+>>++<-]+>]
Tape: 4 7 13 25 49 65 197 129 1 0'

สิ่งนี้จะชดเชยค่าที่ 1 ซึ่งทำให้บางสิ่งสำเร็จ มันทำให้ 12 carriage return, 64 การเริ่มต้นที่แท้จริงของตัวอักษรตัวพิมพ์ใหญ่และ 24 อันใกล้ 26

2 ^ n:

+[[<+>>++<-]>]
Tape: 1 2 4 8 16 32 64 128

เนื่องจาก 64 ดีสำหรับตัวอักษรตัวพิมพ์ใหญ่ 32 คือ ASCII สำหรับเว้นวรรคและ 128 สามารถใช้เป็นตัวนับสำหรับ 26 (130/5 = 26) วิธีนี้สามารถบันทึกไบต์ในบางสถานการณ์ที่ไม่ต้องใช้ตัวเลขและตัวอักษรพิมพ์เล็ก

เลือกการใช้งานที่เหมาะสมกับคำถาม:

  • เซลล์เชิงลบมักจะเกือบตลอดเวลาประโยชน์ครั้งและไม่มีเหตุผลที่จะหลีกเลี่ยงเหล่านั้น (ยกเว้นว่ามันจะไม่เปลี่ยนจำนวนไบต์ของคุณ)
  • เกือบจะเหมือนกับสิ่งเดียวกันกับเซลล์ห่อดังนั้นยิ่งมีค่าคงที่จำนวนมากใช้การตัด
  • ขนาดของเซลล์โดยพลการนั้นมีประโยชน์สำหรับลำดับทางคณิตศาสตร์ที่ไม่มีที่สิ้นสุดเช่นการคำนวณลำดับ Fibonacci อนันต์ ( +[[-<+>>+>+<<]>]) หรือการประมวลผลจำนวนที่มากขึ้น / ลบ ข้อเสียคือวิธีการทั่วไปบางอย่างเช่น[-]และ[->+<]ไม่สามารถพึ่งพาได้ในกรณีที่จำนวนเป็นค่าลบ
  • EOF เป็น 0, -1 หรือไม่มีการเปลี่ยนแปลง 0 มักจะดีกว่าเนื่องจากคุณสามารถวนซ้ำอินพุตทั้งหมดโดยไม่มีการตรวจสอบพิเศษ -1 มีประโยชน์เมื่อวนรอบโครงสร้างอาร์เรย์ ฉันยังไม่พบการใช้งานที่ไม่เปลี่ยนแปลง :(

ติดตามสิ่งที่เกิดขึ้น frick:

ทุกครั้งที่คุณควรมีความคิดเห็นเกี่ยวกับตำแหน่งที่ตัวชี้ควรสัมพันธ์กับข้อมูลที่อยู่รอบ ๆ และตรวจสอบให้แน่ใจว่าคุณทราบช่วงของค่าที่เป็นไปได้ของแต่ละเซลล์ นี่คือโดยเฉพาะอย่างยิ่งความสำคัญเมื่อคุณแยกตัวชี้ต่อหน้าวงเนื่องจากคุณต้องการรวมความเป็นไปได้สองอย่างเข้าด้วยกันในภายหลัง

ณ จุดใดรหัสของฉันเกลื่อนไปด้วยความคิดเห็นในบรรทัดอื่น ๆ ที่มีลักษณะเช่นนี้:

*0 *dat a_1 ?  0' !0 0*
 or
*0 *dat 0' ap1 0  !0 0*

คำแนะนำพิเศษบางอย่างคือการกำหนดสัญลักษณ์ความหมายพิเศษ ในตัวอย่างข้างต้น'คือที่ชี้เป็น*วิธีการทำซ้ำในทิศทางที่?หมายความว่าเซลล์ที่มีค่าที่ไม่รู้จัก!0หมายถึงไม่ใช่ศูนย์เซลล์_แทนหา-และแทนสำหรับp+orบอกเป็นนัยว่าเทปอาจมีลักษณะเป็นตัวแทนอย่างใดอย่างหนึ่งและจำเป็นต้องได้รับการจัดการเช่นนี้

รูปแบบสัญลักษณ์ของคุณไม่จำเป็นต้องเหมือนกับของฉัน (ซึ่งมีข้อบกพร่องเล็กน้อย) เพียง แต่ต้องสอดคล้องกัน สิ่งนี้มีประโยชน์อย่างมากเมื่อทำการดีบั๊กเนื่องจากคุณสามารถเรียกใช้จนถึงจุดนั้นและเปรียบเทียบเทปจริงกับสิ่งที่คุณควรมีซึ่งสามารถชี้ให้เห็นข้อบกพร่องที่อาจเกิดขึ้นในโค้ดของคุณ


5

คำแนะนำหลักของฉันจะไม่

ตกลงคุณต้องการสิ่งที่มีประโยชน์มากกว่านั้น BF นั้นเป็นภาษาที่สั้นมาก แต่สิ่งที่ฆ่าคุณได้จริงคือเลขคณิตซึ่งจำเป็นต้องทำอย่างมีประสิทธิภาพ มันคุ้มค่าที่จะอ่านบนหน้าค่าคงที่ใน Esolang เพื่อเลือกวิธีการเขียนจำนวนมากอย่างมีประสิทธิภาพและเพื่อใช้ประโยชน์จากการห่อหากเป็นไปได้

การเข้าถึงหน่วยความจำยังมีราคาแพงมาก เนื่องจากคุณกำลังอ่านจากเทปคุณต้องจำไว้ว่าหัวของคุณเคลื่อนไหวในเวลาใดก็ตาม แตกต่างจากภาษาอื่น ๆ ที่คุณสามารถเพียงแค่เขียนa, b, cใน BF คุณจะต้องย้ายอย่างชัดเจนหัวจำนวนไบต์บางทางซ้ายหรือขวาเพื่อให้คุณจะต้องมีสติในการที่คุณเก็บสิ่งที่ ฉันค่อนข้างมั่นใจว่าการจัดระเบียบหน่วยความจำของคุณอย่างเหมาะสมที่สุดคือ NP-hard ดังนั้นขอให้โชคดีกับมัน


5

ในคำตอบนี้ฉันจะอ้างอิงเซลล์เฉพาะบนเทปหลายครั้ง ไม่สำคัญว่าจะเป็นเซลล์ใด แต่เป็นเซลล์เดียวกันตลอดทั้งคำตอบ สำหรับจุดประสงค์ของโพสต์นี้ฉันจะเรียกเซลล์นั้นว่า "ทอดด์"

เมื่อพยายามตั้งค่าเซลล์ให้มีค่าคงที่บางครั้งก็จ่ายให้ไม่จบทันที ตัวอย่างเช่นสมมติว่าคุณต้องการให้ทอดด์มี 30 ในภายหลังในรหัสของคุณ (ซึ่งอาจแก้ไขค่าของทอดด์ แต่ไม่เคยอ่าน) คุณกลับมาที่ทอดด์ หากค่าของทอดด์เป็น 0 โปรแกรมจะออก มิฉะนั้นคุณค่าของทอดด์จะถูกพิมพ์ตลอดไป

ตามที่หน้า esolangs.org ของค่าคงที่ brainfuck (ซึ่งอาจจะเป็นเรื่องของเคล็ดลับใน! ของตัวเอง) >+[--[<]>>+<-]>+ทางที่สั้นที่สุดที่จะได้รับคือ ส่วนนำ>นั้นอยู่ที่นั่นเพื่อให้แน่ใจว่าไม่มีการแก้ไขตัวชี้ทางซ้าย แต่ในกรณีนี้เราจะสมมติว่าเราไม่สนใจและวางลง เมื่อใช้รหัสนั้นรหัสของคุณจะมีลักษณะดังนี้:

+[--[<]>>+<-]>+(MISC. CODE)(GO TO TODD)[.]

คุณสามารถนึกถึงโค้ดก้อนแรกเช่นนี้:

(SET TODD TO 30)(MISC. CODE)(GO TO TODD)[.]

>+แต่จำได้ว่าตัวละครสองตัวสุดท้ายในก้อนที่: เป็นเพียงการคิดวิธีนี้:

(SET TODD TO 29)(GO TO TODD)(ADD 1 TO TODD)(MISC. CODE)(GO TO TODD)[.]

ขอให้สังเกตว่าคุณ(GO TO TODD)สองครั้ง! คุณสามารถเขียนโค้ดด้วยวิธีนี้แทน:

(SET TODD TO 29)(MISC. CODE)(GO TO TODD)(ADD 1 TO TODD)[.]
+[--[<]>>+<-](MISC. CODE)(GO TO TODD)+[.]

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


0

ทิปเล็ก ๆ น้อย ๆ สำหรับความท้าทายที่ไม่มีอินพุต คุณสามารถใช้,แทน[-]หากคุณต้องการล้างเซลล์อย่างรวดเร็วเนื่องจากล่ามส่วนใหญ่ (รวมถึง TIO.run หนึ่ง) จะตั้งค่าเนื้อหาของเซลล์ให้เป็นตัวแทน EOF เป็นศูนย์ สิ่งนี้ทำให้โปรแกรมไม่สามารถพูดได้นิดหน่อย แต่ใครสนใจเรื่องนี้ในการเขียนโค้ด

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