Анализ землетрясений

17

Фон

Случайный Domino Automaton игрушки модель для землетрясений, вдохновленная клеточными автоматами. В этой задаче ваша задача - смоделировать упрощенную версию этой модели и собрать из нее данные.

Автомат задается на массив Aиз kбитов, представляющих собой линии разлома , на котором может произойти землетрясения. Массив оборачивается на своих границах. В состоянии A[i] = 0означает , что позиция iявляется расслаблена , и A[i] = 1означает , что она возбуждается , или содержат запас энергии. На каждом временном шаге одна позиция массива выбирается случайным образом равномерно. Если это положение расслаблено, оно становится возбужденным (потенциальная энергия добавляется в систему). Если эта позиция уже взволнована, она вызывает землетрясение, и выбранная позиция и все связанные с ней возбужденные позиции снова ослабляются. Количество возбужденных позиций, которые становятся расслабленными, является величиной землетрясения.

пример

Рассмотрим массив

100101110111

длины 12. Если случайный процесс выбирает второй бит слева, массив обновляется до

110101110111
 ^

так как выбранный бит (отмечен ^) был 0. Если мы затем выберем четвертый бит слева, который является изолированным 1, землетрясение магнитудой 1 сработает, и бит будет установлен 0снова:

110001110111
   ^

Затем мы можем выбрать второй бит справа, который вызовет землетрясение магнитудой 5:

000001110000
          ^

Обратите внимание, что все находящиеся 1в том же «кластере», что и выбранный, были частью землетрясения, и массив обвивается вокруг границы.

Задание

Вы должны взять в качестве входных данных два натуральных числа 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]

правила

Разрешены как полные программы, так и функции. Самый короткий счет байтов побеждает, и стандартные лазейки запрещены.

Обратите внимание, что вам не требуется моделировать автомат с использованием какой-либо конкретной реализации, важен только вывод.

Zgarb
источник
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
Jakube
источник
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:]

Оказывается, у меня было почти то же самое решение, что и у Фрая , но с немного большим возня.

Sp3000
источник
Ничего себе, на самом деле я смотрел randrange, но я не понимал, что это работает только с одним аргументом. Хорошо сделано!
FryAmTheEggman
4

Ява, 278 272 байта

Ява не лучший язык гольфа, и я не лучший игрок в гольф, но было очень весело писать, так что вот оно! Дайте мне знать об ошибках и улучшениях! (Я решил повторно представить как просто функцию.)

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
 }
DeadChex
источник
Если бы вы могли добавить комментарии во второй программе, это могло бы помочь с удобочитаемостью. Благодарю. (Используйте 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

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]

Спасибо @Vioz за то, что нашли более короткий способ заработать Dи еще раз доказали, что notэто, как правило, игра в гольф. А также для написания объяснения.

Я пытался создать подобную программу на Pyth, но, похоже, проблема в том, что я пытался сделать. Это довольно наивно реализует домино, а функция Uраспространяет землетрясения. Направление вычитания в Uне нуждается в моде, потому что оно будет естественным. Последний элемент Eподсчитывает, сколько раз ноль превращается в единицу, поэтому в конце он не печатается.

Ungolfed + Объяснение:

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
источник
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, нет необходимости в последних двух;
Оптимизатор
@ Оптимизатор, ты герой, чтобы вызвать
Компас
a[r]^=1будет Defs работы , если начальное значение либо 1или0
Оптимизатор
1

Perl, 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}

Вероятно, это не правильный алгоритм для этого, но я не могу сейчас думать. Развернутая версия ниже.

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
источник
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.

Попробуйте онлайн

Рето Коради
источник