Ruby (135 caracteres)
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}
Salida de muestra
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
Descompostura
No es demasiado obvio cómo funciona esto, así que aquí hay un desglose rápido. NOTA: Probablemente pueda omitir algunos de estos pasos y pasar a versiones más cortas más rápidamente, pero creo que es lo suficientemente educativo como para ver las diferentes formas en que eliminé los caracteres, especialmente al detectar patrones en literales para convertir números de 2 dígitos en versiones de 1 dígito .
Versión ingenua
A diferencia de las otras soluciones de Ruby que dependen de una matriz bidimensional, puede (eventualmente) obtener una versión más corta comenzando con una matriz unidimensional y trabajando con valores de desplazamiento, ya que los patrones se repiten.
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
El principio clave aquí es que estamos trabajando en las posiciones de índice 8, 10, 12, solo compensadas por múltiplos de 14. Las posiciones 8, 10 y 12 son los centros de las cuadrículas de 3x3 que estamos resumiendo. En la salida de muestra, 34 es la posición 8, 42 es la posición 8 + 14 * 1, etc. Reemplazamos la posición 8 con 34 por las posiciones desplazadas de la posición 8 por [-8,-7,-6,-1,1,6,7,8]
- en otras palabras 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8])
. Este mismo principio es válido para todos los valores de[8 + 14*i, 10 + 14*i, 12 + 14*i]
, ya que el patrón se repite.
Optimizándolo
Primero, algunas optimizaciones rápidas:
- En lugar de
3.times { ... }
, y calculando j + 14*i
cada vez, "en línea" las posiciones [8,10,12,22,24,26,36,38,40]
.
- La
offsets
matriz se usa una vez, así que reemplace la variable con el literal.
- Reemplace
do ... end
con {...}
y cambie la impresión a $> << foo
. (Aquí hay un truco que involucra puts nil
y () == nil
).
- Nombres de variables más cortos.
El código después de esto es 177 caracteres:
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)}
Para la próxima reducción, tenga en cuenta que inject
no necesita que la matriz de compensaciones esté en orden. Podemos tener [-8,-7,-6,-1,1,6,7,8]
u otro orden, ya que la suma es conmutativa.
Así que primero empareje los aspectos positivos y negativos para obtener [1,-1,6,-6,7,-7,8,-8]
.
Ahora puedes acortar
[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)
a
[1,6,7,8].flat_map { |e| [j+e, j-e] }
Esto resulta en
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)}
que tiene 176 caracteres.
Cambia por 8 y pasa a las diferencias
Parece que los valores literales de dos caracteres se pueden acortar, así que tome [8,10,12,22,24,26,36,38,40]
y cambie todo hacia abajo 8
, actualizando j
al comienzo del ciclo. (Tenga en cuenta que +=8
evita tener que actualizar los valores de desplazamiento 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)}
Esto es 179, que es más grande, pero en j+=8
realidad se puede eliminar.
Primer cambio
[0,2,4,14,16,18,28,30,32]
a una serie de diferencias:
[2,2,10,2,2,10,2,2]
y acumulativamente agregue estos valores a una inicial j=8
. Esto eventualmente cubrirá los mismos valores. (Probablemente podríamos pasar directamente a esto en lugar de cambiar por 8 primero).
Tenga en cuenta que vamos a añadir un valor ficticio de 9999
la final de la matriz diferencias, y añadimos a j
la final , no el inicio del bucle. La justificación es que se 2,2,10,2,2,10,2,2
ve muy cerca de ser los mismos 3 números repetidos 3 veces, y al calcular j+difference
al final del ciclo, el valor final de 9999
no afectará realmente la salida, ya que no hay una a[j]
llamada donde j
hay algún valor terminado 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 esta matriz de diferencias, j+=8
ahora es justa j=8
, por supuesto, ya que de lo contrario agregaríamos 8
demasiadas veces . También hemos cambiado la variable de bloque de j
al
.
Entonces, dado que el 9999
elemento no tiene ningún efecto en la salida, podemos cambiarlo 10
y acortar la matriz.
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)}
Esto es 170 caracteres.
Pero ahora se j=8
ve un poco torpe, y puede guardar 2 caracteres al cambiar [2,2,10]
hacia abajo por 2 para obtener convenientemente un 8
que pueda usar para la asignación. Esto también necesita j+=l
ser 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)}
Esto es 169 caracteres. Una forma redonda de exprimir 7 caracteres, pero es genial.
Ajustes finales
La values_at
llamada es en realidad algo redundante, y podemos hacer una Array#[]
llamada en línea . Entonces
a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)
se convierte
[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)
También puede detectar que flat_map
+ j+e/j-e
+ inject
se puede reducir a una suma más directa con una inicial 0
en la matriz.
Esto te deja con 152 caracteres:
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)}
Finalmente:
map.with_index
puede llegar a ser each_slice
.
- Cambiar el enfoque de impresión.
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}