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*i
setiap waktu, "sebariskan" posisi [8,10,12,22,24,26,36,38,40]
.
- The
offsets
array digunakan sekali, sehingga mengganti variabel dengan literal tersebut.
- Ganti
do ... end
dengan {...}
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 inject
array 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 j
pada awal loop. (Perhatikan bahwa Anda +=8
tidak 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+=8
sebenarnya 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 9999
ke akhir array perbedaan, dan menambahkannya j
di akhir , bukan awal dari loop. Pembenarannya adalah bahwa 2,2,10,2,2,10,2,2
terlihat sangat dekat dengan menjadi 3 angka yang sama diulang 3 kali, dan dengan menghitung j+difference
pada akhir loop, nilai akhir dari 9999
tidak akan benar-benar mempengaruhi output, karena tidak ada a[j]
panggilan di mana j
ada 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+=8
sekarang hanya j=8
, tentu saja, karena kalau tidak kita akan berulang kali menambahkan 8
terlalu banyak. Kami juga telah mengubah variabel blok dari j
menjadi l
.
Jadi karena 9999
elemen tidak berpengaruh pada output, kita dapat mengubahnya 10
dan 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=8
tampilannya agak kikuk, dan Anda dapat menyimpan 2 karakter dengan menggeser [2,2,10]
ke bawah 2 untuk mendapatkan yang 8
dapat Anda gunakan untuk tugas. Ini juga perlu j+=l
menjadi 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_at
panggilan 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
+ inject
dapat direduksi menjadi penjumlahan yang lebih langsung dengan inisial 0
dalam 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_index
bisa 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}