Ruby (135 znaków)
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}
Próbka wyjściowa
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
Awaria
To nie jest zbyt oczywiste, jak to działa, więc oto szybki podział. UWAGA: Prawdopodobnie możesz pominąć niektóre z tych kroków i szybciej przejść do krótszych wersji, ale myślę, że jest to wystarczająco edukacyjne, aby zobaczyć różne sposoby golenia znaków, szczególnie poprzez wykrywanie wzorców w literałach, aby zamieniać 2-cyfrowe liczby na 1-cyfrowe wersje .
Wersja naiwna
W przeciwieństwie do innych rozwiązań Ruby, które opierają się na dwuwymiarowej tablicy, możesz (ostatecznie) uzyskać krótszą wersję, zaczynając od tablicy jednowymiarowej i pracując z wartościami przesunięcia, ponieważ wzorce się powtarzają.
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
Kluczową zasadą jest to, że pracujemy na pozycjach indeksu 8, 10, 12, po prostu przesuniętych o wielokrotności 14. Pozycje 8, 10 i 12 są środkami sumowanych siatek 3x3. Na wyjściu próbki 34 to pozycja 8, 42 to pozycja 8 + 14 * 1 itd. Zastępujemy pozycję 8 34 pozycjami przesuniętymi od pozycji 8 o [-8,-7,-6,-1,1,6,7,8]- innymi słowy 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8]). Ta sama zasada obowiązuje dla wszystkich wartości [8 + 14*i, 10 + 14*i, 12 + 14*i], ponieważ wzorzec się powtarza.
Optymalizacja
Po pierwsze, kilka szybkich optymalizacji:
- Zamiast za każdym razem „
3.times { ... }obliczać j + 14*i” pozycje [8,10,12,22,24,26,36,38,40].
offsetsTablica jest użyta tylko raz, aby zastąpić zmienną dosłownym.
- Wymień
do ... endsię {...}i przełączyć okolice drukowanie $> << foo. (Jest tu sztuczka z udziałem puts nili () == nil.)
- Krótsze nazwy zmiennych.
Kod po tym ma 177 znaków:
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)}
Przy następnej redukcji zwróć uwagę, że injecttablica przesunięć nie musi być w porządku. Możemy mieć [-8,-7,-6,-1,1,6,7,8]albo inne zamówienie, ponieważ dodawanie jest przemienne.
Więc najpierw połącz pozytywne i negatywne [1,-1,6,-6,7,-7,8,-8].
Teraz możesz skrócić
[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)
do
[1,6,7,8].flat_map { |e| [j+e, j-e] }
To skutkuje
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)}
który ma 176 znaków.
Przesuń o 8 i przejdź do różnic
Dwuznakowe wartości literalne wydają się być możliwe do skrócenia, więc weź [8,10,12,22,24,26,36,38,40]i przenieś wszystko w dół 8, aktualizując jna początku pętli. (Należy pamiętać, że +=8unika się konieczności aktualizacji wartości przesunięcia 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)}
Jest to 179, co jest większe, ale j+=8faktycznie można je usunąć.
Pierwsza zmiana
[0,2,4,14,16,18,28,30,32]
do szeregu różnic:
[2,2,10,2,2,10,2,2]
i kumulatywnie dodaj te wartości do wartości początkowej j=8. To ostatecznie obejmie te same wartości. (Prawdopodobnie moglibyśmy przejść bezpośrednio do tego, zamiast przejść najpierw o 8).
Zauważ, że dodamy również wartość fikcyjną 9999na końcu tablicy różnic i dodamy jna końcu , a nie na początku pętli. Uzasadnieniem jest to, 2,2,10,2,2,10,2,2że okropnie zbliża się do bycia tymi samymi 3 liczbami powtarzanymi 3 razy, a obliczając j+differencena końcu pętli, ostateczna wartość 9999nie wpłynie na wynik, ponieważ nie ma a[j]wywołania, w którym jjest jakaś wartość ponad 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)}
Z tą tablicą różnic j+=8jest teraz po prostu j=8oczywiście, ponieważ w przeciwnym razie wielokrotnie dodawaliśmy 8zbyt wiele. Zmieniliśmy również zmienną blokową z jna l.
Ponieważ 9999element nie ma wpływu na wynik, możemy go zmienić 10i skrócić tablicę.
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)}
To jest 170 znaków.
Ale teraz j=8wygląda to trochę niezgrabnie i możesz uratować 2 postacie, przesuwając w [2,2,10]dół o 2, aby wygodnie uzyskać postać, 8której możesz użyć do przypisania. To też musi j+=lsię stać 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)}
To jest 169 znaków. Okrągły sposób wyciskania 7 znaków, ale jest fajny.
Ostatnie poprawki
values_atPołączenie jest rzeczywiście rodzaju zbędne i możemy inline takie Array#[]połączenie. Więc
a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)
staje się
[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)
Możesz również zauważyć, że flat_map+ j+e/j-e+ injectmożna zredukować do bardziej bezpośredniego sumowania z inicjałem 0w tablicy.
To daje ci 152 znaki:
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)}
Wreszcie:
map.with_indexmoże zostać each_slice.
- Zmień podejście do drukowania.
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}