Ruby (135 caratteri)
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}
Uscita campione
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
Abbattersi
Non è troppo ovvio come funzioni, quindi ecco una rapida ripartizione. NOTA: Probabilmente puoi saltare alcuni di questi passaggi e passare a versioni più brevi più rapidamente, ma penso che sia abbastanza educativo vedere diversi modi in cui ho rasato i caratteri, in particolare individuando modelli in letterali per trasformare i numeri a 2 cifre in versioni a 1 cifra .
Versione ingenua
A differenza delle altre soluzioni Ruby che si basano su un array bidimensionale, è possibile (eventualmente) ottenere una versione più breve iniziando con un array monodimensionale e lavorando con valori di offset, poiché i motivi si ripetono.
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
Il principio chiave qui è che stiamo lavorando alle posizioni di indice 8, 10, 12, appena compensate da multipli di 14. Le posizioni 8, 10 e 12 sono i centri delle griglie 3x3 che stiamo riassumendo. Nell'output del campione, 34 è la posizione 8, 42 è la posizione 8 + 14 * 1, ecc. Sostituiamo la posizione 8 con 34 con posizioni sfalsate dalla posizione 8 con [-8,-7,-6,-1,1,6,7,8]
- in altre parole 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8])
. Lo stesso principio vale per tutti i valori di [8 + 14*i, 10 + 14*i, 12 + 14*i]
, poiché il modello si ripete.
Ottimizzandolo
Innanzitutto, alcune rapide ottimizzazioni:
- Invece
3.times { ... }
e calcolando j + 14*i
ogni volta, "inline" le posizioni [8,10,12,22,24,26,36,38,40]
.
- L'
offsets
array viene utilizzato una volta, quindi sostituisci la variabile con il valore letterale.
- Sostituire
do ... end
con {...}
e passare alla stampa in $> << foo
. (C'è un trucco qui che coinvolge puts nil
e () == nil
.)
- Nomi delle variabili più brevi.
Il codice dopo questo è di 177 caratteri:
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)}
Per la prossima riduzione, si noti che inject
non è necessario che l'array di offset sia in ordine. Possiamo avere [-8,-7,-6,-1,1,6,7,8]
o qualche altro ordine, poiché l'aggiunta è commutativa.
Quindi prima abbina gli aspetti positivi e quelli negativi da ottenere [1,-1,6,-6,7,-7,8,-8]
.
Ora puoi accorciare
[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)
per
[1,6,7,8].flat_map { |e| [j+e, j-e] }
Questo risulta in
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)}
che è di 176 caratteri.
Spostati di 8 e passa alle differenze
I valori letterali a due caratteri sembrano essere accorciabili, quindi prendi [8,10,12,22,24,26,36,38,40]
e sposta tutto verso il basso 8
, aggiornando j
all'inizio del ciclo. (Notare che non è +=8
necessario aggiornare i valori di offset di 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)}
Questo è 179, che è più grande, ma j+=8
può effettivamente essere rimosso.
Primo cambiamento
[0,2,4,14,16,18,28,30,32]
a una serie di differenze:
[2,2,10,2,2,10,2,2]
e aggiungere cumulativamente questi valori a un'iniziale j=8
. Questo finirà per coprire gli stessi valori. (Probabilmente potremmo saltare direttamente a questo invece di spostarci prima di 8).
Si noti che noi anche aggiungere un valore fittizio di 9999
alla fine dell'array differenze, e aggiungiamo j
alla fine , non la partenza del ciclo. La giustificazione è che 2,2,10,2,2,10,2,2
sembra terribilmente vicino ad essere gli stessi 3 numeri ripetuti 3 volte e calcolando j+difference
alla fine del ciclo, il valore finale di 9999
non influenzerà effettivamente l'output, dal momento che non c'è una a[j]
chiamata dove j
c'è un certo valore finita 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)}
Con questo array di differenze, j+=8
ora è solo j=8
, ovviamente, poiché altrimenti ne aggiungeremmo ripetutamente 8
troppe. Abbiamo anche cambiato la variabile di blocco da j
a l
.
Quindi, poiché l' 9999
elemento non ha alcun effetto sull'output, possiamo cambiarlo 10
e accorciare l'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)}
Questo è di 170 caratteri.
Ma ora j=8
sembra un po 'goffo, e puoi salvare 2 caratteri spostando in [2,2,10]
basso di 2 per ottenere convenientemente un 8
che puoi usare per il compito. Anche questo deve j+=l
diventare 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)}
Questo è di 169 caratteri. Un modo completo per spremere 7 personaggi, ma è pulito.
Modifiche finali
La values_at
chiamata è in realtà una sorta di ridondante e possiamo incorporare una Array#[]
chiamata. Così
a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)
diventa
[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)
Puoi anche individuare che flat_map
+ j+e/j-e
+ inject
può essere ridotto a una somma più diretta con un'iniziale 0
nell'array.
Questo ti lascia con 152 caratteri:
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)}
Infine:
map.with_index
può diventare each_slice
.
- Cambia l'approccio di stampa.
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}