ฉันนำเสนอให้คุณ 3% แรกของตัวแปลภาษา Hexagony ...
|./...\..._..>}{<$}=<;>'<..../;<_'\{*46\..8._~;/;{{;<..|M..'{.>{{=.<.).|.."~....._.>(=</.\=\'$/}{<}.\../>../..._>../_....@/{$|....>...</..~\.>,<$/'";{}({/>-'(<\=&\><${~-"~<$)<....'.>=&'*){=&')&}\'\'2"'23}}_}&<_3.>.'*)'-<>{=/{\*={(&)'){\$<....={\>}}}\&32'-<=._.)}=)+'_+'&<
ลองออนไลน์! คุณสามารถใช้งานได้ด้วยตัวเอง แต่จะใช้เวลาประมาณ 5-10 วินาที
โดยหลักการแล้วสิ่งนี้อาจเข้ากับความยาวด้าน 9 (สำหรับคะแนน 217 หรือน้อยกว่า) เพราะมันใช้เพียง 201 คำสั่งและรุ่นที่ฉันเขียนไม่ดีนัก (ความยาวด้าน 30) ต้องการเพียง 178 คำสั่ง อย่างไรก็ตามฉันค่อนข้างแน่ใจว่ามันจะใช้เวลาตลอดไปในการทำให้ทุกอย่างเข้ากันได้ดีดังนั้นฉันไม่แน่ใจว่าฉันจะลองจริงหรือไม่
มันควรจะเป็นไปได้ที่จะตีกอล์ฟในขนาด 10 เล็กน้อยโดยหลีกเลี่ยงการใช้แถวสุดท้ายหนึ่งหรือสองแถวเพื่อไม่ให้ไม่มีการลากต่อท้าย แต่จะต้องมีการเขียนซ้ำเป็นหนึ่งในเส้นทางแรก joins ใช้ประโยชน์จากมุมซ้ายล่าง
คำอธิบาย
เริ่มต้นด้วยการตีแผ่โค้ดและเพิ่มความคิดเห็นเส้นทางการควบคุม:
ยังค่อนข้างยุ่งดังนั้นนี่คือแผนภาพเดียวกันสำหรับรหัส "ไม่ถูกจับ" ที่ฉันเขียนไว้ก่อน (อันที่จริงนี่คือความยาวด้าน 20 และตอนแรกฉันเขียนรหัสที่ความยาวด้าน 30 แต่นั่นเบาบางจนไม่จำเป็น ไม่ต้องปรับปรุงความสามารถในการอ่านเลยดังนั้นฉันจึงบีบอัดมันเล็กน้อยเพื่อให้ขนาดมีความเหมาะสมมากกว่า):
คลิกเพื่อดูรุ่นที่ใหญ่กว่า
สีจะเหมือนกันทุกประการนอกเหนือจากรายละเอียดเล็กน้อยเพียงเล็กน้อยคำสั่งที่ไม่ได้ควบคุมการไหลก็เหมือนกันทุกประการ ดังนั้นฉันจะอธิบายว่ามันใช้งานได้อย่างไรตามเวอร์ชั่นที่ไม่ดีและถ้าคุณต้องการที่จะรู้ว่ากอล์ฟคนหนึ่งทำงานอย่างไรคุณสามารถตรวจสอบว่าส่วนไหนตรงกับส่วนใดในรูปหกเหลี่ยมที่ใหญ่กว่า (สิ่งที่จับได้เพียงอย่างเดียวคือรหัส golfed เริ่มต้นด้วยกระจกเพื่อให้รหัสจริงเริ่มต้นที่มุมขวาไปทางซ้าย)
อัลกอริทึมพื้นฐานคือเกือบจะเหมือนกับคำตอบ CJam ของฉัน มีความแตกต่างสองประการ:
- แทนที่จะแก้สมการเลขหกเหลี่ยมตรงกลางฉันแค่คำนวณตัวเลขหกเหลี่ยมกึ่งกลางต่อเนื่องจนกว่าจะเท่ากับหรือมากกว่าความยาวของอินพุท นี่เป็นเพราะ Hexagony ไม่มีวิธีง่ายๆในการคำนวณรากที่สอง
- แทนที่จะใส่อินพุตโดยไม่ต้องใช้คำสั่งทันทีฉันจะตรวจสอบภายหลังว่าฉันหมดคำสั่งในอินพุตและพิมพ์
.
แทนถ้ามี
นั่นหมายถึงความคิดพื้นฐานที่ทำให้เดือดร้อนลงไปที่:
- อ่านและเก็บสตริงอินพุตขณะคำนวณความยาว
- ค้นหาความยาวด้านที่เล็กที่สุด
N
(และตัวเลขหกเหลี่ยมกึ่งกลางที่เกี่ยวข้องhex(N)
) ซึ่งสามารถเก็บอินพุตทั้งหมดได้
2N-1
คำนวณขนาดเส้นผ่าศูนย์กลาง
- สำหรับแต่ละบรรทัดให้คำนวณการเยื้องและจำนวนเซลล์ (ซึ่งรวมถึง
2N-1
) พิมพ์การเยื้องพิมพ์เซลล์ (โดยใช้.
ถ้าอินพุตหมดแล้ว) พิมพ์ linefeed
โปรดทราบว่ามีเพียงไม่ Ops ดังนั้นรหัสจริงเริ่มต้นที่มุมซ้าย (คน$
ที่กระโดดข้าม>
ดังนั้นเราจริงๆเริ่มต้นบน,
ในเส้นทางสีเทาดำ)
นี่คือตารางหน่วยความจำเริ่มต้น:
ดังนั้นตัวชี้หน่วยความจำเริ่มออกบนขอบป้ายกำกับป้อนข้อมูลชี้ทิศตะวันตกเฉียงเหนือ ,
อ่านไบต์จาก STDIN หรือ a -1
ถ้าเรากด EOF เข้าไปที่ขอบนั้น ดังนั้น<
หลังจากขวาเป็นเงื่อนไขว่าเราได้อ่านอินพุตทั้งหมด ตอนนี้เรายังคงอยู่ในวงอินพุท รหัสถัดไปที่เราเรียกใช้คือ
{&32'-
นี้เขียน 32 เข้าไปในขอบป้ายพื้นที่แล้วหักจากค่าที่ป้อนเข้าในขอบป้ายกำกับdiff โปรดทราบว่าสิ่งนี้ไม่สามารถเป็นค่าลบได้เนื่องจากเรารับประกันว่าอินพุตมีเฉพาะ ASCII ที่พิมพ์ได้ มันจะเป็นศูนย์เมื่ออินพุตเป็นช่องว่าง (ดังที่ Timwi ชี้ให้เห็นสิ่งนี้จะยังคงใช้งานได้หากอินพุตสามารถมี linefeeds หรือแท็บได้ แต่มันจะตัดอักขระที่ไม่สามารถพิมพ์ออกได้อื่น ๆ ทั้งหมดด้วยรหัสอักขระที่น้อยกว่า 32) ในกรณีนั้นการ<
เบี่ยงเบนตัวชี้คำสั่ง (IP) และเส้นทางสีเทาอ่อนถูกนำ เส้นทางนั้นจะรีเซ็ตตำแหน่งของ MP ด้วย{=
แล้วอ่านอักขระถัดไป - ดังนั้นจึงเว้นช่องว่าง มิฉะนั้นถ้าตัวละครไม่ใช่ช่องว่างเราจะดำเนินการ
=}}})&'+'+)=}
นี่เป็นครั้งแรกย้ายรอบหกเหลี่ยมผ่านความยาวขอบจนกว่าจะตรงข้ามของdiff=}}}
ขอบด้วย จากนั้นก็จะสำเนาค่าจากฝั่งตรงข้ามกับความยาวของขอบเข้าไปในความยาว)&'+'+)
ขอบและเพิ่มขึ้นด้วย เราจะเห็นในไม่ช้าทำไมมันถึงสมเหตุสมผล ในที่สุดเราย้ายขอบใหม่ด้วย=}
:
(ค่าขอบโดยเฉพาะมาจากกรณีทดสอบล่าสุดที่กำหนดในการท้าทาย) ณ จุดนี้ลูปจะทำซ้ำ แต่เมื่อทุกอย่างเปลี่ยนเป็นหกเหลี่ยมทิศตะวันออกเฉียงเหนือ ดังนั้นหลังจากอ่านตัวละครอื่นเราได้สิ่งนี้:
ตอนนี้คุณจะเห็นว่าเรากำลังค่อยๆเขียนอินพุต (ลบช่องว่าง) พร้อมภาคตะวันออกเฉียงเหนือในแนวทแยงกับตัวละครในทุกขอบอื่น ๆ และมีความยาวถึงตัวละครที่ถูกเก็บไว้ขนานไปกับขอบป้ายยาว
เมื่อเราเสร็จสิ้นด้วยการวนรอบการป้อนข้อมูลหน่วยความจำจะมีลักษณะเช่นนี้ (ที่ฉันได้ติดป้ายขอบใหม่ไม่กี่สำหรับส่วนถัดไป):
%
เป็นตัวละครที่ผ่านมาเราอ่าน29
เป็นจำนวนอักขระที่ไม่ใช่พื้นที่ที่เราอ่าน ตอนนี้เราต้องการค้นหาความยาวด้านของรูปหกเหลี่ยม อันดับแรกมีรหัสการเริ่มต้นเชิงเส้นบางส่วนในเส้นทางสีเขียวเข้ม / สีเทา:
=&''3{
นี่=&
สำเนายาว (29 ในตัวอย่างของเรา) เข้าไปในขอบป้ายยาว จากนั้น''3
เลื่อนไปที่ขอบที่มีป้ายกำกับ3และตั้งค่าเป็น3
(ซึ่งเราต้องการเพียงค่าคงที่ในการคำนวณ) ในที่สุดก็{
ย้ายไปที่ขอบที่มีข้อความN (N-1)
ตอนนี้เราเข้าสู่ลูปสีน้ำเงิน การเพิ่มลูปนี้N
(เก็บไว้ในเซลล์ที่มีข้อความN ) จากนั้นคำนวณตัวเลขหกเหลี่ยมตรงกลางและลบออกจากความยาวอินพุต รหัสเชิงเส้นซึ่งทำนั่นคือ:
{)')&({=*'*)'-
นี่{)
ย้ายไปและเพิ่มN ')&(
ย้ายไปที่ขอบชื่อN-1คัดลอกN
ตรงนั้นและลดลง {=*
คำนวณผลิตภัณฑ์ของพวกเขาในN (N-1) '*)
คูณว่าด้วยค่าคงที่3
และเพิ่มผลในขอบป้ายกำกับที่ฐานสิบหก (N) อย่างที่คาดไว้นี่คือตัวเลขหกเหลี่ยมที่กึ่งกลาง Nth ในที่สุดก็'-
คำนวณความแตกต่างระหว่างนั้นกับความยาวของอินพุต หากผลลัพธ์เป็นบวกความยาวด้านยังไม่ใหญ่พอและวนซ้ำ (ที่}}
ย้าย MP กลับไปที่ขอบป้ายN (N-1) )
เมื่อความยาวด้านมีขนาดใหญ่พอความแตกต่างจะเป็นศูนย์หรือลบและเราได้สิ่งนี้:
ก่อนอื่นตอนนี้มีเส้นทางสีเขียวเชิงเส้นที่ยาวมากซึ่งทำการกำหนดค่าเริ่มต้นที่จำเป็นสำหรับลูปเอาท์พุท:
{=&}}}32'"2'=&'*){=&')&}}
การ{=&
เริ่มต้นโดยการคัดลอกผลลัพธ์ในส่วนต่างไปที่ขอบความยาวเนื่องจากเราต้องการบางสิ่งที่ไม่ใช่บวก }}}32
เขียนขอบ 32 เข้าป้ายพื้นที่ '"2
เขียนคงที่ 2 ลงไปที่ด้านไม่ติดฉลากข้างต้นต่าง '=&
คัดลอกN-1
ลงในขอบที่สองด้วยฉลากเดียวกัน '*)
คูณมันด้วย 2 และเพิ่มมันเพื่อเราจะได้ค่าที่ถูกต้องในขอบที่มีป้ายกำกับ2N-1ที่ด้านบน นี่คือเส้นผ่านศูนย์กลางของรูปหกเหลี่ยม {=&')&
สำเนาเส้นผ่าศูนย์กลางลงไปที่ด้านอื่น ๆ ที่มีข้อความ2N-1 ในที่สุดก็}}
ย้ายกลับไปที่ขอบที่มีป้ายกำกับ2N-1ที่ด้านบน
ลองติดฉลากใหม่ที่ขอบ:
ขอบที่เราอยู่ในขณะนี้ (ซึ่งยังคงมีขนาดเส้นผ่าศูนย์กลางของรูปหกเหลี่ยม) จะถูกใช้เพื่อย้ำบนบรรทัดของเอาต์พุต เยื้องที่มีป้ายกำกับขอบจะคำนวณจำนวนช่องว่างที่ต้องการในบรรทัดปัจจุบัน เซลล์ที่มีป้ายกำกับขอบจะถูกใช้เพื่อวนซ้ำจำนวนเซลล์ในบรรทัดปัจจุบัน
เราตอนนี้บนเส้นทางสีชมพูซึ่งคำนวณเยื้อง ('-
ลดจำนวนตัววนซ้ำของบรรทัดและลบออกจากN-1 (ลงในขอบเยื้อง ) สาขาสีน้ำเงิน / สีเทาสั้น ๆ ในโค้ดเพียงคำนวณโมดูลัสของผลลัพธ์ ( ~
ทำให้ค่านั้นเป็นลบหรือเป็นศูนย์ ส่วนที่เหลือของเส้นทางสีชมพู"-~{
ซึ่งจะลบการเยื้องจากเส้นผ่านศูนย์กลางเข้าสู่ขอบเซลล์แล้วจึงย้ายกลับไปที่ขอบเยื้อง
เส้นทางสีเหลืองสกปรกจะพิมพ์การเยื้อง เนื้อหาของวงเป็นเพียงแค่จริงๆ
'";{}(
ที่ที่'"
ย้ายไปที่ขอบอวกาศ;
พิมพ์มัน{}
ย้ายกลับไปเยื้องและ(
ลดลง
เมื่อเราทำเสร็จแล้วเส้นทางสีเทาเข้ม (ที่สอง) จะค้นหาอักขระถัดไปที่จะพิมพ์ การ=}
เคลื่อนไหวในตำแหน่ง (ซึ่งหมายความว่าบนขอบเซลล์ชี้ใต้) จากนั้นเรามีการวนรอบที่แน่น{}
ซึ่งเพียงแค่เคลื่อนลงสองขอบในทิศทางตะวันตกเฉียงใต้จนกระทั่งเราตีที่ส่วนท้ายของสตริงที่เก็บไว้:
โปรดสังเกตว่าฉันได้ทำการติดตั้งใหม่อีกหนึ่งEOF แล้วหรือยัง . เมื่อเราประมวลผลตัวละครนี้แล้วเราจะทำให้ค่าลบขอบนั้นเพื่อให้{}
ลูปสิ้นสุดที่นี่แทนการวนซ้ำครั้งถัดไป:
ในรหัสเราอยู่ที่จุดสิ้นสุดของเส้นทางสีเทาเข้มที่ซึ่ง'
ย้อนกลับไปหนึ่งขั้นตอนบนอักขระอินพุต หากสถานการณ์เป็นหนึ่งในสองแผนภาพสุดท้าย (เช่นยังมีตัวละครจากอินพุตที่เรายังไม่ได้พิมพ์) แสดงว่าเรากำลังเข้าสู่เส้นทางสีเขียว (ล่างสุดสำหรับผู้ที่ไม่ดีกับสีเขียวและ สีน้ำเงิน). อันนั้นค่อนข้างง่าย: ;
พิมพ์ตัวละครเอง '
ย้ายไปที่ขอบอวกาศที่สอดคล้องกันซึ่งยังคงเก็บ 32 จากก่อนหน้านี้และ;
พิมพ์พื้นที่นั้น ถ้าอย่างนั้น{~
ทำEOFของเรา? ลบสำหรับการทำซ้ำครั้งถัดไป'
ย้ายกลับขั้นตอนหนึ่งเพื่อให้เราสามารถกลับไปที่ปลายตะวันตกเฉียงเหนือของสตริงที่มี}{
วงแน่นอีก ซึ่งจบลงที่ความยาวเซลล์ (ไม่ใช่ค่าบวกด้านล่างฐานสิบหก (N)ในที่สุดก็}
ย้ายกลับไปที่ขอบเซลล์
หากเราได้ป้อนข้อมูลจนหมดแล้ววงที่ค้นหา EOF? จะยุติที่นี่จริง:
ในกรณีนั้น'
จะย้ายไปที่เซลล์ความยาวและเรากำลังใช้เส้นทางสีน้ำเงิน (บนสุด) แทนซึ่งจะพิมพ์ไม่มีตัวเลือก รหัสในสาขานี้เป็นแบบเส้นตรง:
{*46;{{;{{=
การ{*46;
เขียน 46 ลงในขอบที่ไม่มีข้อความกำกับและพิมพ์ออกมา (เช่นจุด) จากนั้น{{;
เลื่อนไปที่ขอบอวกาศแล้วพิมพ์ออกมา การ{{=
เคลื่อนที่กลับไปที่ขอบเซลล์สำหรับการทำซ้ำครั้งถัดไป
เมื่อมาถึงจุดนี้ทางเดินกลับมารวมกันและ(
ลดขอบเซลล์ หากตัววนซ้ำยังไม่เป็นศูนย์เราจะใช้เส้นทางสีเทาอ่อนซึ่งจะกลับทิศทางของ MP ด้วย=
และจากนั้นไปหาตัวอักษรถัดไปเพื่อพิมพ์
มิฉะนั้นเราถึงจุดสิ้นสุดของบรรทัดปัจจุบันและ IP จะใช้เส้นทางสีม่วงแทน นี่คือลักษณะของตารางหน่วยความจำที่จุดนั้น:
เส้นทางสีม่วงประกอบด้วย:
=M8;~'"=
=
ฝืนทิศทางของ MP อีกครั้ง M8
ตั้งค่าให้ตั้งค่าเป็น778
(เพราะรหัสตัวอักษรM
คือ77
และตัวเลขจะผนวกเข้ากับค่าปัจจุบัน) สิ่งนี้เกิดขึ้น10 (mod 256)
ดังนั้นเมื่อเราพิมพ์ด้วย;
เราจะได้รับ linefeed จากนั้น~
ทำให้ขอบติดลบอีกครั้ง'"
เลื่อนกลับไปที่เส้นขอบและ=
กลับ MP อีกครั้ง
ทีนี้ถ้าเส้นขอบเป็นศูนย์เราก็เสร็จแล้ว IP จะใช้พา ธ สีแดง (สั้นมาก) ซึ่ง@
จะยุติโปรแกรม มิฉะนั้นเราจะดำเนินต่อไปบนเส้นทางสีม่วงซึ่งวนกลับเข้าไปในสีชมพูเพื่อพิมพ์อีกบรรทัด
แผนภาพกระแสที่สร้างขึ้นด้วยการควบคุมของ Timwi HexagonyColorer แผนภาพหน่วยความจำที่สร้างขึ้นด้วยดีบักภาพของเขาในIDE ลึกลับ
abc`defg
จริง ๆ แล้วจะกลายเป็นpastebin.com/ZrdJmHiR