Ruby (135 karakter)
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}
Output sampel
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
Kerusakan
Tidak terlalu jelas bagaimana ini bekerja, jadi inilah uraian singkatnya. CATATAN: Anda mungkin dapat melewati beberapa langkah ini dan melompat ke versi yang lebih pendek dengan lebih cepat, tetapi saya pikir ini cukup mendidik untuk melihat berbagai cara saya mencukur karakter, terutama dengan melihat pola dalam literal untuk mengubah angka 2 digit menjadi versi 1 digit .
Versi naif
Berbeda dengan solusi Ruby lainnya yang mengandalkan array dua dimensi, Anda (akhirnya) bisa mendapatkan versi yang lebih pendek dengan memulai dengan array 1 dimensi dan bekerja dengan nilai offset, karena pola-pola tersebut berulang.
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
Prinsip utama di sini adalah bahwa kami bekerja pada posisi indeks 8, 10, 12, hanya diimbangi dengan kelipatan 14. Posisi 8, 10 dan 12 adalah pusat dari kisi 3x3 yang kami simpulkan. Dalam output sampel, 34 adalah posisi 8, 42 adalah posisi 8 + 14 * 1, dll. Kami mengganti posisi 8 dengan posisi 34 dengan mengimbangi dari posisi 8 dengan [-8,-7,-6,-1,1,6,7,8]- dengan kata lain 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8]). Prinsip yang sama berlaku untuk semua nilai[8 + 14*i, 10 + 14*i, 12 + 14*i] , karena polanya berulang.
Mengoptimalkannya
Pertama, beberapa optimisasi cepat:
- Dari pada
3.times { ... } , dan menghitung j + 14*isetiap waktu, "sebariskan" posisi [8,10,12,22,24,26,36,38,40].
- The
offsetsarray digunakan sekali, sehingga mengganti variabel dengan literal tersebut.
- Ganti
do ... enddengan {...}dan beralih ke pencetakan $> << foo. (Ada trik di sini yang melibatkanputs nil dan () == nil.)
- Nama variabel lebih pendek.
Kode setelah ini adalah 177 karakter:
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)}
Untuk reduksi berikutnya, perhatikan bahwa injectarray offset tidak perlu berurutan. Kami dapat memiliki [-8,-7,-6,-1,1,6,7,8]atau memesan lainnya, karena penambahan bersifat komutatif.
Jadi pertama-tama pasangkan hal positif dan negatif untuk didapatkan [1,-1,6,-6,7,-7,8,-8].
Sekarang Anda bisa mempersingkat
[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)
untuk
[1,6,7,8].flat_map { |e| [j+e, j-e] }
Ini menghasilkan
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)}
yaitu 176 karakter.
Bergeser 8 dan pindah ke perbedaan
Nilai-nilai literal dua karakter sepertinya dapat dipersingkat, jadi ambil [8,10,12,22,24,26,36,38,40]dan geser semuanya dengan 8, memperbarui jpada awal loop. (Perhatikan bahwa Anda +=8tidak perlu memperbarui nilai ofset dari 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)}
Ini 179, yang lebih besar, tetapi j+=8sebenarnya bisa dihilangkan.
Perubahan pertama
[0,2,4,14,16,18,28,30,32]
ke berbagai perbedaan:
[2,2,10,2,2,10,2,2]
dan secara kumulatif menambahkan nilai-nilai ini ke awal j=8. Ini pada akhirnya akan mencakup nilai yang sama. (Kami mungkin bisa langsung beralih ke ini alih-alih menggeser 8 terlebih dahulu.)
Perhatikan bahwa kami juga akan menambahkan nilai dummy 9999ke akhir array perbedaan, dan menambahkannya jdi akhir , bukan awal dari loop. Pembenarannya adalah bahwa 2,2,10,2,2,10,2,2terlihat sangat dekat dengan menjadi 3 angka yang sama diulang 3 kali, dan dengan menghitung j+differencepada akhir loop, nilai akhir dari 9999tidak akan benar-benar mempengaruhi output, karena tidak ada a[j]panggilan di mana jada beberapa nilai selesai 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)}
Dengan array perbedaan ini, j+=8sekarang hanya j=8, tentu saja, karena kalau tidak kita akan berulang kali menambahkan 8terlalu banyak. Kami juga telah mengubah variabel blok dari jmenjadi l.
Jadi karena 9999elemen tidak berpengaruh pada output, kita dapat mengubahnya 10dan mempersingkat array.
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)}
Ini adalah 170 karakter.
Tapi sekarang j=8tampilannya agak kikuk, dan Anda dapat menyimpan 2 karakter dengan menggeser [2,2,10]ke bawah 2 untuk mendapatkan yang 8dapat Anda gunakan untuk tugas. Ini juga perlu j+=lmenjadi 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)}
Ini adalah 169 karakter. Cara memutar untuk memeras 7 karakter, tapi rapi.
Tweak terakhir
The values_atpanggilan sebenarnya semacam berlebihan, dan kami dapat inline sebuah Array#[]panggilan. Begitu
a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)
menjadi
[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)
Anda juga dapat mengetahui bahwa flat_map+ j+e/j-e+ injectdapat direduksi menjadi penjumlahan yang lebih langsung dengan inisial 0dalam array.
Ini memberi Anda 152 karakter:
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)}
Akhirnya:
map.with_indexbisa menjadi each_slice.
- Ubah pendekatan pencetakan.
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}