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*icada vez, "en línea" las posiciones [8,10,12,22,24,26,36,38,40].
- La
offsetsmatriz se usa una vez, así que reemplace la variable con el literal.
- Reemplace
do ... endcon {...}y cambie la impresión a $> << foo. (Aquí hay un truco que involucra puts nily () == 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 injectno 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 jal comienzo del ciclo. (Tenga en cuenta que +=8evita 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+=8realidad 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 9999la final de la matriz diferencias, y añadimos a jla final , no el inicio del bucle. La justificación es que se 2,2,10,2,2,10,2,2ve muy cerca de ser los mismos 3 números repetidos 3 veces, y al calcular j+differenceal final del ciclo, el valor final de 9999no afectará realmente la salida, ya que no hay una a[j]llamada donde jhay 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+=8ahora es justa j=8, por supuesto, ya que de lo contrario agregaríamos 8demasiadas veces . También hemos cambiado la variable de bloque de jal .
Entonces, dado que el 9999elemento no tiene ningún efecto en la salida, podemos cambiarlo 10y 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=8ve un poco torpe, y puede guardar 2 caracteres al cambiar [2,2,10]hacia abajo por 2 para obtener convenientemente un 8que pueda usar para la asignación. Esto también necesita j+=lser 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_atllamada 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+ injectse puede reducir a una suma más directa con una inicial 0en 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_indexpuede 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}