Analisando terremotos

17

fundo

O Random Domino Automaton é um modelo de brinquedo para terremotos, inspirado em autômatos celulares. Nesse desafio, sua tarefa é simular uma versão simplificada desse modelo e coletar dados dele.

O autômato é definido em uma matriz Ade kbits, representando uma linha de falha na qual terremotos podem ocorrer. A matriz envolve suas bordas. A condição A[i] = 0significa que a posição iestá relaxada e A[i] = 1significa que está excitada ou contém energia armazenada. Em cada etapa do tempo, uma posição da matriz é escolhida uniformemente aleatoriamente. Se essa posição estiver relaxada, ela ficará excitada (energia potencial é adicionada ao sistema). Se essa posição já estiver excitada, desencadeia um terremoto, e a posição escolhida e todas as posições excitadas conectadas a ela são relaxadas novamente. O número de posições excitadas que ficam relaxadas é a magnitude do terremoto.

Exemplo

Considere a matriz

100101110111

12. Se o processo aleatório escolher o segundo bit da esquerda, a matriz será atualizada para

110101110111
 ^

desde que o bit escolhido (marcado com ^) foi 0. Se, em seguida, escolhermos o quarto bit da esquerda, que é um isolado 1, um terremoto de magnitude 1 é acionado e o bit é definido 0novamente:

110001110111
   ^

Em seguida, podemos escolher o segundo bit da direita, o que desencadeia um terremoto de magnitude 5:

000001110000
          ^

Observe que todos os 1s no mesmo "aglomerado" que o escolhido foram parte do terremoto, e a matriz se envolve na borda.

A tarefa

Você deve tomar como entrada dois números inteiros positivos ke t, e sua tarefa é simular o autômato aleatório do dominó para tintervalos de tempo, iniciando a partir de uma kmatriz de comprimento inicial de todos os 0s. Sua saída deve ser uma lista Lde knúmeros inteiros, onde L[i](com indexação baseada em 1) contém o número de terremotos de magnitude ique ocorreram durante a simulação. Você tem permissão para eliminar zeros à direita da saída.

Para as entradas k = 15e t = 1000, algumas saídas representativas são

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

Regras

Programas e funções completos são permitidos. A menor contagem de bytes vence e as brechas padrão não são permitidas.

Observe que você não precisa simular o autômato usando uma implementação específica, apenas a saída é importante.

Zgarb
fonte
2
É possível adicionar um sinal de intercalação ^ no bit que muda? Ele pode torná-lo mais fácil de visualizar o exemplo
DeadChex
11
@DeadChex Boa ideia, atualizada.
Zgarb

Respostas:

2

Pitão, 48 bytes

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

Fiquei um pouco inspirado pela explicação de @ Dennis. Teve alguns pensamentos semelhantes ontem, mas realmente não os seguiu.

Experimente online: Demonstração

Explicação:

      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
fonte
5

CJam, 57 55 bytes

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

Essa é uma função anônima que exibe k e t da pilha ( k em cima de t ) e deixa a matriz desejada em troca.

Experimente online no intérprete CJam .

Como 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
fonte
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:]

Acontece que eu tinha quase a mesma solução que a de Fry , mas com um pouco mais de brincadeira.

Sp3000
fonte
Uau, eu realmente tinha olhado randrange, mas não sabia que funcionava com apenas um argumento. Bom trabalho!
FryAmTheEggman
4

Java, 278 272 bytes

Java não é a melhor linguagem de golfe, e eu não sou o melhor jogador de golfe, mas foi muito divertido escrever, então aqui está! Deixe-me saber sobre bugs e melhorias! (Decidi reenviar como apenas uma função.)

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

E o arquivo com espaços e comentários:

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
fonte
Se você puder separar os comentários um pouco no segundo programa, isso pode ajudar na legibilidade. Obrigado. (Use Alt+09, ou guia-lo no bloco de notas ++)
mbomb007
d[q]+=1;isso pode se tornar d[q]++;você pode incrementar diretamente nas matrizes em vez de usar + = em qualquer lugar. Isso deve salvar um monte de personagens.
Compass
@ Compass Já fez essa alteração, obrigado!
23415 DeadChex
11
Também: for(;t>0;t--){ pode ser alterado para for(;t-->0;){: D
Compass
Parabéns pelo seu primeiro golfe aqui! : D Agora .... apenas rearranjando um pouco as declarações e retornando (em vez de imprimir) o resultado, você pode diminuir um pouco isso. Pode haver mais a ser feito, mas tenho que ir. Aqui está uma versão de 244 bytes: pastebin.com/TWAXvyHW
Geobits
4

Python 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]

Obrigado @Vioz por encontrar uma maneira mais curta de fazer De provar novamente quenot geralmente é jogável. E também para escrever a explicação.

Eu tentei criar um programa semelhante em Pyth, mas parece haver um problema de escopo no que eu estava tentando fazer. Isso implementa de forma bastante ingênua os dominós e a função Upropaga terremotos. A direção da subtração Unão precisa de um mod, porque será envolvida naturalmente. O último elemento deE conta o número de vezes que um zero é transformado em um, portanto, não é impresso no final.

Ungolfed + Explicação:

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
fonte
11
Alterando D[r]=not ea D[r]=e<1salva 2 bytes, e E=[0]*-~kpara E=D+[0]salva outro 2, para levá-lo para baixo para 170.
Kade
1

ES6, 224 196 189 179 172

O material mais fácil já foi jogado, mas ainda há trabalho a fazer. Vou digitar uma explicação mais tarde. Além disso, se alguém puder me dizer por que a new Date%kcoisa curta não funciona mais tão bem, isso seria ótimo.

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}

O uso é

f(10, 1000);
Bússola
fonte
Você pode remover o new. Você não precisa que tno loop for, Não há necessidade de que dois últimos;
Optimizer
@Optimizer você é herói para a causa
Compass
a[r]^=1vai DEFS trabalho se o valor inicial é tanto 1ou0
Optimizer
1

Perl, 212

A versão anterior que eu havia apresentado não estava encapsulando corretamente, e a implementação levou algum trabalho.

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}

Provavelmente este não é o algoritmo certo para isso, mas não consigo pensar agora. A versão ungolfed está abaixo.

Ungolfed:

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
fonte
1

CJam, 76 bytes

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

Bem, isso não é muito competitivo. Mas como demorei bastante, pensei em publicá-lo de qualquer maneira.

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.

Experimente online

Reto Koradi
fonte