ทับทิม (135 ตัวอักษร)
a=(0..48).map{rand(9)+1}
([0,0,j=8]*3).each{|l|a[j]=[0,1,6,7,8].inject{|s,e|s+a[j+e]+a[j-e]};j+=l+2}
a.each_slice(7){|r|puts"%-3s"*7%r}
ตัวอย่างผลลัพธ์
2 1 6 9 4 5 1
9 34 4 37 2 31 3
7 2 3 1 8 1 7
5 42 4 40 2 47 9
3 9 9 4 9 4 7
3 44 4 41 2 47 4
6 9 1 5 7 6 8
ชำรุด
มันไม่ชัดเจนว่ามันทำงานอย่างไรดังนั้นนี่คือการแยกย่อยอย่างรวดเร็ว บันทึก:คุณอาจข้ามขั้นตอนเหล่านี้ไปบางส่วนและข้ามไปยังเวอร์ชั่นที่สั้นกว่าได้เร็วขึ้น แต่ฉันคิดว่ามันเป็นความรู้ที่ดีพอที่จะเห็นวิธีการที่แตกต่างกันที่ฉันโกนอักขระโดยเฉพาะอย่างยิ่ง .
รุ่นที่ไร้เดียงสา
ไม่เหมือนกับโซลูชัน Ruby อื่น ๆที่ใช้อาร์เรย์สองมิติคุณสามารถ (ในที่สุด) รับรุ่นที่สั้นกว่าโดยเริ่มต้นด้วยอาร์เรย์ 1 มิติและทำงานกับค่าออฟเซ็ตเนื่องจากรูปแบบซ้ำกัน
ary=(0..48).map { rand(9) + 1 }
offsets = [-8,-7,-6,-1,1,6,7,8]
3.times do |i|
[8,10,12].each do |j|
ary[j + 14*i] = ary.values_at(*offsets.map { |e| j+14*i + e }).inject(:+)
end
end
ary.each.with_index do |e,i|
$> << ("%-3s" % e)
$> << ?\n if i % 7==6
end
หลักการสำคัญที่นี่คือเรากำลังทำงานที่ตำแหน่งดัชนี 8, 10, 12, เพียงแค่ชดเชยด้วยทวีคูณของ 14 ตำแหน่ง 8, 10 และ 12 เป็นศูนย์กลางของกริด 3x3 ที่เรากำลังสรุป ในการแสดงผลตัวอย่าง 34 เป็นตำแหน่งที่ 8 42 คือตำแหน่ง 8 + 14 * 1 ฯลฯ เราแทนตำแหน่งที่ 8 กับ 34 โดยตำแหน่งชดเชยจากตำแหน่ง 8 [-8,-7,-6,-1,1,6,7,8]
- 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8])
ในคำอื่น หลักการเดียวกันนี้มีไว้สำหรับค่าทั้งหมดของ[8 + 14*i, 10 + 14*i, 12 + 14*i]
เนื่องจากรูปแบบซ้ำ
เพิ่มประสิทธิภาพมัน
ก่อนอื่นการเพิ่มประสิทธิภาพอย่างรวดเร็ว:
- แทน
3.times { ... }
และการคำนวณj + 14*i
ในแต่ละครั้ง "อินไลน์" [8,10,12,22,24,26,36,38,40]
ตำแหน่ง
offsets
อาร์เรย์จะใช้ครั้งเดียวดังนั้นแทนที่ตัวแปรที่มีตัวอักษร
- แทนที่
do ... end
ด้วยและสลับรอบพิมพ์เพื่อ{...}
$> << foo
(มีเคล็ดลับเกี่ยวกับที่นี่puts nil
และ() == nil
)
- ชื่อตัวแปรที่สั้นกว่า
รหัสหลังจากนี้คือ177ตัวอักษร:
a=(0..48).map{rand(9)+1}
[8,10,12,22,24,26,36,38,40].each{|j|a[j]=a.values_at(*[-8,-7,-6,-1,1,6,7,8].map{|e|j+e}).inject(:+)}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
สำหรับการลดถัดไปโปรดทราบว่าinject
ไม่จำเป็นต้องมีอาร์เรย์ออฟเซ็ต เราสามารถมีได้[-8,-7,-6,-1,1,6,7,8]
หรือสั่งซื้ออื่น ๆ เนื่องจากการเพิ่มเป็นคอมมิชชัน
ดังนั้นคู่แรกขึ้นบวกและเชิงลบที่จะได้รับ [1,-1,6,-6,7,-7,8,-8]
ดังนั้นคู่แรกขึ้นบวกและเชิงลบที่จะได้รับ
ตอนนี้คุณสามารถร่น
[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)
ถึง
[1,6,7,8].flat_map { |e| [j+e, j-e] }
ผลลัพธ์นี้ใน
a=(0..48).map{rand(9)+1}
[8,10,12,22,24,26,36,38,40].each{|j|a[j]=a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
ซึ่งคือ176ตัวอักษร
เลื่อนไป 8 และย้ายไปที่ความแตกต่าง
ดูเหมือนว่าค่าตัวอักษรสองตัวที่ดูเหมือนว่าจะสั้นลงไปได้ดังนั้นรับ[8,10,12,22,24,26,36,38,40]
และเลื่อนทุกอย่างลงไปโดย8
อัพเดทj
ที่จุดเริ่มต้นของลูป (โปรดทราบว่า+=8
หลีกเลี่ยงการจำเป็นต้องอัปเดตค่าออฟเซ็ตของ1,6,7,8
)
a=(0..48).map{rand(9)+1}
[0,2,4,14,16,18,28,30,32].each{|j|j+=8;a[j]=a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
นี่คือ 179 ซึ่งใหญ่กว่า แต่ j+=8
สามารถลบออกได้จริง
การเปลี่ยนแปลงครั้งแรก
[0,2,4,14,16,18,28,30,32]
ไปยังอาร์เรย์ของความแตกต่าง:
[2,2,10,2,2,10,2,2]
และรวมเพิ่มค่าเหล่านี้เพื่อเริ่มต้น j=8
และสะสมเพิ่มค่าเหล่านี้เพื่อเริ่มต้นสิ่งนี้จะครอบคลุมค่าเดียวกันในที่สุด (เราอาจข้ามตรงไปที่สิ่งนี้แทนที่จะเปลี่ยนเป็น 8 ก่อน)
โปรดทราบว่าเราจะเพิ่มค่าตัวอย่างของ9999
ไปยังจุดสิ้นสุดของอาร์เรย์ความแตกต่างและเพิ่มj
ในตอนท้ายไม่ใช่จุดเริ่มต้นของลูป เหตุผลก็คือว่า2,2,10,2,2,10,2,2
รูปลักษณ์ชะมัดใกล้เคียงกับการเดียวกันตัวเลข 3 ซ้ำแล้วซ้ำอีก 3 ครั้งและโดยการคำนวณj+difference
ในตอนท้ายของวงมูลค่าสุดท้ายของการ9999
จะไม่ส่งผลกระทบต่อการส่งออกจริงเนื่องจากไม่มีa[j]
การเรียกร้องที่j
เป็นค่าบางอย่าง 10000
มากกว่า
a=(0..48).map{rand(9)+1}
j=8
[2,2,10,2,2,10,2,2,9999].each{|l|a[j]=a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+);j+=l}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
ด้วยความแตกต่างนี้อาร์เรย์j+=8
ตอนนี้เป็นเพียงj=8
แน่นอนเพราะมิฉะนั้นเราจะเพิ่ม8
จำนวนมากเกินไปซ้ำแล้วซ้ำอีก เราได้เปลี่ยนยังตัวแปรบล็อกจากไปj
l
ดังนั้นเนื่องจาก9999
องค์ประกอบไม่มีผลกับเอาต์พุตเราจึงสามารถเปลี่ยนเป็น10
และทำให้อาร์เรย์สั้นลง
a=(0..48).map{rand(9)+1}
j=8
([2,2,10]*3).each{|l|a[j]=a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+);j+=l}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
นี่คือ170ตัวอักษร
แต่ตอนนี้มันj=8
ดูค่อนข้างจะ clunky และคุณสามารถบันทึก 2 ตัวอักษรโดยเลื่อน[2,2,10]
ลง 2 เพื่อให้ได้สิ่งที่8
คุณสามารถใช้ในการมอบหมาย นี้ยังมีความต้องการที่จะกลายเป็นj+=l
j+=l+2
a=(0..48).map{rand(9)+1}
([0,0,j=8]*3).each{|l|a[j]=a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+);j+=l+2}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
นี่คือ169ตัวอักษร วิธีการบีบตัวอักษร 7 รอบโดยรอบ แต่ก็เรียบร้อย
ปรับแต่งสุดท้าย
การvalues_at
โทรนั้นซ้ำซ้อนจริง ๆ และเราสามารถArray#[]
โทรเข้าได้ ดังนั้น
a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)
กลายเป็น
[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)
นอกจากนี้คุณยังสามารถมองเห็นว่าflat_map
+ j+e/j-e
+ inject
สามารถลดลงสู่การสรุปโดยตรงได้มากขึ้น0
ในอาร์เรย์
สิ่งนี้ทำให้คุณมี152ตัวอักษร:
a=(0..48).map{rand(9)+1}
([0,0,j=8]*3).each{|l|a[j]=[0,1,6,7,8].inject{|s,e|s+a[j+e]+a[j-e]};j+=l+2}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
สุดท้าย:
map.with_index
each_slice
จะกลายเป็น
- เปลี่ยนวิธีการพิมพ์
135 :
a=(0..48).map{rand(9)+1}
([0,0,j=8]*3).each{|l|a[j]=[0,1,6,7,8].inject{|s,e|s+a[j+e]+a[j-e]};j+=l+2}
a.each_slice(7){|r|puts"%-3s"*7%r}