Numeri che esplodono


25

sandbox (cancellato)

Consente di definire una matrice di 9s come:

N=[999999999]

Consente di definire un numero che esplode come un numero in posizione (x,y) che può essere scomposto in interi uguali tra tutti i suoi vicini adiacenti (incluso se stesso) e il valore assoluto di ogni porzione è maggiore di 0.

Dalla matrice precedente, facciamo esplodere il numero in posizione (1,1) (0 indicizzato)

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

N=[10101010110101010]

A volte, il risultato della decomposizione in un numero razionale maggiore di 1. Questo è qualcosa che dobbiamo evitare quando esplodiamo numeri. In questo caso il resto verrà assegnato al numero esploso.

Per dimostrarlo, continuiamo a lavorare con la nostra matrice precedente. Questa volta esploderemo il numero in posizione (0,0)

N=[10101010110101010]

Qui abbiamo 3 vicini e il numero stesso. Ecco l'equazione è qualcosa come 10/4 che ci danno 2 per ciascuno e 2 come resto.

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

N=[4121012310101010]

Inoltre, a volte un numero non sarà abbastanza grande da essere scomposto in parti uguali (dove gli addominali sono maggiori di 0) tra i suoi vicini (| numero razionale | <1). In questi casi è necessario "prendere in prestito" dal numero esploso per mantenere la condizione "maggiore di 0" . Continuiamo con il nostro esempio precedente ed esplodiamo il numero in posizione (1,1) .

N=[4121012310101010]

N=[4+112+110+112+10+1-610+110+110+110+1]
N=[5131113-511111111]


La sfida è, dato un elenco di posizioni (X,y) e un array finito di numeri naturali non vuoto, restituire la forma esplosa dopo che ogni numero dall'elenco delle posizioni è stato esploso.


Casi test

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

Produzione: [[1, 0, 1], [5, 6, 5], [3, 3, 3]]


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

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


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

Produzione: [[-9, 3],[3, 3]]


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

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


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

Produzione: [[1]]


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

Produzione: [[1, 1, 4]]


Gli appunti

  • Si applicano le regole di input / output

  • Puoi presumere che la matrice di input non sarà mai vuota

  • Puoi presumere che le coordinate siano sempre valide

  • Il coord in input nei casi di test è indicato come (riga, colonna). Se è necessario che sia (x, y) è possibile scambiare i valori. In tal caso, si prega di dichiararlo nella risposta


nuovo al codice golf; in quale formato è consentito il campione per prendere queste matrici? Qualunque formato esiste nella lingua? Forma di stringa esattamente come scritta?
rtpax,

1
Suggerisco di aggiungere un caso di prova per matrici non quadrate.
Οuroso

@Ourous uh oh, stavo scrivendo il mio programma supponendo che fossero garantiti quadrati, tornando al tavolo da disegno immagino
rtpax

Possiamo supporre che la dimensione della matrice sia almeno 2 per 2? Oppure può essere inserita anche una matrice 1 per 1?
Kevin Cruijssen,

@rtpax Qualsiasi formato a meno che la domanda non indichi diversamente, sì
solo ASCII il

Risposte:


9

C (GCC) 220 216 214 212 byte

credito a @ceilingcat per 2 byte

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

Eseguilo qui

una versione leggermente meno giocata a golf

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

Il codice chiamante con un esempio

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 l'uscita

001,005,003,
000,006,003,
001,005,003,

11
Benvenuto in PPCG :)
Shaggy,


7

JavaScript (ES7),  126 125 123  121 byte

Salvato 2 byte grazie a @Shaggy

Accetta input come (matrix)(list). Emette modificando la matrice.

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]++)``)

Provalo online!

Come?

Se dovessimo seguire rigorosamente l'algoritmo descritto nella sfida, dovremmo eseguire le seguenti operazioni per ciascuna coppia di posizioni (X,y):

  1. camminare attraverso la matrice per calcolare il numero di vicini n
  2. calcolare m(X,y)/n e dedurre la quantità q che deve essere aggiunto a ciascun vicino
  3. camminare di nuovo attraverso la matrice per aggiornare ogni vicino
  4. aggiornare m(X,y)

Invece, utilizziamo una funzione ricorsiva che esegue un flusso di operazioni più semplice, ripetuto tutte le volte che è necessario:

  1. per ogni vicino e per la cella di riferimento stessa: incrementa la cella e incrementa un contatore n (inizializzato a 0)
  2. sottrarre n+1 dalla cella di riferimento
  3. se il risultato sopra è maggiore o uguale a n, effettua una chiamata ricorsiva
  4. incrementa la cella di riferimento (tutti i passaggi di questo tipo vengono eseguiti in successione al completamento dell'ultima chiamata ricorsiva)

Il vantaggio principale è che abbiamo solo bisogno di un loop sopra la matrice. Il secondo vantaggio è che non è necessario calcolare alcun quoziente.

Esempio

M=(0000260000) and (X,y)=(1,1)

Dopo il passaggio 1 della prima iterazione , abbiamo:

M=(1111271111) e n=9

E dopo il passaggio 2 della prima iterazione :

M=(1111171111)

Il punto chiave qui è che la cella di riferimento viene aggiornata prendendo solo il costo (-9) in considerazione senza il guadagno (+1), in modo da sapere quanto possiamo ancora trarne.

Di conseguenza, la somma delle celle non è più uguale a 26a questo punto. Ma questo verrà corretto alla fine del processo, in cui tutti i guadagni sulla cella di riferimento vengono contabilizzati contemporaneamente.

Step 3 of the first iteration: because 17 is greater than 9, we do a recursive call.

Dopo step 1 of the second iteration, we have:

M=(2222182222) and n=9

E dopo il passaggio 2 della seconda iterazione :

M=(222282222)

Passaggio 3 della seconda iterazione : questa volta, abbiamo8<9, quindi ci fermiamo qui.

Ora incrementiamo due volte la cella di riferimento ( passaggio 4 di entrambe le iterazioni ), portando al risultato finale:

M=(2222102222)

Commentate

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

1
È possibile salvare un paio di byte sostituendo entrambe le occorrenze di (0)con 2 backtick.
Shaggy,

6

R , 163 162 161 159 155 146 byte

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}

Provalo online!

Spiegazione

(Corrisponde a una versione precedente del codice)

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
}

4

Pulito , 181 167 byte

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

Provalo online!

Sotto forma di una funzione parzialmente applicata letterale.

Espanso (prima versione):

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
        }

4

Ruggine - 295 byte

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

Questo è piuttosto lungo a causa del fatto che Rust richiede l'indicizzazione di numeri interi senza segno dei vettori, ma richiede numeri interi con segno per fare sottrazione con conseguenti negativi. Tuttavia, credo che finora il mio algoritmo sia "l'algoritmo più breve". In realtà non è necessario occuparsi del rilevamento dei bordi, del fondo, ecc.

Nota tre cose: una, la somma di tutte le celle è sempre costante. Due, questa è una situazione di divisione / resto, quindi possiamo applicare il pensiero in stile algoritmo di Bresenham. Tre, la domanda aggiunge sempre lo stesso numero a tutte le celle entro una certa distanza dalla cella della posizione speciale, prima di occuparsi delle cose "extra" nella posizione speciale.

Algoritmo:

Memorizza il valore originale della cella nella posizione P in M.

Inizia il ciclo:

Scorrere su ogni cella I nella matrice. Se la posizione della cella I è all'interno di 3 Quadrance (distanza quadrata) dalla posizione P, quindi sottrarre 1 dalla cella P e aggiungere 1 alla cella I. Conta quante volte ciò viene fatto in una iterazione attraverso la matrice.

Se il valore rimanente nella cella in posizione P è inferiore o uguale a M / Count + M modulo Count, quindi interrompere il loop. Altrimenti esegui di nuovo il loop.

La matrice risultante sarà la versione esplosa. Il conteggio è sostanzialmente un modo per contare i vicini senza occuparsi dei bordi. Il looping è un modo per scomporre la divisione / addizione in una singola aggiunta / sottrazione ripetuta di una. Il controllo del modulo assicura che alla rimanente posizione P rimanga il resto appropriato per far fronte alle "esplosioni" che non sono equamente divisibili tra vicini. La struttura del ciclo do / while consente a P <0 di funzionare correttamente.

Versione non golfata nel Rust Playground


1
Non è necessario un nome di funzione così lungo, qualsiasi 1 byte come ffarebbe. Ma potresti probabilmente salvare ancora più byte, usando una funzione anonima:|p:(i8,i8),v:&mut Vec<Vec<i8>>|{...}
Kirill L.

3

Java 10, 194 193 191 190 184 182 171 byte

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 della risposta JavaScript di @Arnauld .
-17 byte grazie a @Arnauld .

Modifica la matrice di input invece di restituirne una nuova per salvare i byte.

Provalo online.

Spiegazione:

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`

1
m[y] con yfuori limite è OK in JS (resa indefinita ), ma m[y][x]conyanche fuori limite si schianterebbe pure.
Arnauld,

@Arnauld Ah ok. In effetti, mi sono ricordato che fuori dai limiti di solito non è un problema in JS, ma posso capire perché undefined[x]fallirebbe. Comunque, il tuo (x-X)**2+(y-Y)**2<3assegno è piuttosto intelligente. Devo ricordare che quando mai voglio controllare i valori in una matrice in un blocco 3x3 (e entro limiti) attorno ad esso. Penso di avere effettivamente alcune risposte del genere, dove ora uso un try-catch, e in un caso try-finalmente .. Guarderò quelle quando avrò del tempo.
Kevin Cruijssen,

1
171 byte con ottimizzato per loop.
Arnauld,

@Arnauld Oh bello. Ora che lo vedo non riesco a credere di non
averci

2

Lisp comune , 498 byte

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

Provalo online!

Utilizzare questa funzione come (print (c #2A((3 3 3) (3 3 3) (3 3 3)) '((0 0)(0 1)(0 2))))

Versione leggibile meglio:

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

Esempio di output:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.