Ruby (135 caractères)
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}
Exemple de sortie
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
Panne
Ce n'est pas trop évident comment cela fonctionne, alors voici une ventilation rapide. REMARQUE: vous pouvez probablement ignorer certaines de ces étapes et passer à des versions plus courtes plus rapidement, mais je pense que c'est assez pédagogique pour voir différentes façons dont je rase les caractères, en particulier en repérant les modèles dans les littéraux pour transformer les nombres à 2 chiffres en versions à 1 chiffre .
Version naïve
Contrairement aux autres solutions Ruby qui reposent sur un tableau bidimensionnel, vous pouvez (éventuellement) obtenir une version plus courte en commençant par un tableau unidimensionnel et en travaillant avec des valeurs de décalage, car les motifs se répètent.
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
Le principe clé ici est que nous travaillons aux positions d'index 8, 10, 12, juste compensées par des multiples de 14. Les positions 8, 10 et 12 sont les centres des grilles 3x3 que nous résumons. Dans l'exemple de sortie, 34 est la position 8, 42 est la position 8 + 14 * 1, etc. Nous remplaçons la position 8 par 34 par des positions décalées de la position 8 par [-8,-7,-6,-1,1,6,7,8]
- en d'autres termes 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8])
. Ce même principe vaut pour toutes les valeurs de [8 + 14*i, 10 + 14*i, 12 + 14*i]
, puisque le motif se répète.
L'optimiser
Tout d'abord, quelques optimisations rapides:
- Au lieu de
3.times { ... }
, et calculant à j + 14*i
chaque fois, "aligner" les positions [8,10,12,22,24,26,36,38,40]
.
- Le
offsets
tableau est utilisé une fois, alors remplacez la variable par le littéral.
- Remplacez
do ... end
par {...}
et basculez l'impression vers $> << foo
. (Il y a un truc ici impliquant puts nil
et () == nil
.)
- Noms de variables plus courts.
Le code suivant est de 177 caractères:
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)}
Pour la prochaine réduction, notez que le inject
tableau de décalages n'a pas besoin d'être en ordre. Nous pouvons avoir [-8,-7,-6,-1,1,6,7,8]
soit un autre ordre, car l'addition est commutative.
Donc, associez d'abord les points positifs et les points négatifs à obtenir [1,-1,6,-6,7,-7,8,-8]
.
Vous pouvez maintenant raccourcir
[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)
à
[1,6,7,8].flat_map { |e| [j+e, j-e] }
Il en résulte
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)}
qui est de 176 caractères.
Décaler de 8 et passer aux différences
Les valeurs littérales à deux caractères semblent pouvoir être raccourcies, alors prenez [8,10,12,22,24,26,36,38,40]
et décalez tout par le bas 8
, en mettant j
à jour au début de la boucle. (Notez que cela +=8
évite d'avoir à mettre à jour les valeurs de décalage de 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)}
C'est 179, ce qui est plus grand, mais il j+=8
peut être supprimé.
Premier changement
[0,2,4,14,16,18,28,30,32]
à un tableau de différences:
[2,2,10,2,2,10,2,2]
et ajouter cumulativement ces valeurs à une initiale j=8
. Cela couvrira éventuellement les mêmes valeurs. (Nous pourrions probablement passer directement à cela au lieu de passer de 8 en premier.)
Notez que nous ajouterons également une valeur fictive de 9999
à la fin du tableau des différences et ajouterons j
à la fin , pas au début de la boucle. La justification est que cela 2,2,10,2,2,10,2,2
ressemble terriblement aux mêmes 3 chiffres répétés 3 fois, et en calculant j+difference
à la fin de la boucle, la valeur finale de 9999
n'affectera pas réellement la sortie, car il n'y a pas d' a[j]
appel où j
est une valeur fini 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)}
Avec ce tableau de différences, le j+=8
est maintenant juste j=8
, bien sûr, car sinon nous en ajouterions 8
trop à plusieurs reprises . Nous avons également changé la variable de bloc de j
à l
.
Donc, puisque l' 9999
élément n'a aucun effet sur la sortie, nous pouvons le changer 10
et raccourcir le tableau.
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)}
C'est 170 caractères.
Mais maintenant, l' j=8
apparence est un peu maladroite, et vous pouvez enregistrer 2 caractères en diminuant [2,2,10]
de 2 pour obtenir facilement un que 8
vous pouvez utiliser pour l'attribution. Cela doit aussi j+=l
devenir 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)}
Il s'agit de 169 caractères. Un moyen détourné de presser 7 caractères, mais c'est bien.
Derniers ajustements
L' values_at
appel est en fait en quelque sorte redondant, et nous pouvons incorporer un Array#[]
appel. Donc
a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)
devient
[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)
Vous pouvez également remarquer que flat_map
+ j+e/j-e
+ inject
peut être réduit à une somme plus directe avec une initiale 0
dans le tableau.
Cela vous laisse avec 152 caractères:
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)}
Finalement:
map.with_index
peut devenir each_slice
.
- Modifiez l'approche d'impression.
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}