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*ijedes Mal eine Berechnung durchgeführt [8,10,12,22,24,26,36,38,40].
- Das
offsetsArray wird einmal verwendet. Ersetzen Sie daher die Variable durch das Literal.
- Ersetzen Sie
do ... endmit {...}und schalten Sie den Druck auf um $> << foo. (Es gibt hier einen Trick mit puts nilund () == 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 injectdas 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, jum es am Anfang der Schleife zu aktualisieren . (Beachten Sie, dass Sie +=8die 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+=8kann 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 9999am Ende des Differenzen-Arrays und jam Ende , nicht am Anfang der Schleife , hinzufügen . Die Rechtfertigung ist, dass es furchtbar ähnlich 2,2,10,2,2,10,2,2aussieht, als wären es die gleichen 3 Zahlen, die dreimal wiederholt werden. Wenn Sie j+differenceam Ende der Schleife rechnen, hat der Endwert von 9999keinen Einfluss auf die Ausgabe, da es keinen a[j]Aufruf gibt, bei dem jein 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+=8ist das jetzt j=8natürlich gerade, da wir sonst immer wieder 8zu viele hinzufügen würden . Wir haben auch die Blockvariable von jnach geändert l.
Da das 9999Element keine Auswirkung auf die Ausgabe hat, können wir es ändern 10und 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=8sieht 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 8Sie für die Zuweisung verwenden können. Das muss auch j+=lwerden 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_atAnruf 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+ injectkann mit einem anfänglichen zu einer direkteren Summe reduziert wird 0in 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_indexwerden 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}