Analiza trzęsień ziemi

17

tło

Losowe Domino Automat jest model zabawka dla trzęsień ziemi, zainspirowany automatów komórkowych. W tym wyzwaniu Twoim zadaniem jest symulacja uproszczonej wersji tego modelu i zbieranie z niego danych.

Automat jest zdefiniowana w tablicy Az kbitów, co stanowi linię podziału, w którym może występować trzęsienia ziemi. Tablica owija się wokół swoich granic. Warunek A[i] = 0oznacza, że ​​pozycja ijest zrelaksowana i A[i] = 1oznacza, że ​​jest podekscytowana lub zawiera zmagazynowaną energię. Na każdym kroku czasowym jedna pozycja tablicy jest wybierana losowo równomiernie. Jeśli ta pozycja jest rozluźniona, staje się podekscytowana (energia potencjalna jest dodawana do systemu). Jeśli ta pozycja jest już podekscytowana, powoduje trzęsienie ziemi, a wybrana pozycja i wszystkie powiązane z nią podekscytowane pozycje są ponownie rozluźnione. Liczba podekscytowanych pozycji, które się rozluźniają, jest wielkością trzęsienia ziemi.

Przykład

Rozważ tablicę

100101110111

o długości 12. Jeśli losowy proces wybierze drugi bit od lewej, tablica zostanie zaktualizowana do

110101110111
 ^

ponieważ wybrany bit (oznaczony ^) był 0. Jeśli następnie wybierzemy czwarty bit od lewej, który jest izolowany 1, nastąpi trzęsienie ziemi o sile 1 i bit zostanie 0ponownie ustawiony :

110001110111
   ^

Następnie możemy wybrać drugi bit z prawej strony, co powoduje trzęsienie ziemi o sile 5:

000001110000
          ^

Zauważ, że wszystkie 1s w tej samej „grupie” co wybrana były częścią trzęsienia, a tablica owija się wokół granicy.

Zadanie

Weźmiesz jako wejścia dwie liczby całkowite dodatnie ka t, a twoim zadaniem jest symulacja losowy domina automat do tkroków czasowych, począwszy od początkowego wzdłużnych ktablicy wszystkich 0s. Jego wynik będzie lista Lz kliczb całkowitych, gdzie L[i](z indeksowaniem 1-based) zawiera liczbę trzęsień ziemi wielkości i, które wystąpiły w trakcie symulacji. Możesz usunąć końcowe zera z danych wyjściowych.

Dla danych wejściowych k = 15i t = 1000niektórych reprezentatywnych danych wyjściowych są

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

Zasady

Dozwolone są zarówno pełne programy, jak i funkcje. Wygrywa najkrótsza liczba bajtów, a standardowe luki są niedozwolone.

Zauważ, że nie musisz symulować automatu przy użyciu żadnej konkretnej implementacji, liczy się tylko wynik.

Zgarb
źródło
2
Czy to możliwe, że możesz dodać kursor ^ pod bitem, który się zmienia? Może to ułatwić wizualizację przykładu
DeadChex
1
@DeadChex Dobry pomysł, zaktualizowany.
Zgarb,

Odpowiedzi:

2

Pyth, 48 bajtów

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

Trochę zainspirowało mnie wyjaśnienie @ Dennisa. Wczoraj miałem podobne myśli, ale tak naprawdę ich nie śledziłem.

Wypróbuj online: demonstracja

Wyjaśnienie:

      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
źródło
5

CJam, 57 55 bajtów

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

Jest to anonimowa funkcja, która wyrzuca k i t ze stosu ( k na górze t ) i pozostawia żądaną tablicę w zamian.

Wypróbuj online w interpretatorze CJam .

Jak to działa

: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
źródło
4

Python 2, 153 bajty

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

Okazało się, że miałem prawie takie samo rozwiązanie jak Fry'ego , ale z nieco większą ilością majstrowania.

Sp3000
źródło
Wow, na co właściwie spojrzałem randrange, ale nie zdawałem sobie sprawy, że zadziałało to z jednym argumentem. Dobra robota!
FryAmTheEggman
4

Java, 278 272 bajtów

Java nie jest najlepszym językiem golfowym i nie jestem najlepszym golfistą, ale pisanie było fajne, więc oto jest! Daj mi znać o błędach i ulepszeniach! (Postanowiłem przesłać ponownie jako funkcję).

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

A plik ze spacjami i komentarzami:

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
źródło
Jeśli możesz nieco zakomentować komentarze w drugim programie, może to pomóc w czytelności. Dzięki. (Użyj Alt+09lub
tabuluj
d[q]+=1;w ten sposób d[q]++;możesz zwiększać wartość bezpośrednio w tablicach zamiast używać + = wszędzie. To powinno uratować wiele postaci.
Kompas
@Compass Dokonałem już tej zmiany, dziękuję!
DeadChex
1
Ponadto: for(;t>0;t--){ można zmienić na for(;t-->0;){: D
Kompas
Gratulujemy pierwszego golfa! : D Teraz .... po prostu trochę przestawiając deklaracje i zwracając (zamiast drukować) wynik, możesz trochę to obniżyć. Może być jeszcze wiele do zrobienia, ale muszę iść. Oto 24-bajtowa wersja: 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]

Dzięki @Vioz za znalezienie krótszego sposobu na zrobienie Di ponowne udowodnienie, że notzwykle jest to gra w golfa. A także do napisania wyjaśnienia.

Próbowałem stworzyć podobny program w Pyth, ale wydaje się, że jest problem z zakresem w tym, co próbowałem zrobić. To dość naiwnie implementuje domino, a funkcja Upropaguje trzęsienia ziemi. Kierunek odejmowania w Unie wymaga modyfikacji, ponieważ będzie się naturalnie owijał. Ostatni element Eliczy, ile razy zero jest zamieniane na jeden, więc nie jest drukowane na końcu.

Niegolfowany + Objaśnienie:

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
źródło
1
Zmiana D[r]=not edo D[r]=e<1oszczędza 2 bajty, i E=[0]*-~kaby E=D+[0]zaoszczędzić kolejne 2, aby dostać się na dół do 170.
Kade
1

ES6, 224 196 189 179 172

Łatwe rzeczy zostały zagrane w golfa, ale wciąż jest trochę do zrobienia. Wyjaśnię to później. Ponadto, jeśli ktoś może mi powiedzieć, dlaczego ta krótka new Date%krzecz nie działa już tak dobrze, byłoby to pęczniejące.

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}

Wykorzystanie jest

f(10, 1000);
Kompas
źródło
Możesz usunąć new. Nie potrzebujesz tego tw pętli for, nie potrzebujesz dwóch ostatnich;
Optimizer
@Optimizer, którego jesteś bohaterem
Compass
a[r]^=1będzie DEFS pracę, jeśli wartość początkowa jest albo 1albo0
Optymalizator
1

Perl, 212

Poprzednia wersja, którą przygotowałem, nie była poprawnie opakowana, a jej wdrożenie zajęło trochę pracy.

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}

Prawdopodobnie nie jest to odpowiedni algorytm do tego, ale nie mogę teraz myśleć. Wersja bez golfa znajduje się poniżej.

Nie golfowany:

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
źródło
1

CJam, 76 bajtów

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

To nie jest zbyt konkurencyjne. Ale ponieważ zajęło mi to wystarczająco dużo czasu, pomyślałem, że i tak to opublikuję.

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.

Wypróbuj online

Reto Koradi
źródło