Ruby (135 Zeichen)
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}
Beispielausgabe
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
Nervenzusammenbruch
Es ist nicht ganz klar, wie das funktioniert. Hier ist eine kurze Übersicht. HINWEIS: Möglicherweise können Sie einige dieser Schritte überspringen und schneller zu kürzeren Versionen wechseln, aber ich denke, es ist lehrreich genug, um zu sehen, wie ich Zeichen abgeschabt habe, insbesondere, indem Muster in Literalen erkannt werden, um zweistellige Zahlen in einstellige Versionen umzuwandeln .
Naive Version
Im Gegensatz zu den anderen Ruby-Lösungen , die auf einem zweidimensionalen Array basieren, können Sie (möglicherweise) eine kürzere Version erhalten, indem Sie mit einem eindimensionalen Array beginnen und mit Versatzwerten arbeiten, da sich die Muster wiederholen.
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
Das Schlüsselprinzip hierbei ist, dass wir an den Indexpositionen 8, 10, 12 arbeiten, die nur um ein Vielfaches von 14 versetzt sind. Die Positionen 8, 10 und 12 sind die Zentren der 3x3-Gitter, die wir summieren. In der Beispielausgabe ist 34 Position 8, 42 Position 8 + 14 * 1 usw. Wir ersetzen Position 8 durch 34 durch Positionen, die von Position 8 versetzt sind, mit [-8,-7,-6,-1,1,6,7,8]
anderen Worten - 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8])
. Dasselbe Prinzip gilt für alle Werte von [8 + 14*i, 10 + 14*i, 12 + 14*i]
, da sich das Muster wiederholt.
Es optimieren
Zunächst einige schnelle Optimierungen:
- Anstelle der "Inline" -Positionen
3.times { ... }
wird j + 14*i
jedes Mal eine Berechnung durchgeführt [8,10,12,22,24,26,36,38,40]
.
- Das
offsets
Array wird einmal verwendet. Ersetzen Sie daher die Variable durch das Literal.
- Ersetzen Sie
do ... end
mit {...}
und schalten Sie den Druck auf um $> << foo
. (Es gibt hier einen Trick mit puts nil
und () == nil
.)
- Kürzere Variablennamen.
Der Code danach ist 177 Zeichen:
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)}
Beachten Sie für die nächste Reduzierung, dass inject
das Offsets-Array nicht in Ordnung sein muss. Wir können entweder eine [-8,-7,-6,-1,1,6,7,8]
oder eine andere Reihenfolge haben, da die Addition kommutativ ist.
Kombinieren Sie also zuerst die positiven und negativen Punkte, um sie zu erhalten [1,-1,6,-6,7,-7,8,-8]
.
Jetzt können Sie kürzen
[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)
zu
[1,6,7,8].flat_map { |e| [j+e, j-e] }
Das führt zu
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)}
Das sind 176 Zeichen.
Verschieben Sie um 8 und bewegen Sie sich zu Differenzen
Die zweistelligen Literalwerte scheinen verkürzt zu werden. Nehmen Sie also [8,10,12,22,24,26,36,38,40]
alles auf und verschieben Sie es nach unten 8
, j
um es am Anfang der Schleife zu aktualisieren . (Beachten Sie, dass Sie +=8
die Offsetwerte von nicht aktualisieren müssen 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)}
Das ist 179, das ist größer, aber das j+=8
kann tatsächlich entfernt werden.
Erste Änderung
[0,2,4,14,16,18,28,30,32]
zu einer Reihe von Unterschieden:
[2,2,10,2,2,10,2,2]
und addiere diese Werte kumulativ zu einer Initiale j=8
. Dies wird schließlich die gleichen Werte abdecken. (Wir könnten wahrscheinlich direkt dorthin springen, anstatt zuerst um 8 zu verschieben.)
Beachten Sie, dass wir auch einen Dummy-Wert von 9999
am Ende des Differenzen-Arrays und j
am Ende , nicht am Anfang der Schleife , hinzufügen . Die Rechtfertigung ist, dass es furchtbar ähnlich 2,2,10,2,2,10,2,2
aussieht, als wären es die gleichen 3 Zahlen, die dreimal wiederholt werden. Wenn Sie j+difference
am Ende der Schleife rechnen, hat der Endwert von 9999
keinen Einfluss auf die Ausgabe, da es keinen a[j]
Aufruf gibt, bei dem j
ein bestimmter Wert vorliegt vorbei 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)}
Mit diesem Unterschiedsarray j+=8
ist das jetzt j=8
natürlich gerade, da wir sonst immer wieder 8
zu viele hinzufügen würden . Wir haben auch die Blockvariable von j
nach geändert l
.
Da das 9999
Element keine Auswirkung auf die Ausgabe hat, können wir es ändern 10
und das Array verkürzen.
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)}
Dies sind 170 Zeichen.
Aber jetzt j=8
sieht das ein bisschen klobig aus, und Sie können 2 Zeichen speichern, indem Sie um 2 nach [2,2,10]
unten verschieben , um ein Zeichen zu erhalten, das 8
Sie für die Zuweisung verwenden können. Das muss auch j+=l
werden 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)}
Dies ist 169 Zeichen. Eine runde Sache, um 7 Charaktere zusammenzudrücken, aber es ist ordentlich.
Letzte Verbesserungen
Der values_at
Anruf ist eigentlich redundant und wir können einen Array#[]
Anruf einleiten. So
a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)
wird
[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)
Sie können auch erkennen , dass flat_map
+ j+e/j-e
+ inject
kann mit einem anfänglichen zu einer direkteren Summe reduziert wird 0
in der Anordnung.
So bleiben Ihnen 152 Zeichen:
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)}
Schließlich:
map.with_index
werden kann each_slice
.
- Ändern Sie die Druckmethode.
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}