Аналіз землетрусів


17

Фон

Випадковий Domino Automaton іграшки модель для землетрусів, натхненна клітинними автоматами. У цьому виклику ваше завдання - імітувати спрощену версію цієї моделі та збирати з неї дані.

Автомат задається на масив Aз kбітів, що представляють собою лінії розлому , на якому може статися землетрус. Масив обертається біля своїх кордонів. Ця умова A[i] = 0означає, що положення iє розслабленим і A[i] = 1означає, що воно збуджене або містить накопичену енергію. На кожному етапі часу одне положення масиву вибирається рівномірно. Якщо це положення розслаблене, воно стає збудженим (потенційна енергія додається в систему). Якщо це положення вже збуджене, воно спричиняє землетрус, і вибране положення та всі збуджені до нього положення знову розслабляються. Кількість збуджених позицій, які розслабляються, - це магнітуда землетрусу.

Приклад

Розглянемо масив

100101110111

довжини 12. Якщо випадковий процес вибирає другий біт зліва, масив оновлюється до

110101110111
 ^

оскільки обраний біт (позначений символом ^) був 0. Якщо ми виберемо четвертий біт зліва, який є ізольованим 1, спрацьовує заземлення магнітудою 1, і біт встановлюється 0знову:

110001110111
   ^

Далі ми можемо вибрати другий біт справа, який викликає землетрус магнітудою 5:

000001110000
          ^

Зауважте, що всі 1s у тому ж "кластері", що й обраний, були частиною землетрусу, а масив обертається навколо кордону.

Завдання

Ви повинні взяти в якості двох цілих чисел kі t, ваше завдання - імітувати випадковий автомат доміно для tчасових кроків, починаючи з початкового kмасиву всіх 0s. Ваш висновок повинен бути список Lз kцілих чисел, де L[i](з індексацією з 1) містить число землетрусів величини , iякі мали місце під час моделювання. Вам дозволяється скидати проміжні нулі з виводу.

Для входів k = 15і t = 1000, деякі представницькі результати є

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

Правила

Дозволені як повні програми, так і функції. Виграє найкоротший байт, а стандартні лазівки заборонені.

Зауважте, що вам не потрібно моделювати автомат за допомогою будь-якої конкретної реалізації, лише вихід має значення.


2
Чи можливо ви можете додати карету ^ під біт, який змінюється? Це може полегшити візуалізацію прикладу
DeadChex

1
@DeadChex Хороша ідея, оновлено.
Згарб

Відповіді:


2

Pyth, 48 байт

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

Трохи надихнувся поясненнями @ Денніса. Учора були подібні думки, але насправді не стежили за ними.

Спробуйте в Інтернеті: Демонстрація

Пояснення:

      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

5

CJam, 57 55 байт

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

Це анонімна функція, яка спливає k і t зі стека ( k вгорі t ) і залишає бажаний масив натомість.

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Як це працює

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

4

Python 2, 153 байт

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

Виявляється, у мене було майже те саме рішення, що і у Фрі , але з трохи більше хитрістю.


Нічого, я насправді подивився randrange, але не зрозумів, що це працює лише з одним аргументом. Хороша робота!
FryAmTheEggman

4

Java, 278 272 байт

Java - не найкраща мова для гольфу, і я не найкращий гольфіст, але писати було дуже весело, ось так! Повідомте мене про помилки та вдосконалення! (Я вирішив повторно подати лише функцію.)

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

І файл із пробілами та коментарями:

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
 }

Якщо ви можете трохи розмістити коментарі у другій програмі, це може допомогти з легкістю для читання. Спасибі. (Використовуйте Alt+09або
вставте

d[q]+=1;це може стати d[q]++;ви можете збільшувати безпосередньо на масивах, а не використовувати + = скрізь. Це повинно врятувати купу персонажів.
Компас

@Compass Вже змінилися, хоча дякую!
DeadChex

1
Також: for(;t>0;t--){ можна змінити на for(;t-->0;){: D
Компас

З повагою до вашого першого гольфу тут! : D Тепер .... просто переставивши декларації та повернувши (замість того, щоб роздрукувати) результат, ви можете це дуже знизити. Можна зробити ще багато, але мені треба йти. Ось версія з 244 байтами: pastebin.com/TWAXvyHW
Geobits

4

Пітон 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]

Дякуємо @Vioz за те, що знайшов коротший спосіб заробити Dта ще раз довести, що notце зазвичай пограбує. А також для написання пояснення.

Я намагався зробити подібну програму в Pyth, але, мабуть, є проблема сфери в тому, що я намагався зробити. Це досить наївно реалізує доміно та функцію Uпоширює землетруси. Напрямок віднімання Uв моді не потребує, оскільки він природно завернеться. Останній елемент Eрахує кількість разів, коли нуль перетворюється на одиницю, тому він не друкується в кінці.

Недоліковані + Пояснення:

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

1
Зміна D[r]=not eдо D[r]=e<1зберігає 2 байта, а E=[0]*-~kдля E=D+[0]економить ще 2, щоб отримати вас вниз до 170.
Kade

1

ES6, 224 196 189 179 172

Легкі речі були в гольф, але все ще потрібно виконати певну роботу. Я поясню пояснення пізніше. Крім того, якщо хтось може сказати мені, чому коротка new Date%kріч не працює так добре, це було б набрякло.

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}

Використання є

f(10, 1000);

Ви можете видалити new. Вам це не потрібно tв циклі for, Не потрібні останні два;
Optimizer

@Optimizer - ти герой викликати
Компас

a[r]^=1буде визначати роботу, якщо початкове значення є 1або0
Оптимізатор

1

Перл, 212

Попередня версія, яку я виклав, не була правильно обгорнутою, а реалізація вимагала певної роботи.

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}

Це, мабуть, не правильний алгоритм для цього, але я зараз не можу думати. Недоладжена версія знаходиться нижче.

Безголовки:

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

1

CJam, 76 байт

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

Ну, це не дуже конкурентоспроможно. Але оскільки це пройшло у мене досить довго, я думав, що все-таки опублікую його.

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.

Спробуйте в Інтернеті

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.