ตีแผ่ซอร์สโค้ดของ Hexagony


52

บทนำ

หากคุณไม่คุ้นเคยกับHexagonyเป็นภาษาลึกลับที่สร้างโดย Martin Büttner สิ่งนี้คือภาษานี้ยอมรับหลายรูปแบบสำหรับโปรแกรม โปรแกรมต่อไปนี้เทียบเท่าทั้งหมด:

abcdefg

และ

 a b
c d e
 f g

ดังนั้นโดยพื้นฐานแล้วรหัสนั้นถูกรีดเป็นรูปหกเหลี่ยมปกติ แต่โปรดทราบว่าการเพิ่มคำสั่งใหม่ให้กับรหัสซึ่งabcdefghจะส่งผลให้โปรแกรมดังต่อไปนี้:

  a b c
 d e f g
h . . . .
 . . . .
  . . .

ในขณะที่คุณสามารถดูขั้นตอนแรกคือการรีดรหัสลงในรูปหกเหลี่ยมและหลังจากนั้นหกเหลี่ยมที่เต็มไปด้วยไม่มี Ops ( .) ถัดไปจำนวนหกเหลี่ยมศูนย์กลาง

งานของคุณง่าย ๆ เมื่อได้รับสตริง (ซอร์สโค้ด) เอาต์พุตรหัสต้นฉบับหกเหลี่ยมแบบเต็ม

กฎระเบียบ

  • คุณอาจให้โปรแกรมหรือฟังก์ชั่น
  • ช่องว่างนำหน้าได้รับอนุญาต แต่เมื่อหกเหลี่ยมไม่หลุดออกจากรูปร่าง
  • อนุญาตให้มีช่องว่างต่อท้ายได้
  • หมายเหตุช่องว่างในโปรแกรมที่จะถูกละเลย ดังนั้นa b cเท่ากับabc
  • มีการใช้เฉพาะอักขระ ASCII ที่พิมพ์ได้ ( 32 - 126) ดังนั้นเฉพาะSpaceอักขระปกติเท่านั้นที่จะถูกละเว้น
  • สมมติว่าความยาวของสตริงมากกว่า 0
  • นี่คือดังนั้นการส่งที่มีจำนวนไบต์น้อยที่สุดจะชนะ!

กรณีทดสอบ

Input: ?({{&2'2':{):!/)'*/

Output:
  ? ( {
 { & 2 '
2 ' : { )
 : ! / )
  ' * /


Input: H;e;l;d;*;r;o;Wl;;o;*433;@.>;23<\4;*/

Output:
   H ; e ;
  l ; d ; *
 ; r ; o ; W
l ; ; o ; * 4
 3 3 ; @ . >
  ; 2 3 < \
   4 ; * /


Input: .?'.) .@@/'/ .!.>   +=(<.!)}    (  $>( <%

Output:
   . ? ' .
  ) . @ @ /
 ' / . ! . >
+ = ( < . ! )
 } ( $ > ( <
  % . . . .
   . . . .

6
นอกจากนี้ฉันไม่แน่ใจว่าคุณต้องการเป็นคนจู้จี้จุกจิกหรือไม่ แต่ backticks จะถูกละเว้นในกระบวนการกำหนดความกว้างของรหัสเพราะมันจะใส่คำอธิบายประกอบอักขระต่อไป ดังนั้นabc`defgจริง ๆ แล้วจะกลายเป็นpastebin.com/ZrdJmHiR
Martin Ender

2
@ MartinBüttnerโอ้ฉันไม่รู้เหมือนกัน :) สำหรับความท้าทายนี้ backticks จะไม่ถูกเพิกเฉย
Adnan

18
ฉันอยากเห็นคำตอบใน Hexagony สำหรับคำถามนี้
Arcturus

2
@Adnan อาจเป็นการตอบสนองที่ดีกว่าน่าจะเป็น "คุณสามารถสันนิษฐานได้ว่าอินพุตนั้นไม่มีแฟล็กการดีบัก ( `อักขระ)"
Riking

4
@Ampora ถามและคุณจะได้รับ
Martin Ender

คำตอบ:


13

Pyth, 57 54 50 49 48 46

V+UJfgh*6sUTlK-zd1_UtJ+*d-JNjd:.[K\.^TJZ=+Z+JN

ชุดทดสอบ

พิมพ์พื้นที่นำหน้าในแต่ละบรรทัด

รุ่นนี้ต้องใช้หลักฐานที่10 ^ n> = 3n (n - 1) + 1สำหรับทุกn> = 1 ขอบคุณANerdIและErickWong ที่ให้การพิสูจน์

การติดตามความไม่เท่าเทียมกันเหล่านี้: 10 ^ n> (1 + 3) ^ n = 1 + 3n + 9n (n - 1) + ... > 3n (n - 1) + 1หนึ่งสามารถเห็นว่านี่ถูกต้องสำหรับn> = 2 ตรวจสอบn = 1กรณีที่ค่อนข้างน่ารำคาญให้10> 1

อีกวิธีหนึ่งการใช้อนุพันธ์ของสมการเหล่านี้สองครั้งแสดงให้เห็นว่า10 ^ nมีอนุพันธ์อันดับสองที่มากขึ้นสำหรับn> = 1ซึ่งสามารถลดหลั่นลงไปจนถึงอนุพันธ์อันดับแรกและในที่สุดก็จะเป็นสมการดั้งเดิม

คำอธิบาย

              ##  Implicit: z=input(); Z=0
Jf...1        ##  Save to J the side length of the hexagon the code fills up
              ##  by finding the first number such that:
gh*6sUT       ##  the the T'th hexagonal number is greater than...
              ##  Computes 6 * T'th triangular number (by using sum 1..T-1) + 1
    lK-zd     ##  ...the length of the code without spaces (also save the string value to K)
V+UJ_UtJ      ##  For loop over N = [0, 1, ..., J-1, ..., 0]:
+*d-JN        ##  append J - N spaces to the front of the line
jd            ##  riffle the result of the next operation with spaces
:.[K\.yJ      ##  slice the string given by K padded to be the length of the Jth hexagon
              ##  number with noops
Z=+Z+JN       ##  from Z to Z + J + N, then set Z to be Z + J + N

2
ก่อนอื่นคุณต้องพิสูจน์ว่า ln (10) * 10 ^ n> 6n-3 (อนุพันธ์) สำหรับ n> = 1 นี่เป็นเรื่องง่ายเนื่องจากอนุพันธ์ของนิพจน์เหล่านี้คือ ln (10) ^ 2 10 ^ n และ 6 เนื่องจาก 10 ^ n เพิ่มขึ้นแบบ monotonically และ 10 ^ 1> 6 * 1, 10 ^ n มากกว่า 6n-3 สำหรับทุกคน n> = 1 คุณสามารถใช้ตรรกะเดียวกันเพื่อทำให้การพิสูจน์สมบูรณ์เป็นเวลา 10 ^ n และ 3n (n-1) +1
Arcturus

@ Ampora ขอบคุณฉันพิจารณาใช้ตราสารอนุพันธ์ แต่ดูเหมือนไม่สะอาด ฉันไม่สามารถหาวิธีที่ดีกว่านี้ได้ แต่ชื่นชมมาก!
FryAmTheEggman

ดีใจที่ได้ช่วยเหลือ Calc อาจได้รับการ realllly น่าเกลียดในบางครั้ง
Arcturus

ในลิงค์pyth.herokuapp.com/?code=etcด้านบนฉันพบว่าคอมไพเลอร์ไม่ทำงาน ...
RosLuP

1
@FryAmTheEggman มีวิธีที่ง่ายมากในการแสดงขอบเขตที่แข็งแกร่งมากขึ้น 4 ^ n> 3n (n-1) + 1 สำหรับ n> = 1 โดยไม่ต้องใช้แคลคูลัส เพียงใช้ความจริงที่ (1 + 3) ^ n = 1 + 3n + 9n (n-1) / 2 + ... โดยการขยายแบบทวินาม คำที่หนึ่งและที่สามให้ส่วนใหญ่โดยตรง 1 + 3n (n-1) ดังนั้นความไม่เท่าเทียมจึงเกิดขึ้นทันทีหากมีคำที่สามอยู่ (นั่นคือสำหรับ n> = 2) กรณีนี้เหลือเพียงกรณี n = 1 ซึ่งไม่สำคัญเนื่องจาก RHS คือ 1
Erick Wong

90

Hexagonyขนาด 271 ไบต์

ฉันนำเสนอให้คุณ 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 ลึกลับ


19
ฉันพบว่าตัวเองพูดมากเกี่ยวกับคำตอบหกเหลี่ยม: แค่นี้
Conor O'Brien

5
อืม ... แต่ .. วัด ... จิตใจ = เป่า
Adnan

ฉันหวังว่าจะมีคนทำเช่นนี้และ ... ว้าว ฉันพูดไม่ออก ที่น่ากลัว.
Arcturus

19
ขั้นตอนที่สอง - เขียนอีก 97% :)
ASCIIThenANSI

ขั้นตอนที่สาม - เป็นคำตอบด้วยไบต์น้อยที่สุด
Tom M

19

CJam, 56 52 50 48 ไบต์

ความคิดแรกของฉันคือ "เฮ้ฉันมีรหัสสำหรับสิ่งนี้แล้ว!" แต่แล้วฉันก็ไม่สามารถที่จะดึงชิ้นส่วนที่จำเป็นเข้าด้วยกันจากรหัส Ruby ได้โดยเฉพาะอย่างยิ่งเพราะพวกเขาไม่เหมาะที่จะเล่นกอล์ฟ ดังนั้นฉันลองอย่างอื่นใน CJam แทน ...

lS-{_,4*(3/mq:D1%}{'.+}wD{D(2/-z_S*D@-@/(S*N@s}/

ทดสอบที่นี่

คำอธิบาย

คณิตศาสตร์เกี่ยวกับตัวเลขหกเหลี่ยมตรงกลางก่อน ถ้าหกเหลี่ยมปกติมีความยาวด้านข้างNแล้วมันจะประกอบด้วยเซลล์ที่มีให้เท่ากับความยาวของรหัสที่มา3N(N-1)+1 kเราสามารถแก้ได้Nเพราะมันเป็นสมการกำลังสองง่าย:

N = 1/2 ± √(1/4 + (k-1)/3)

เราสามารถเพิกเฉยรูตลบได้เพราะนั่นให้ลบ N เพื่อให้มีวิธีแก้ปัญหาเราต้องการสแควร์รูทเป็นจำนวนเต็มครึ่ง หรือกล่าวอีกนัยหนึ่ง√(1 + 4(k-1)/3) = √((4k-1)/3)จำเป็นต้องเป็นจำนวนเต็ม (โชคดีที่จำนวนเต็มนี้เกิดขึ้นเป็นเส้นผ่านศูนย์กลางD = 2N-1ของรูปหกเหลี่ยมซึ่งเราจะต้องการต่อไป) ดังนั้นเราสามารถเพิ่มหนึ่งครั้งซ้ำ ๆ.จนกว่าเงื่อนไขนั้นจะเป็นไปตาม

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

lS-     e# Read input and remove spaces.
{       e# While the first block yields something truthy, evaluate the second...
  _,    e#   Duplicate the code and get its length k.
  4*(   e#   Compute 4k-1.
  3/    e#   Divide by 3.
  mq    e#   Take the square root.
  :D    e#   Store this in D, just in case we're done, because when we are, this happens
        e#   to be the diameter of the hexagon.
  1%    e#   Take modulo 1. This is 0 for integers, and non-zero for non-integers.
}{      e# ...
  '.+   e#   Append a no-op to the source code.
}w
D{      e# For every i from 0 to D-1...
  D(2/  e#   Compute (D-1)/2 = N, the side length.
  -z    e#   Subtract that from the current i and get its modulus. That's the size of the
        e#   indentation on this line.
  _S*   e#   Duplicate and get a string with that many spaces.
  D@-   e#   Subtract the other copy from D to get the number of characters of code
        e#   in the current line.
  @/    e#   Pull up the source code and split into chunks of this size.
  (S*   e#   Pull off the first chunk and riffle it with spaces.
  N     e#   Push a linefeed character.
  @s    e#   Pull up the remaining chunks and join them back into a single string.
}/

ปรากฎว่าเราไม่จำเป็นต้องใช้เลขคณิตสองเท่าเลย (ยกเว้นสแควร์รูท) เนื่องจากการคูณด้วย 4 จึงไม่มีการชนกันเมื่อหารด้วย 3 และสิ่งที่ต้องการkจะเป็นครั้งแรกที่ให้ผลเป็นสแควร์รูทจำนวนเต็ม


8

Perl, 203 200 198

รวม +1 สำหรับ -p

s/\s//g;{($l=y///c)>($h=1+3*++$n*($n-1))&&redo}$s=$_.'.'x($h-$l);for($a=$n;$a<($d=2*$n-1);$a++){$s=~s/.{$a}/$&\n/,$s=reverse($s)for 0..1}$_=join$/,map{(' 'x abs($n-$i++-1)).$_}$s=~/\S+/g;s/\S/ $&/g

ทำงานเป็น: echo abc | perl -p file.pl

วิธีการที่ไร้เดียงสามาก:

#!/usr/bin/perl -p

s/\s//g;                            # ignore spaces and EOL etc.
{                                   # find the smallest hex number:
    ($l=y///c)                      # calc string length
    > ($h=1+3*++$n*($n-1))          # 
    && redo                         # (should use 'and', but..)
}

$s = $_                             # save $_ as it is used in the nested for
   . '.' x ($h-$l);                 # append dots to fill hexagon

for ( $a = $n; $a < ($d=2*$n-1); $a++ )
{
        $s=~s/.{$a}/$&\n/,          # split lines
        $s=reverse($s)              # mirror
    for 0..1                        # twice
}

$_ = join$/,                        # join using newline
map {                               # iterate the lines
    (' 'x abs($n-$i++-1)) .$_       # prepend padding
} $s=~/\S+/g;                       # match lines

s/\S/ $&/g                          # prepend spaces to characters
                                    # -p takes care of printing $_

  • อัปเดต 200บันทึกการกำหนดตัวแปรย้ายไบต์และอีก 2 โดยละเว้นสุดท้าย;; โค้ดตัวเองต่ำกว่า 200 ไบต์ตอนนี้!
  • อัปเดต 198บันทึก 2 ไบต์โดยใช้$s=~/\S+/gแทนsplit/\n/,$s

7

JavaScript (ES6), 162 172

ฟังก์ชั่นไม่ระบุชื่อ

ขนาดหกเหลี่ยมพบการแก้ไขสมการจากวิกิพีเดีย

3*n*(n-1)-1 = l

สูตรการแก้ปัญหานั้นเป็นพื้น

n = ceil(3+sqrt(12*l-3))/6)

ด้วยพีชคณิตบางส่วนและการประมาณบางอย่าง (ขอบคุณถึง @ user18655 ด้วย) มันจะกลายเป็น

n = trunc(sqrt(l/3-1/12)+1.4999....)
s=>eval("s=s.match(/\\S/g);m=n=Math.sqrt(s.length/3-1/12)+1.49999|0;p=o=``;for(i=n+n;--i;i>n?++m:--m)for(o+=`\n`+` `.repeat(n+n-m),j=m;j--;o+=` `)o+=s[p++]||`.`")

อ่านเพิ่มเติม

s=>{
  s=s.match(/\S/g);
  m=n=Math.sqrt(s.length/3-1/12)+1.49999;
  p=o='';
  for(i=n+n; --i; i>n?++m:--m)
    for(o += '\n'+' '.repeat(n+n-m), j=m; j--; o += ' ')
      o+=s[p++]||'.';
  return o
}

ตัวอย่างข้อมูลทดสอบ (เต็มหน้าดีกว่า - เวลาทำงาน ~ 1 นาที)

f=s=>eval("s=s.match(/\\S/g);m=n=Math.sqrt(s.length/3-1/12)+1.49999|0;p=o=``;for(i=n+n;--i;i>n?++m:--m)for(o+=`\n`+` `.repeat(n+n-m),j=m;j--;o+=` `)o+=s[p++]||`.`")

t=0;
r='0';
(T=_=>t++<816?(O.innerHTML=f(r=t%10+r),setTimeout(T,20)):0)()
pre { font-size: 66% }
<pre id=O></pre>


1
คุณสามารถใช้n=...+1-1e-9|0แทนn=Math.ceil(...)การบันทึก 2 ไบต์ คุณสามารถไป ES7 และใช้**0.5แทนได้Math.sqrtแต่นั่นก็ขึ้นอยู่กับคุณ ฉันมักจะเพียงแค่ตอบคำถาม ES6 เพราะพวกเขาทำงานในเบราว์เซอร์ของฉันฮ่า ๆ !
user81655

@ user81655 คำใบ้ที่ดีขอบคุณ
edc65

5

Pyth, 52 51 ไบต์

Jfgh**3TtTl=H-zd1=+H*\.*lHTV+UJt_UJAcH]+JN+*-JNdjdG

ลองออนไลน์ ชุดทดสอบ

แต่ละบรรทัดมีหนึ่งช่องว่างพิเศษนำตามที่อนุญาตโดย OP

คำอธิบาย

 f              1          |   find first number n for which
             -zd           |           remove spaces from input
           =H              |         put result in H
          l                |       length of input without spaces
  g                        |     is less than or equal to
   h**3TtT                 |       nth centered hexagonal number
J                          | put result (hexagon side length) in J
                           |
      *lHT                 |      ten times length of input without spaces
   *\.                     |   that amount of dots
=+H                        | append to H
                           |
  UJ                       |    numbers 0 up to side length - 1
 +  t_UJ                   |   add numbers side length - 2 down to 0
V                          | loop over result
            +JN            |       current loop number + side length
         cH]               |     split to two parts at that position
        A                  |   put parts to G and H
                 -JN       |       side length - current loop number - 1
                *   d      |     that many spaces
                     jdG   |     join code on the line (G) by spaces
               +           |   concatenate parts and print

5

เรติน่า 161 ไบต์

ขอบคุณ FryAmTheEggman สำหรับการบันทึก 2 ไบต์

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

จำนวนไบต์ถือว่าการเข้ารหัส ISO 8859-1 บรรทัดแรกมีช่องว่างเดียว โปรดทราบว่าส่วนใหญ่·เป็นจุดกึ่งกลาง (0xB7)

 

^
$._$*·¶
^·¶
¶
((^·|\2·)*)·\1{5}·+
$2·
^·*
$.&$* ·$&$&$.&$* 
M!&m`(?<=(?= *(·)+)^.*)(?<-1>.)+(?(1)!)|^.+$
+m`^( *·+)· *¶(?=\1)
$& 
·
 ·
O$`(·)|\S
$1
·
.
G-2`

ลองออนไลน์!

ดี...

คำอธิบาย

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

 

แม้ว่าจะดูเหมือนไม่มากนักขั้นตอนแรกนี้จะลบช่องว่างออกจากอินพุต

^
$._$*·¶

เราเริ่มต้นด้วยการเพิ่มบรรทัดเพิ่มเติมซึ่งมีMจุดกึ่งกลางMอยู่ที่ความยาวของอินพุต (หลังจากลบช่องว่าง)

^·¶
¶

หากอินพุตเป็นอักขระตัวเดียวเราจะลบจุดกลางนั้นอีกครั้ง นี่เป็นกรณีพิเศษที่โชคร้ายที่ไม่ได้อยู่ในขั้นตอนต่อไป

((^·|\2·)*)·\1{5}·+
$2·

นี้คำนวณความยาวของด้านที่ต้องการNลบ 1 นี่คือวิธีการที่ทำงาน: 3*N*(N-1) + 1ศูนย์กลางหมายเลขหกเหลี่ยมที่มีรูปแบบ ตั้งแต่หมายเลขสามเหลี่ยมN*(N-1)/2นั่นหมายความว่าตัวเลขหกเหลี่ยมจะหกครั้งจำนวนสามเหลี่ยมแถม 1 นั่นคือสะดวกเพราะตรงกับหมายเลขสามเหลี่ยม (ซึ่งจริงๆเพียงแค่1 + 2 + 3 + ... + N) ใน regex เป็นค่อนข้างง่ายที่มีการอ้างอิงไปข้างหน้า (^·|\2·)*ตรงกับจำนวนรูปสามเหลี่ยมที่ใหญ่ที่สุดที่จะสามารถ เป็นโบนัสที่ดี$2จากนั้นจะเก็บดัชนีของหมายเลขสามเหลี่ยมนี้ หากต้องการคูณด้วย 6 เราจับภาพเป็นกลุ่ม1และจับคู่อีก 5 ครั้ง เราตรวจสอบให้แน่ใจว่ามีอย่างน้อยสองรายการ·ด้วย·และ·+. วิธีนี้ดัชนีของหมายเลขรูปสามเหลี่ยมที่พบจะไม่เพิ่มขึ้นจนกว่าจะมีหนึ่งตัวอักษรมากกว่าตัวเลขหกเหลี่ยมที่กึ่งกลาง

ในท้ายที่สุดการแข่งขันครั้งนี้จะช่วยให้เราสองน้อยกว่าด้านยาวของรูปหกเหลี่ยมที่จำเป็นในกลุ่มเพื่อให้เราเขียนว่ากลับมารวมกันกับอีกหนึ่งศูนย์จุดที่จะได้รับ$2N-1

^·*
$.&$* ·$&$&$.&$* 

สิ่งนี้ทำให้สตริงN-1จุดกึ่งกลางของเรากลายเป็นN-1ช่องว่าง2N-1จุดกึ่งกลางและN-1ช่องว่างอื่น โปรดทราบว่านี่คือการเยื้องสูงสุดตามด้วยเส้นผ่าศูนย์กลางของรูปหกเหลี่ยมตามด้วยการเยื้องอีกครั้ง

M!&m`(?<=(?= *(·)+)^.*)(?<-1>.)+(?(1)!)|^.+$

นี่เป็นเวลาที่ไม่ราบรื่น แต่โดยทั่วไปแล้วมันให้การจับคู่ที่ทับซ้อนกันทั้งหมดซึ่งเป็น a) 2N-1ตัวอักษรยาวและในบรรทัดแรกหรือ b) บรรทัดที่สอง สิ่งนี้จะขยายผลลัพธ์จากขั้นตอนก่อนหน้านี้ให้เป็นเต็มรูปแบบ เช่นการป้อนข้อมูล12345678เราจะได้รับ:

  ···
 ····
·····
···· 
···  
12345678

นี่คือเหตุผลที่เราต้องการผนวกช่องว่างในระยะก่อนหน้านี้ด้วย

+m`^( *·+)· *¶(?=\1)
$& 

วิธีนี้จะแก้ไขการเยื้องของเส้นหลังกึ่งกลางโดยการเยื้องบรรทัดใด ๆ ที่สั้นกว่าก่อนหน้านี้ซ้ำ ๆ (ละเว้นการเว้นวรรคต่อท้าย) ดังนั้นเราจึงได้รับสิ่งนี้:

  ···
 ····
·····
 ···· 
  ···  
12345678

ตอนนี้เราเพิ่งแทรกช่องว่างด้วย

·
 ·

ซึ่งทำให้เรา:

   · · ·
  · · · ·
 · · · · ·
  · · · · 
   · · ·  
12345678

ว้านั่นเสร็จแล้ว

O$`(·)|\S
$1

เวลาในการเติมสตริงการป้อนลงในจุดกึ่งกลาง สิ่งนี้ทำได้ด้วยความช่วยเหลือของสเตจการจัดเรียง เราจับคู่จุดกึ่งกลางทั้งหมดและตัวละครแต่ละตัวในบรรทัดสุดท้ายและเราเรียงลำดับตามผลลัพธ์ของการทดแทนที่กำหนด การทดแทนนั้นว่างเปล่าสำหรับตัวละครในบรรทัดสุดท้ายและ·สำหรับจุดกึ่งกลางดังนั้นสิ่งที่เกิดขึ้นคือจุดกึ่งกลางจะถูกจัดเรียงอย่างง่ายจนจบ (เนื่องจากการเรียงมีความเสถียร) สิ่งนี้จะย้ายตัวอักขระอินพุตไปที่:

   1 2 3
  4 5 6 7
 8 · · · ·
  · · · · 
   · · ·  
········

เหลืออีกสองสิ่ง:

·
.

สิ่งนี้จะเปลี่ยนจุดกึ่งกลางให้เป็นช่วงปกติ

G-2`

และนี่จะเป็นการละทิ้งบรรทัดสุดท้าย


1

JavaScript (ES6), 144 ไบต์

(s,n=1,l=0,p=0,m=s.match(/\S/g))=>m[n]?f(s,n+6*++l,l):[...Array(l+l+1)].map((_,i,a)=>a.map((_,j)=>j<l-i|j<i-l?``:m[p++]||`.`).join` `).join`\n`

ไหน\nหมายถึงอักขระ newline ที่แท้จริง ใช้เทคนิคในการสร้างรูปหกเหลี่ยมที่ก่อนหน้านี้ฉันเคยใช้กับคำตอบอื่น ๆ สำหรับ ES7 การรากที่สองจะทำงานได้สั้นกว่าวิธีแบบเรียกซ้ำ:

(s,p=0,m=s.match(/\S/g),l=(~-m.length/3)**.5+.5|0)=>[...Array(l+l+1)].map((_,i,a)=>a.map((_,j)=>j<l-i|j<i-l?``:m[p++]||`.`).join` `).join`\n`

1

Python 3 , 144 ไบต์

c=input().replace(' ','')
n=x=1
while x<len(c):x+=n*6;n+=1
c=c.ljust(x,'.')
while c:print(' '*(x-n)+' '.join(c[:n]));c=c[n:];n-=(len(c)<x/2)*2-1

ลองออนไลน์!

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

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