Ruby (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, які покладаються на двовимірний масив, ви можете (зрештою) отримати більш коротку версію, починаючи з одновимірного масиву та працюючи зі значеннями зміщення, оскільки шаблони повторюються.
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
виглядає трохи незграбно, і ви можете зберегти 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}