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}
Saída de amostra
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
Demolir
Não é muito óbvio como isso funciona, então aqui está um rápido resumo. NOTA: você provavelmente pode pular algumas dessas etapas e pular para versões mais curtas mais rapidamente, mas acho que é educativo o suficiente para ver as diferentes maneiras em que raspei os caracteres, principalmente identificando padrões em literais para transformar números de 2 dígitos em versões de 1 dígito .
Versão ingênua
Diferente das outras soluções Ruby que dependem de uma matriz bidimensional, você pode (eventualmente) obter uma versão mais curta iniciando com uma matriz unidimensional e trabalhando com valores de deslocamento, uma vez que os padrões se repetem.
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
O princípio chave aqui é que estamos trabalhando nas posições 8, 10, 12 do índice, apenas compensadas por múltiplos de 14. As posições 8, 10 e 12 são os centros das grades 3x3 que estamos resumindo. Na saída de amostra, 34 é a posição 8, 42 é a posição 8 + 14 * 1, etc. Substituímos a posição 8 por 34 por posições deslocadas da posição 8 por [-8,-7,-6,-1,1,6,7,8]- em outras palavras 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8]). Esse mesmo princípio vale para todos os valores de [8 + 14*i, 10 + 14*i, 12 + 14*i], uma vez que o padrão se repete.
Otimizando
Primeiro, algumas otimizações rápidas:
- Em vez de
3.times { ... }, e calcular j + 14*icada vez, "inline" as posições [8,10,12,22,24,26,36,38,40].
- A
offsetsmatriz é usada uma vez, portanto substitua a variável pelo literal.
- Substitua
do ... endpor {...}e alterne a impressão para $> << foo. (Há um truque aqui envolvendo puts nile () == nil.)
- Nomes de variáveis mais curtos.
O código depois disso tem 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 a próxima redução, observe que injectnão é necessário que a matriz de compensações esteja em ordem. Podemos ter [-8,-7,-6,-1,1,6,7,8]ou alguma outra ordem, pois a adição é comutativa.
Então, primeiro emparelhe os pontos positivos e negativos de obter [1,-1,6,-6,7,-7,8,-8].
Agora você pode encurtar
[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)
para
[1,6,7,8].flat_map { |e| [j+e, j-e] }
Isto resulta em
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 tem 176 caracteres.
Mude para 8 e mude para diferenças
Os valores literais de dois caracteres parecem que podem ser reduzidos, então pegue [8,10,12,22,24,26,36,38,40]e mude tudo 8, atualizando jno início do loop. (Observe que +=8evita a necessidade de atualizar os valores de deslocamento 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)}
Isso é 179, que é maior, mas j+=8pode realmente ser removido.
Primeira mudança
[0,2,4,14,16,18,28,30,32]
para uma variedade de diferenças:
[2,2,10,2,2,10,2,2]
e adicione cumulativamente esses valores a uma inicial j=8. Isso acabará por cobrir os mesmos valores. (Nós provavelmente poderíamos pular direto para isso, em vez de mudar para 8 primeiro.)
Note que nós também vamos adicionar um valor fictício de 9999ao final da matriz diferenças, e adicionar jno final , não o início do loop. A justificativa é que 2,2,10,2,2,10,2,2parece muito próximo de ser os mesmos 3 números repetidos 3 vezes e calculandoj+difference no final do loop, o valor final de 9999realmente não afetará a saída, pois não há uma a[j]chamada em que haja jalgum valor. acabou 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)}
Com esse conjunto de diferenças, o j+=8agora é apenas j=8, é claro, pois caso contrário, adicionaríamos repetidamente 8muitos. Também alteramos a variável de bloco de jpara l.
Portanto, como o 9999elemento não tem efeito na saída, podemos alterá-lo para 10e encurtar a 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)}
São 170 caracteres.
Mas agora a j=8aparência é um pouco desajeitada e você pode salvar 2 caracteres deslocando [2,2,10]a tecla 2 para baixo para obter convenientemente um que 8você pode usar para atribuição. Isso também precisa j+=lse tornar 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)}
São 169 caracteres. Uma maneira geral de espremer 7 caracteres, mas é legal.
Ajustes finais
A values_atchamada é realmente redundante e podemos incorporar uma Array#[]chamada. então
a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)
torna-se
[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)
Você também pode identificar que flat_map+ j+e/j-e+inject pode ser reduzido a um somatório mais direto com uma inicial 0na matriz.
Isso deixa você com 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_indexpode se tornar each_slice.
- Mude a abordagem de impressão.
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}