Números explodindo

25

sandbox (excluído)

Vamos definir uma matriz de 9s como:

N=[999999999]

Vamos definir um número explodindo como um número na posição (x,y) que pode ser decomposto em números inteiros iguais entre todos os seus vizinhos adjacentes (incluindo a si próprio) e o valor absoluto de cada parte é maior que 0.

A partir da matriz anterior, vamos explodir o número na posição (1,1) (0 indexado)

N=[999999999]
N=[9+19+19+19+10 0+19+19+19+19+1]

N=[10101010110101010]

Às vezes, a decomposição resulta em um número racional maior que 1. Isso é algo que precisamos evitar ao explodir números. Nesse caso, o restante será atribuído ao número explodido.

Para demonstrá-lo, vamos continuar trabalhando com nossa matriz anterior. Desta vez, explodiremos o número na posição (0 0,0 0)

N=[10101010110101010]

Aqui temos 3 neightbors e o próprio número. Aqui, a equação é algo como 10/4 que nos dão 2 para cada um e 2 como restante.

N=[2+210+21010+21+210101010]

N=[4121012310101010]

Além disso, às vezes um número não será grande o suficiente para ser decomposto em partes iguais (onde o abs é maior que 0) entre seus vizinhos (| número racional | <1). Nesses casos, precisamos "emprestar" do número explodido para manter a condição "maior que 0" . Vamos continuar com o exemplo anterior e explodir o número na posição (1,1) .

N=[4121012310101010]

N=[4+112+110+112+10+1610+110+110+110+1]
N=[5131113511111111]


O desafio é que, dada uma lista de posições (x,y) e uma matriz finita não vazia de números naturais, retorne a forma explodida após a explosão de cada número da lista de posições.


Casos de teste

Entrada: initial matrix: [[3, 3, 3], [3, 3, 3], [3, 3, 3]], numbers: [[0,0],[0,1],[0,2]]

Saída: [[1, 0, 1], [5, 6, 5], [3, 3, 3]]


Entrada: Initial matrix: [[9, 8, 7], [8, 9, 7], [8, 7, 9]], numbers: [[0,0],[1,1],[2,2]]

Saída: [[4, 11, 8],[11, 5, 10],[9, 10, 4]]


Entrada: Initial matrix: [[0, 0], [0, 0]], numbers: [[0,0],[0,0],[0,0]]

Saída: [[-9, 3],[3, 3]]


Entrada: Initial Matrix: [[10, 20, 30],[30, 20, 10],[40, 50, 60]], numbers: [[0,2],[2,0],[1,1],[1,0]]

Saída: [[21, 38, 13], [9, 12, 21], [21, 71, 64]]


Entrada: Initial Matrix: [[1]], numbers: [[0,0]]

Saída: [[1]]


Entrada: Initial Matrix: [[1, 2, 3]], numbers: [[0,0], [0, 1]]

Saída: [[1, 1, 4]]


Notas

  • Aplicam- se regras de entrada / saída

  • Você pode assumir que a matriz de entrada nunca estará vazia

  • Você pode assumir que as coordenadas sempre serão válidas

  • A coordenada de entrada nos casos de teste é fornecida como (linha, coluna). Se você precisar que seja (x, y), poderá trocar os valores. Em caso afirmativo, indique que em sua resposta

Luis felipe De jesus Munoz
fonte
novo no código de golfe; em que formato a amostra pode receber essas matrizes? Algum formato que existe no idioma? Formulário de string exatamente como está escrito?
rtpax 20/02
1
Sugiro adicionar um caso de teste para matrizes não quadradas.
Οurous 20/02
@Ourous uh oh, eu estava escrevendo meu programa assumindo que eles eram garantidos, de volta à prancheta, eu acho
rtpax
Podemos assumir que o tamanho da matriz é de pelo menos 2 por 2? Ou uma matriz 1 por 1 também pode ser inserida?
Kevin Cruijssen em 21/02
@rtpax Qualquer formato, a menos que a pergunta indique o contrário, sim
somente ASCII

Respostas:

9

C (GCC) 220 216 214 212 bytes

crédito para @ceilingcat por 2 bytes

#define L(v)for(int v=2;~v--;)
#define P l/C+r<0|l/C+r>=R|l%C+c<0|l%C+c>=C
f(int R,int C,int*m){for(int*i=m+R*C;~*i;) {int*M,l=*i+++C**i++,a=0,b;L(r)L(c)P?:++a;M=m+l;b=*M/a;b+=!b;*M- =b*a;L(r)L(c)M[r*C+c]+=P?0:b;}}

Execute aqui

uma versão um pouco menos golfe

#define L(v)for(int v=2;~v--;)
#define P l/C+r<0|l/C+r>=R|l%C+c<0|l%C+c>=C
f(int R, int C, int*m) {
    for(int*i=m+R*C;~*i;) {
        int*M,l=*i+++C**i++,a=0,b;
        L(r)
            L(c)
                P?:++a;
        M=m+l;
        b=*M/a;
        b+=!b;
        *M-=b*a;
        L(r)
            L(c)
                M[r*C+c]+=P?0:b;
    }
}

O código de chamada com um exemplo

int main()
{
  int matrix[] = {3,3,3,3,3,3,3,3,3,0,0,0,1,0,2,-1};
  int rows = 3;
  int columns = 3;
  f(rows,columns,matrix);
  for(int r = 0; r < rows; ++r) {
    for(int c = 0; c < columns; ++c) {
      printf("%03d,",matrix[r*columns + c]);
    }
    printf("\n");
  }
}

e a saída

001,005,003,
000,006,003,
001,005,003,
rtpax
fonte
11
Bem-vindo ao PPCG :)
Shaggy
198 bytes
ceilingcat
7

JavaScript (ES7),  126 125 123  121 bytes

Guardado 2 bytes graças a @Shaggy

Toma entrada como (matrix)(list). Saídas modificando a matriz.

m=>a=>a.map(([Y,X])=>(g=n=>m[m.map((r,y)=>r.map((_,x)=>(x-X)**2+(y-Y)**2<3&&r[n++,x]++)),(m[Y][X]+=~n)<n||g``,Y][X]++)``)

Experimente online!

Quão?

(x,y)

  1. n
  2. m(x,y)/nq
  3. percorra a matriz novamente para atualizar cada vizinho
  4. m(x,y)

Em vez disso, usamos uma função recursiva que executa um fluxo de operações mais simples, repetido quantas vezes for necessário:

  1. n0 0
  2. n+1
  3. n
  4. incrementa a célula de referência (todas as etapas desse tipo são executadas sucessivamente quando a última chamada recursiva é concluída)

O principal benefício é que precisamos apenas de um loop sobre a matriz. O segundo benefício é que não precisamos calcular nenhum quociente.

Exemplo

M=(0 00 00 00 0260 00 00 00 0) e (x,y)=(1,1)

Após a etapa 1 da primeira iteração , temos:

M=(1111271111) e n=9

E após a etapa 2 da primeira iteração :

M=(1111171111)

-9+1

26

179 , fazemos uma chamada recursiva.

Após a etapa 1 da segunda iteração , temos:

M=(2222182222) e n=9

E após a etapa 2 da segunda iteração :

M=(222282222)

8<9 , então paramos por aí.

Agora, incrementamos a célula de referência duas vezes ( etapa 4 de ambas as iterações ), levando ao resultado final:

M=(2222102222)

Comentado

m => a =>                     // m[] = input matrix, a[] = list of positions
  a.map(([Y, X]) => (         // for each pair (X, Y) in a[]:
    g = n =>                  //   g = recursive function expecting n = 0
      m[                      //
        m.map((r, y) =>       //     for each row r[] at position y in m[]:
          r.map((_, x) =>     //       for each value at position x in r[]:
            (x - X) ** 2 +    //         if the quadrance between (x, y)
            (y - Y) ** 2 < 3  //         and (X, Y) is less than 3:
            && r[n++, x]++    //           increment n and increment r[x]
          )                   //       end
        ),                    //     end
        (m[Y][X] += ~n)       //     subtract n + 1 from m[Y][X]
        < n                   //     if the result is greater than or equal to n:
        || g``,               //       do a recursive call
        Y                     //     
      ][X]++                  //     increment m[Y][X]
    )``                       //   initial call to g
  )                           // end
Arnauld
fonte
1
Você pode salvar alguns bytes substituindo as duas ocorrências (0)por 2 backticks.
Shaggy
6

R , 163 162 161 159 155 146 bytes

function(m,l){for(e in l){v=m[i<-e[1],j<-e[2]];s=m[x<--1:(i<dim(m))+i,y<--1:(j<ncol(m))+j];z=sum(1|s);d=max(1,v%/%z);m[x,y]=s+d;m[i,j]=v+d-d*z};m}

Experimente online!

Explicação

(Corresponde a uma versão anterior do código)

function(m,l) {          # Take input as matrix m and 1-indexed list of explosion points l
  for(e in l) {          # Loop over the list of explosion points
    i=e[1]; j=e[2]       # Assign current coordinates to (i,j) for brevity
    x=-1:1+i             # Assign the ranges of neighboring cells: (i-1) to (i+1),
    y=-1:1+j             # and (j-1) to (j+1)
    s=                   # Take the submatrix s=m[x,y]
      m[x<-x[x<=dim(m)]  # But first trim x and y from above to prevent out of bounds errors,
     ,y<-y[y<=ncol(m)]]  # trimming from below isn't necessary, as R tolerates index 0
    z=sum(1|s)           # Count the neighbors
    d=max(1,m[i,j]%/%z)  # Estimate, how much we'll distribute to each neighbor
    m[x,y]=s+d           # Add the distributed amount to each cell of the submatrix
    m[i,j]=m[i,j]-d*z    # Subtract the total amount from the exploded cell
  }
  m                      # Return the modified matrix
}
Kirill L.
fonte
4

Limpo , 181 167 bytes

import StdEnv;

foldl\m(x,y)={{if(d>2)0b+e-if(d>0)0b*n\\e<-:l&v<-[0..],let{b=max m.[y,x]n/n;$a b=2+sign a-(a+1)/size b;n= $x l* $y m;d=(v-x)^2+(u-y)^2}}\\l<-:m&u<-[0..]}

Experimente online!

Na forma de uma função parcialmente aplicada literal.

Expandido (primeira versão):

f // functinon f on {{Int}} and [(Int,Int)]
    = foldl \m (x, y) // fold :: (a -> b -> a) a [b] -> a with first argument \ {{Int}} (Int,Int) -> {{Int}} giving \ {{Int}} [(Int,Int)] -> {{Int}}
        = {                     // an array of
            {                   // arrays of
                if(d > 2) 0 b   // the amount we give to the neighbors
                + e             // plus the current entry
                - if(d > 0) 0 b // minus the amount taken from the target entry
                * n             // times the number of neighbors, if we're on the target
            \\                  // for each
                e <-: l         // element of row l
                & v <- [0..]    // and x-index v
                , let           // local definitions:
                    b           // the amount given to the neighbors
                        = max   // we need at least 1 each, so take the largest of
                            m.[y, x] // the target entry
                            n   // or the number of neighbors
                        / n     // divide it by the number of neighbors
                    n           // the number of neighbors
                        = (     // sum of
                            1   // one
                            + s x // if x is at the left edge = 0 else 1
                            + s ( // if x is at the right edge = 0 else 1
                                size l
                                - x 
                                - 1
                            )
                        ) * (   // times the sum of
                            1   // one
                            + s y // if y is at the top edge = 0 else 1
                            + s ( // if y is at the bottom edge = 0 else 1
                                size m
                                - y
                                - 1
                            )
                        )
                    d           // distance from the target point
                        = (v - x)^2
                        + (u - y)^2
            }
        \\                      // for each
            l <-: m             // row l in matrix m
            & u <- [0..]        // and y-index u
        }
Furioso
fonte
4

Ferrugem - 295 bytes

fn explode(p:(i8,i8),v:&mut Vec<Vec<i8>>){let x=v[p.0 as usize][p.1 as usize];let q=|x,y|x*x+y*y;loop{let mut t=0;for i in 0..v.len(){for j in 0..v[i].len(){if q(i as i8-p.0,j as i8-p.1)<3{v[i][j]+=1;v[p.0 as usize][p.1 as usize]-=1;t+=1;}}}if v[p.0 as usize][p.1 as usize]<=(x/t+x%t){break;}}}

Isso é muito longo devido ao Rust exigir indexação de números inteiros não assinados, mas exigir que números inteiros assinados realizem subtrações, resultando em negativos. No entanto, acredito que meu algoritmo é o "algoritmo mais curto" até agora. Na verdade, não há necessidade de lidar com a detecção de bordas, fundo, etc.

Observe três coisas: uma, a soma de todas as células é sempre constante. Segundo, essa é uma situação de divisão / restante, para que possamos aplicar o pensamento no estilo do algoritmo de Bresenham. Terceiro, a pergunta sempre adiciona o mesmo número a todas as células a uma certa distância da célula de posição especial, antes de lidar com o material "extra" na posição especial.

Algoritmo:

Armazene o valor original da célula na posição P em M.

Iniciar loop:

Itere sobre cada célula I na matriz. Se a posição da célula I estiver a 3 Quadrance (distância ao quadrado) da posição P, subtraia 1 da célula P e adicione 1 à célula I. Conte quantas vezes isso é feito em uma iteração na matriz.

Se o valor restante na célula na posição P for menor ou igual a M / Count + M modulo Count, interrompa o loop. Caso contrário, execute o loop novamente.

A matriz resultante será a versão explodida. Contar é basicamente uma maneira de contar vizinhos sem lidar com arestas. Looping é uma maneira de decompor o material de divisão / adição em uma adição / subtração única e repetida de um. A verificação do módulo garante que teremos o restante apropriado na posição P para lidar com as 'explosões' que não são igualmente divisíveis entre os vizinhos. A estrutura do loop do / while permite que P <0 funcione corretamente.

Versão não destruída no Rust Playground

não brilhante
fonte
1
Um nome de função tão longo não é necessário, qualquer um byter como o ffaria. Mas você provavelmente poderia salvar ainda mais bytes usando uma função anônima:|p:(i8,i8),v:&mut Vec<Vec<i8>>|{...}
Kirill L.
3

Java 10, 194 193 191 190 184 182 171 bytes

M->C->{for(var q:C){int n,X=q[0],Y=q[1],x,y,c=0;do{c++;x=n=0;for(var r:M){y=0;for(int $:r)r[y]+=Math.hypot(x-X,y++-Y)<2?++n/n:0;x++;}}while((M[X][Y]+=~n)>=n);M[X][Y]+=c;}}

Porta iterativa da resposta JavaScript de @Arnauld .
-17 bytes graças a @Arnauld .

Modifica a matriz de entrada em vez de retornar uma nova para salvar bytes.

Experimente online.

Explicação:

M->C->{                      // Method with two integer-matrix parameters and no return-type
  for(var q:C){              //  Loop over the coordinates:
    int n,                   //   Count integer
        X=q[0],Y=q[1],       //   The current X,Y coordinate
        x,y,                 //   Temp x,y coordinates
        c=0;                 //   Counter, starting at 0
    do{                      //   Do-while:
      c++;                   //    Increase the counter `c` by 1
      x=n=0;                 //    (Re)set both `x` and the count `n` to 0
      for(var r:M)           //    Loop over the rows `r`:
        y=0;                 //     (Re)set `y` to 0
        for(int $:r)         //     Loop over the cells of the current row:
          r[y]+=             //      Increase the value at x,y by:
            Math.hypot(      //       If the hypot (builtin for `sqrt(a*a, b*b)`) of:
              x-X,           //        the difference between `x` and `X`,
                  y++-Y)     //        and difference between `y` and `Y`
                             //        (and increase `y` by 1 afterwards with `y++`)
              <2?            //       Is smaller than 2:
                 ++n/n       //        Increase count `n` and the value at x,y both by 1
                :            //       Else:
                 0;          //        Leave the value at x,y the same by increasing by 0
       x++;}}                //     Increase `x` by 1
    while((M[X][Y]+=~n)      //    Decrease the value at X,Y by n+1
          >=n);              //    Continue the do-while if this new value is still larger
                             //    than or equal to count `n`
    M[X][Y]+=c;}}            //   Increase the value at X,Y with counter `c`
Kevin Cruijssen
fonte
1
m[y]ym[y][x]y
@ Arnauld Ah ok. Na verdade, lembrei-me dos limites normalmente não é um problema no JS, mas posso entender por undefined[x]que falharia. De qualquer forma, seu (x-X)**2+(y-Y)**2<3cheque é bastante inteligente. É preciso lembrar que quando eu quiser verificar valores em uma matriz em um bloco 3x3 (e dentro dos limites) ao seu redor. Eu acho que realmente tenho algumas respostas como essa, onde agora uso o try-catch e, em um caso, o try-finalmente.
Kevin Cruijssen em 21/02
1
171 bytes com aprimorado para loops.
Arnauld
@ Arnauld Oh, bom. Agora que eu vê-lo Eu não posso acreditar que eu não tinha pensado nisso quando eu criei uma porta de sua resposta, desde que você faça o mesmo ..>>;.)
Kevin Cruijssen
2

Lisp comum , 498 bytes

(defmacro s(l c x)`(incf(aref m,l,c),x))
(defmacro w(a &rest f)`(if(,a(or(= l 0)(= l(d 0)))(or(= c 0)(= c(d 1)))),@f))
(defmacro d(n)`(1-(array-dimension m,n)))
(defmacro p(i l m &rest f)`(loop for,i from(1-,l)to(1+,l)when(and(>=,i 0)(<=,i,m))do,@f))
(defmacro g()`(or(p i l(d 0)(p j c(d 1)(s i j 1)))(s l c(- v))))
(defun f(m l c)(let((v(w and 4(w or 6 9))))(if (<(/(s l c 0)v)1)(g)(loop for i to(1-(/(s l c 0)v))do(g)))))
(defun c(m n)(dotimes(i(length n))(f m(nth 0(nth i n))(nth 1(nth i n))))m)

Experimente online!

Use esta função como (print (c #2A((3 3 3) (3 3 3) (3 3 3)) '((0 0)(0 1)(0 2))))

Versão melhor legível:

(defmacro s (l c x)
  `(incf (aref m ,l ,c) ,x))

(defmacro w (a &rest f)
  `(if (,a (or (= l 0)
           (= l (d 0)))
       (or (= c 0)
           (= c (d 1))))
       ,@f))

(defmacro d (n)
  `(1- (array-dimension m ,n)))

(defmacro p (i l m &rest f)
  `(loop for ,i from (1- ,l) to (1+ ,l)
     when (and (>= ,i 0) (<= ,i ,m))
     do ,@f))

(defmacro g ()
  `(or(p i l (d 0)
     (p j c (d 1)
        (s i j 1)))
      (s l c (- v))))

(defun f (m l c)
  (let ((v (w and 4 (w or 6 9))))
    (if (< (/ (s l c 0) v) 1)
    (g)
      (loop for i to (1- (/ (s l c 0) v))
        do (g)))))

(defun c (m n)
  (dotimes (i (length n))
    (f m (nth 0 (nth i n))
       (nth 1 (nth i n))))
  m)

Exemplo de saída:

(print (c #2A((3 3 3) (3 3 3) (3 3 3) (3 3 3) (3 3 3) (3 3 3)) '((5 0)(4 1)(0 2))))
;; #2A((3 4 0) (3 4 4) (3 3 3) (4 4 4) (5 -4 4) (1 5 4))

(print (c #2A((3 3 3) (3 3 3) (3 3 3)) '((0 0)(0 1)(0 2))))
; #2A((1 0 1) (5 6 5) (3 3 3))  => #2A((1 0 1) (5 6 5) (3 3 3))

(print (c #2A((9 8 7) (8 9 7) (8 7 9)) '((0 0)(1 1)(2 2))))
;; #2A((4 11 8) (11 5 10) (9 10 4))  => #2A((4 11 8) (11 5 10) (9 10 4))

(print (c #2A((0 0) (0 0)) '((0 0)(0 0)(0 0))))
;; #2A((-9 3) (3 3))  => #2A((-9 3) (3 3))

(print (c #2A((10 20 30)(30 20 10)(40 50 60)) '((0 2)(2 0)(1 1)(1 0))))
;; #2A((21 38 13) (9 12 21) (21 71 64))  => #2A((21 38 13) (9 12 21) (21 71 64))
adl
fonte
2

Python 2 , 171 bytes

M,p=input()
l=len
for i,j in p:
 y=[(i+y,j+x)for x in-1,0,1for y in-1,0,1if l(M)>j+x>-1<i+y<l(M[0])];x=max(M[i][j]/l(y),1);M[i][j]-=x*l(y)
 for i,j in y:M[i][j]+=x
print M

Experimente online!

Erik, o Outgolfer
fonte