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*ichaque fois, "aligner" les positions [8,10,12,22,24,26,36,38,40].
- Le
offsetstableau est utilisé une fois, alors remplacez la variable par le littéral.
- Remplacez
do ... endpar {...}et basculez l'impression vers $> << foo. (Il y a un truc ici impliquant puts nilet () == 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 injecttableau 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+=8peut ê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,2ressemble 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 9999n'affectera pas réellement la sortie, car il n'y a pas d' a[j]appel où jest 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+=8est maintenant juste j=8, bien sûr, car sinon nous en ajouterions 8trop à 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 10et 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=8apparence est un peu maladroite, et vous pouvez enregistrer 2 caractères en diminuant [2,2,10]de 2 pour obtenir facilement un que 8vous pouvez utiliser pour l'attribution. Cela doit aussi j+=ldevenir 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_atappel 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+ injectpeut être réduit à une somme plus directe avec une initiale 0dans 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_indexpeut 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}