Analizando terremotos

17

Antecedentes

El Random Domino Automaton es un modelo de juguete para terremotos, inspirado en autómatas celulares. En este desafío, su tarea es simular una versión simplificada de este modelo y recopilar datos de él.

El autómata se define en una matriz Ade kbits, que representa una línea de falla en la cual pueden ocurrir terremotos. La matriz se envuelve en sus bordes. La condición A[i] = 0significa que la posición iestá relajada y A[i] = 1significa que está excitada o que contiene energía almacenada. En cada paso de tiempo, se elige una posición de la matriz de manera uniforme al azar. Si esa posición se relaja, se excita (se agrega energía potencial al sistema). Si esa posición ya está excitada, desencadena un terremoto, y la posición elegida y todas las posiciones excitadas conectadas a ella se relajan nuevamente. El número de posiciones excitadas que se relajan es la magnitud del terremoto.

Ejemplo

Considera la matriz

100101110111

de longitud 12. Si el proceso aleatorio elige el segundo bit desde la izquierda, la matriz se actualiza a

110101110111
 ^

ya que el bit elegido (marcado con ^) era 0. Si luego elegimos el cuarto bit de la izquierda, que es un aislado 1, se activa un terremoto de magnitud 1, y el bit se establece de 0nuevo en:

110001110111
   ^

A continuación, podríamos elegir el segundo bit de la derecha, que desencadena un terremoto de magnitud 5:

000001110000
          ^

Tenga en cuenta que todos los 1s en el mismo "clúster" que el elegido fueron parte del terremoto, y la matriz se envuelve en el borde.

La tarea

Deberá tomar como entradas dos enteros positivos ky t, y su tarea es simular el autómata de dominó aleatorio para tpasos de tiempo, comenzando desde una kmatriz de longitud inicial de todos los 0s. Su salida será una lista Lde kenteros, donde L[i](con indexación basada en 1) contiene el número de terremotos de magnitud ique ocurrieron durante la simulación. Se le permite eliminar los ceros finales de la salida.

Para las entradas k = 15y t = 1000, algunas salidas representativas son

[117, 97, 45, 26, 10, 5, 3, 1, 3, 0, 0, 0, 0, 0, 0]
[135, 91, 58, 21, 8, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0]
[142, 63, 51, 31, 17, 4, 2, 1, 1, 0, 0, 0, 0, 0, 0]
[106, 75, 45, 30, 16, 8, 5, 2, 2, 0, 0, 0, 0, 0, 0]
[111, 96, 61, 22, 3, 8, 3, 2, 0, 0, 0, 1, 0, 0, 0]

Reglas

Se permiten tanto programas completos como funciones. El conteo de bytes más corto gana, y las lagunas estándar no se permiten.

Tenga en cuenta que no es necesario que simule el autómata utilizando una implementación particular, solo importa la salida.

Zgarb
fuente
2
¿Es posible que pueda agregar un cursor ^ debajo del bit que cambia? Podría facilitar la visualización del ejemplo
DeadChex
1
@DeadChex Buena idea, actualizada.
Zgarb

Respuestas:

2

Pyth, 48 bytes

Km0QJsM.u?<+vM.sjkZ\1KQe=Z.>NOQ+PZ1vwKm/-VJtJhdQ

Me inspiré un poco en la explicación de @ Dennis. Tuve algunos pensamientos similares ayer, pero realmente no los seguí.

Pruébelo en línea: demostración

Explicación:

      implicit: Q is the first input number
 m0Q  create a list with Q zeros
K     store the list in K


       .u                      vwK   apply the following expression eval(input) times, 
                                     start with N = K:
                      .>NOQ            shift N by a random integer of [0, ..., Q-1]
                    =Z                 store the result in Z
     ?             e Z                 if the last digit == 1:
            jkZ                          convert Z to string
          .s   \1                        remove "1"s from the start and end
        vM                               convert to list of integers
       +         K                       add K (adds a bunch of zeros)
      <           Q                      correct size (take the first Q elements)
                                         implicitly update N with this result
                                       else:
                           PZ            all but last of Z
                          +  1           append 1
                                         implicitly update N with this result

   .u                                gives all the intermediate states
 sM                                  sum each list
J                                    store in J


m/-VJtJhdQ
m        Q   map each d in [0, 1, ..., Q-1] to:
  -VJtJ        vectorized minus between J and J[1:]
 /     hd      count d+1 in ^
             implicitly print
Jakube
fuente
5

CJam, 57 55 bytes

{:K,K0a*@[{Kmrm<){_{_0#>W%K0e]}2*_)}1?+}*;]1fb2/::-fe=}

Esta es una función anónima que saca k y t de la pila ( k encima de t ) y deja la matriz deseada a cambio.

Pruébelo en línea en intérprete de CJam .

Cómo funciona

:K         e# Save the topmost integer (k) in K.
,          e# Push I := [0 ... K-1].
K0a*       e# Push J := [0 ... 0] (K elements).
@          e# Rotate the other integer (t) on top of the stack.
[{         e# Do t times:
  Kmr      e#   Pseudo-randomly select an integer between 0 and t-1.
  m<       e#   Rotate the array J than many units to the left.
  )        e#   Pop out the last element.
  {        e#   If it is 1:
    _      e#     Copy J.
    {      e#     Do 2 times:
      _0#  e#       Push the first index of 0 in J.
      >    e#       Discard the preceding elements.
      W%   e#       Reverse the array.
      K0e] e#       Pad it with zeroes to length K.
    }2*    e#
    _)     e#     Copy J and pop out the last element.
  }        e#
  1?       e#   Else: Push 1.
  +        e#   Push the integer on the stack on J.
}*         e#
;          e# Discard the last value of J.
]          e# Collect the intermediate values of J in an array.
1fb        e# Replace each array by the sum of its elements (number of ones).
2/         e# Split the array into chunks of length 2.
::-        e# Replace each chunk by the difference of its elements.
fe=        e# Count the occurrences of each integer in I.
Dennis
fuente
4

Python 2, 153 bytes

from random import*
k,t=input()
E=[0]*k
L=E+[0]
def g(i,x=0):y=E[i];E[i]=y&x^x;return y and-~g(i-1)+g(-~i%k)
exec"L[g(randrange(k),1)]+=1;"*t
print L[1:]

Resulta que tenía casi la misma solución que la de Fry , pero con un poco más de violín.

Sp3000
fuente
Wow, en realidad lo había mirado randrange, pero no me di cuenta de que funcionaba con un solo argumento. ¡Buen trabajo!
FryAmTheEggman
4

Java, 278 272 bytes

Java no es el mejor lenguaje de golf, y no soy el mejor golfista, pero fue muy divertido escribir, ¡así que aquí está! ¡Avísame sobre errores y mejoras! (Decidí volver a enviarlo solo como una función).

void e(int k, int t){int[]d=new int[k],b=d.clone();for(;t-->0;){int m=0,q=(int)(Math.random()*k),i=q,h=1,f=0;d[q]++;if(d[q]>1){for(;;){if(i<0){i=k-1;h=-1;}if(d[i%k]>0){m++;d[i%k]=0;}else{if(f>0)break;h*=-1;i=q;f=1;}i+=h;}b[m-1]++;}}System.out.println(Arrays.toString(b));}

Y el archivo con espacios y comentarios:

void e(int k, int t){
    int[]d=new int[k],b=d.clone();          //b is the record, d is the map   

    for(;t-->0;){                           //do time steps //q is the spot
      int m=0,q=(int)(Math.random()*k),i=q,h=1,f=0; 
                        //m-magnitude,i spot examining, h moving index, f change counter
      d[q]++;                               //add the energy
      if(d[q]>1){                           //double energy, quake here 
        for(;;){                            //shorthand while true
          if(i<0){                          //i has wrapped negative, need to start a left hand search from the end now
            i=k-1;                          //Start at the end
            h=-1;                           //Left handed search
          }
          if(d[i%k]>0){                     //is the spot energetic and set off
           m++;                             //add one to the mag counter
           d[i%k]=0;                        //remove energy
          } else {                          //it's a non active spot so we need to flip search direction
           if(f>0) break;                   //we've already flipped once, break
           h*=-1;                           //flip the direction now
           i=q;                             //reset the spot we look at to the epicenter
           f=1;                             //add one to the flip counter
          }
          i+=h;                             //add the search increment to the spot we look at
        }
        b[m-1]++;                           //update the mag record
      }
    }
    System.out.println(Arrays.toString(b)); //print it out
 }
DeadChex
fuente
Si pudiera separar un poco los comentarios en el segundo programa, eso podría ayudar con la legibilidad. Gracias. (Use Alt+09o
separe
d[q]+=1;Esto puede convertirse en d[q]++;un incremento directo en las matrices en lugar de usar + = en todas partes. Eso debería salvar a un montón de personajes.
Brújula
@Compass Ya hizo ese cambio, ¡gracias!
DeadChex
1
También: for(;t>0;t--){ se puede cambiar a for(;t-->0;){: D
Brújula
¡Felicidades por tu primer golf aquí! : D Ahora ... simplemente reorganizando un poco las declaraciones y devolviendo (en lugar de imprimir) el resultado, puede reducir esto bastante. Puede que haya más por hacer, pero me tengo que ir. Aquí hay una versión de 244 bytes: pastebin.com/TWAXvyHW
Geobits
4

Pitón 2, 174 170

from random import*
k,t=input()
D=[0]*k
E=D+[0]
def U(x):b=D[x];D[x]=0;return b and-~U(x-1)+U(-~x%k)
for x in[0]*t:r=randint(0,k-1);e=U(r);E[e-1]+=1;D[r]=e<1
print E[:-1]

Gracias @Vioz por encontrar una forma más corta de hacer Dy probar de nuevo que notgeneralmente es golfable. Y también por escribir la explicación.

Intenté hacer un programa similar en Pyth, pero parece haber un problema de alcance en lo que estaba tratando de hacer. Esto implementa ingenuamente las fichas de dominó y la función Upropaga terremotos. La dirección de resta Uno necesita un mod porque se envolverá naturalmente. El último elemento deE cuenta el número de veces que un cero se convierte en uno, por lo que no se imprime al final.

Ungolfed + Explicación:

from random import*
k,t=input()                            # Takes input in form k,t
D = [0]*k                              # Empty array of size k is made for
                                       # performing the simulation.
E = D+[0]                              # Empty array of size k+1 is made for
                                       # storing the magnitudes.
def U(x):                              # Define a function U that takes an int x
    b = D[x]                           # Assign b to the value at x in D
    D[x] = 0                           # Clear the value at x in D
    return b and U(x-1)+1 + U((x+1)%k) # Return the sum of U(x-1)+1 and U((x+1)%k)
                                       # if b is a 1.
for x in[0]*t:                         # Perform t tests
    r=randint(0,k-1)                   # Generate a random number between 0 and k-1
    e=U(r)                             # Assign e to the value of U(r)
    E[e-1]+=1;                         # Increment the magnitude array at position
                                       # e-1
    D[r] = e<1                         # Set D[r] to be 1 if no earthquake happened.
print E[:-1]                           # Print the magnitude list
FryAmTheEggman
fuente
1
Cambiar D[r]=not epara D[r]=e<1guardar 2 bytes, y E=[0]*-~kpara E=D+[0]guardar otros 2, para llegar a 170.
Kade
1

ES6, 224 196 189 179 172

Las cosas fáciles se han jugado al golf, pero aún queda mucho trabajo por hacer. Escribiré una explicación más tarde. Además, si alguien puede decirme por qué la new Date%kcosa corta ya no funciona tan bien, sería genial.

f=(k,t)=>{a=Array(k).fill(0);o=a.slice(0);for(;t--;){c=0;r=Math.random()*k|0;if(a[r]){for(d=r+1;d<k&a[d];c++)a[d++]--;for(d=r-1;d&a[d];c++)a[d--]--;o[c]++};a[r]^=1}return o}

El uso es

f(10, 1000);
Brújula
fuente
Puedes eliminar el new. No necesita eso ten el ciclo for, no necesita los dos últimos;
Optimizer
@Optimizer eres el héroe que causa
Brújula
a[r]^=1defs trabajará si el valor inicial es 1o0
Optimizer
1

Perl, 212

La versión anterior que había publicado no se ajustaba correctamente, y su implementación tomó algo de trabajo.

sub f{sub n{$i=($i+$d)%($#a+1)}($k,$t)=@_;@L=@a=(0)x$k;for(1..$t){$i=$x=int rand($k);if(++$a[$x]>1){$d=1;my%z;for(;;){$z{$i}=1;n;if(!$a[$i]){$d*=-1;n}last if($d>0&&$i==$x)}@z=keys %z;@a[@z]=(0)x@z;++$L[$#z]}}@L}

Probablemente este no sea el algoritmo correcto para esto, pero no puedo pensar en este momento. La versión sin golf es la siguiente.

Sin golf:

sub f {
  # n() implements the iterator, so that each time it is called a
  # global index is incremented or decremented correctly wrapping
  # around
  sub n { $i = ($i + $d) % ($#a + 1) }
  # Receive input
  ($k, $t) = @_;
  # Initialise the array for earthquake magnitudes an the fault
  # line
  @L = @a = (0) x $k;

  for(1..$t){
    # Assign a random integer value to two control variables
    # $i is used for moving along the fault, and $x to remember
    # the initial value
    $i = $x = int rand($k);
    # The corresponding value in the fault line is incremented,
    # and earthquakes detected
    if(++$a[$x]>1){
      # Earthquake!
      # To propagate the earthquake, we move along the fault 
      # bouncing on unactivated nodes. We stop when we've covered
      # the entire activated block.

      # $d tracks the direction (initially forward);
      $d = 1;
      # %z keeps the indeces of known activated nodes
      my %z;

      for(;;){
        $z{$i} = 1;              # Read current node
        n;                       # Move head
        if (!$a[$i]) {           # If next one is deactivated
          $d *= -1;              # change direction
          n                      # and move the head (bounce!)
        }
        # If we've reached the beginning, and we're moving
        # forward we've covered the entire activated block
        last if ($d > 0 && $i == $x);
      }

      # Deactivate all consecutive activated nodes
      @z = keys %z;
      @a[@z] = (0) x @z;
      # And store the magnitude of the earthquake
      ++$L[$#z];
    }
  }
  # Return list of magnitudes
  @L
}

print join ' ', f(15, 1000), "\n";
jja
fuente
1

CJam, 76 bytes

l~_0a*:R@{1$mr_2$={W@@[W1]{{_@0t@)\@K+_2$=}g2$+)}fK;\(_R=)R\t:R;}{1t}?}*;;Rp

Bueno, esto no es muy competitivo. Pero como me llevó bastante tiempo, pensé en publicarlo de todos modos.

l~     Get input.
_0a*   Initial bit pattern, list of k zeros.
:R     Save away the list of zeros, will be used for histogram.
@{     Pull number of tries to top of stack, and start main loop.
1$mr   Generate random position in range 0 to k-1.
_2$    Duplicate current pattern and position.
=      Get current value of bit at position.
{      Start if statement. This is the block for bit value 1.
W@@    Create initial count of 1 bits in quake, and push it down the stack.
[W1]{  Start for loop over value [-1 1], the two increments for going left/right.
{      Start while loop that proceeds as long as 1 bits are found.
_@0t   Set current value of bit to 0.
@)     Get current bit counter to top of stack, and increment it.
\@     Pull list and bit position back to top of stack.
K+     Increment/decrement bit position.
_2$=   Get value at new bit position.
}g     End of while loop over 1 bits.
2$+)   Restore position to get ready to move in opposite direction.
}fK    End for loop over left/right increment.
;\(_   Pull counter of 1 bits in quake to top of stack.
R=     Get current value in histogram,
)      increment it,
R\t:R  and store it back in the histogram.
;}     End of if branch for 1 bit.
{1t}?  Else branch of if. For 0 bit, simply set it.
}*     End main loop.
;;Rp   Clean up stack and print histogram.

Pruébalo en línea

Reto Koradi
fuente