Números explosivos

25

sandbox (eliminado)

Vamos a definir una matriz de 9s como:

norte=[9 99 99 99 99 99 99 99 99 9]

Definamos un número explosivo como un número en la posición (X,y) que se puede descomponer en enteros iguales entre todos sus vecinos adyacentes (incluido él mismo) y el valor absoluto de cada porción es mayor que 0.

De la matriz anterior, explotemos el número en la posición (1,1) (0 indexado)

norte=[9 99 99 99 99 99 99 99 99 9]
norte=[9 9+19 9+19 9+19 9+10 0+19 9+19 9+19 9+19 9+1]

N=[10101010110101010]

A veces, el resultado de descomposición en un número racional mayor que 1. Esto es algo que debemos evitar al explotar números. En estos casos, el resto se asignará al número explotado.

Para demostrarlo, continuemos trabajando con nuestra matriz anterior. Esta vez estallaremos el número en la posición(0 0,0 0)

norte=[10101010110101010]

Aquí tenemos 3 puertos y el número en sí. Aquí la ecuación es algo así como 10/ /4 4 que nos dan 2 para cada uno y 2 como resto.

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

norte=[4 4121012310101010]

Además, a veces un número no será lo suficientemente grande como para descomponerse en partes iguales (donde el abs es mayor que 0) entre sus vecinos (| número racional | <1). En estos casos, necesitamos "tomar prestado" del número explotado para mantener la condición "mayor que 0" . Continuemos con nuestro ejemplo anterior y explotemos el número en la posición .(1,1)

norte=[4 4121012310101010]

norte=[4 4+112+110+112+10 0+1-6 610+110+110+110+1]
norte=[5 5131113-5 511111111]


El desafío es, dada una lista de posiciones y una matriz finita no vacía de números naturales, devolver la forma explotada después de que cada número de la lista de posiciones haya sido explotado.(X,y)


Casos de prueba

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

Salida: [[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]]

Salida: [[4, 11, 8],[11, 5, 10],[9, 10, 4]]


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

Salida: [[-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]]

Salida: [[21, 38, 13], [9, 12, 21], [21, 71, 64]]


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

Salida: [[1]]


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

Salida: [[1, 1, 4]]


Notas

  • Aplican reglas de entrada / salida

  • Puede suponer que la matriz de entrada nunca estará vacía

  • Puedes asumir que las coordenadas siempre serán válidas

  • La entrada coord en casos de prueba se da como (fila, columna). Si necesita que sea (x, y) puede intercambiar los valores. Si es así, indíquelo en su respuesta

Luis felipe De jesus Munoz
fuente
nuevo en el código de golf; ¿en qué formato se permite que la muestra tome estas matrices? ¿Algún formato que exista en el idioma? ¿Forma de cadena exactamente como está escrita?
rtpax
1
Sugiero agregar un caso de prueba para matrices no cuadradas.
Οurous
@Ourous uh oh, había estado escribiendo mi programa asumiendo que se garantizaba que serían cuadrados, de vuelta al tablero de dibujo, supongo
rtpax
¿Podemos suponer que el tamaño de la matriz es al menos 2 por 2? ¿O también se puede ingresar una matriz 1 por 1?
Kevin Cruijssen
@rtpax Cualquier formato a menos que la pregunta indique lo contrario, sí
solo ASCII

Respuestas:

9

C (CCG) 220 216 214 212 bytes

crédito a @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;}}

Ejecútalo aquí

una versión un poco menos golfizada

#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;
    }
}

El código de llamada con un ejemplo

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");
  }
}

y la salida

001,005,003,
000,006,003,
001,005,003,
rtpax
fuente
11
Bienvenido a PPCG :)
Shaggy
198 bytes
ceilingcat
7

JavaScript (ES7),  126 125 123  121 bytes

Guardado 2 bytes gracias a @Shaggy

Toma entrada como (matrix)(list). Salidas modificando la 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]++)``)

Pruébalo en línea!

¿Cómo?

(X,y)

  1. norte
  2. metro(X,y)/ /norteq
  3. caminar de nuevo por la matriz para actualizar a cada vecino
  4. metro(X,y)

En lugar de eso, usamos una función recursiva que ejecuta un flujo de operaciones más simple, repetido tantas veces como sea necesario:

  1. norte0 0 )
  2. norte+1
  3. norte
  4. incremente la celda de referencia (todos los pasos de este tipo se ejecutan sucesivamente cuando se completa la última llamada recursiva)

El principal beneficio es que solo necesitamos un bucle sobre la matriz. El segundo beneficio es que no tenemos que calcular ningún cociente.

Ejemplo

METRO=(0 00 00 00 0260 00 00 00 0) y (X,y)=(1,1)

Después del paso 1 de la primera iteración , tenemos:

METRO=(1111271111) y norte=9 9

Y después del paso 2 de la primera iteración :

METRO=(1111171111)

-9 9+1

26

179 9

Después del paso 1 de la segunda iteración , tenemos:

METRO=(222218 años2222) y norte=9 9

Y después del paso 2 de la segunda iteración :

METRO=(222282222)

8<9 9

Ahora incrementamos la celda de referencia dos veces ( paso 4 de ambas iteraciones ), lo que lleva al resultado final:

METRO=(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
fuente
1
Puede guardar un par de bytes reemplazando ambas apariciones (0)con 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}

Pruébalo en línea!

Explicación

(Corresponde a una versión anterior del 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.
fuente
4

Limpio , 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..]}

Pruébalo en línea!

En forma de una función literal parcialmente aplicada.

Ampliado (primera versión):

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
        }
Οurous
fuente
4

Óxido - 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;}}}

Esto es bastante largo debido a que Rust requiere la indexación de enteros sin signo de los vectores, pero requiere que los enteros con signo resten lo que resulta en negativos. Sin embargo, creo que mi algoritmo es el "algoritmo más corto" hasta ahora. En realidad no hay necesidad de lidiar con la detección de bordes, fondo, etc.

Observe tres cosas: una, la suma de todas las celdas siempre es constante. Dos, esta es una situación de división / resto, por lo que podemos aplicar el pensamiento estilo algoritmo de Bresenham. Tres, la pregunta siempre agrega el mismo número a todas las celdas dentro de una cierta distancia de la celda de posición especial, antes de ocuparse de las cosas "adicionales" en la posición especial.

Algoritmo:

Almacene el valor original de la celda en la posición P en M.

Comenzar bucle:

Iterar sobre cada celda I en la matriz. Si la posición de la celda I está dentro de los 3 cuadrantes (distancia al cuadrado) de la posición P, reste 1 de la celda P y agregue 1 a la celda I. Cuente cuántas veces se hace esto en una iteración a través de la matriz.

Si el valor restante en la celda en la posición P es menor o igual que M / Count + M módulo Count, entonces rompa el ciclo. De lo contrario, realice el ciclo nuevamente.

La matriz resultante será la versión explosionada. Contar es básicamente una forma de contar vecinos sin tratar con bordes. El bucle es una manera de dividir las cosas de división / suma en una suma / resta única repetida de una. La verificación del módulo asegura que nos quedará el resto apropiado en la posición P para lidiar con 'explosiones' que no son divisibles entre vecinos. La estructura de bucle do / while permite que P <0 funcione correctamente.

Versión sin golf en Rust Playground

don brillante
fuente
1
Un nombre de función tan largo no es necesario, cualquier 1 byter como flo haría. Pero probablemente podría guardar aún más bytes, utilizando una función 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;}}

Puerto iterativo de la respuesta JavaScript de @Arnauld .
-17 bytes gracias a @Arnauld .

Modifica la matriz de entrada en lugar de devolver una nueva para guardar bytes.

Pruébalo en línea.

Explicación:

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
fuente
1
m[y] con yfuera de los límites está bien en JS (rendimiento indefinido ), pero m[y][x]conyfuera de los límites también se estrellaría.
Arnauld
@Arnauld Ah, ok. De hecho, recordé que fuera de los límites generalmente no es un problema en JS, pero puedo entender por undefined[x]qué fallaría. De todos modos, su (x-X)**2+(y-Y)**2<3cheque es bastante inteligente. Necesito recordar eso cuando alguna vez quiero verificar los valores en una matriz en un bloque de 3x3 (y dentro de los límites) a su alrededor. Creo que en realidad tengo algunas respuestas como esa, donde ahora uso un try-catch y, en un caso, try-finally ... Las miraré cuando tenga algo de tiempo.
Kevin Cruijssen
1
171 bytes con bucles mejorados.
Arnauld
@Arnauld Oh que bien. Ahora que lo veo, no puedo creer que no haya pensado en eso cuando creé un puerto a partir de su respuesta, ya que usted hace lo mismo ...>.>;)
Kevin Cruijssen
2

Lisp común , 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)

Pruébalo en línea!

Use esta función como (print (c #2A((3 3 3) (3 3 3) (3 3 3)) '((0 0)(0 1)(0 2))))

Versión mejor legible:

(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)

Ejemplo de salida:

(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
fuente
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

Pruébalo en línea!

Erik el Outgolfer
fuente