ワイヤーで跳ねる電子


46

nスペースがある「ワイヤー」を想像してください。さらに、そのワイヤに「電子」があると想像してください。これらの電子は1単位の時間だけ生きます。正確に1つの電子に隣接するワイヤ内のスペースはすべて電子になります。Game of Lifeの用語では、これはB1/Sです。

たとえば、これは長さ10、期間62のワイヤです。

ここに画像の説明を入力してください

ルール

  • 入力、nは、単一の正の整数です。
  • 出力は、長さnのワイヤの周期を示す単一の整数でなければなりません。
  • 開始状態は、ワイヤの一端にある単一の電子です。
  • 期間には必ずしも開始状態が含まれるわけではありません。一部の長さは開始状態に戻ることはありませんが、それらはすべて周期的です。
  • 静的ワイヤ(つまり、電子のないワイヤ)の周期は1です。
  • 境界条件は周期的ではありません。つまり、ワイヤはトロイダルではありません。

テストケース

このリストを作成してくれたorlpに感謝します。(n = 27まで検証しました。)

1 1
2 2
3 1
4 6
5 4
6 14
7 1
8 14
9 12
10 62
11 8
12 126
13 28
14 30
15 1
16 30
17 28
18 1022
19 24
20 126
21 124
22 4094
23 16
24 2046
25 252
26 1022
27 56
28 32766
29 60
30 62
31 1
32 62
33 60
34 8190
35 56
36 174762
37 2044
38 8190
39 48
40 2046
41 252
42 254
43 248
44 8190
45 8188

Game-of-Life-esqueシミュレーター:バリエーションオブライフで、n = 2から21までのテストケースを見ることができます。


編集:ここでのシーケンスはA268754として公開されています


それらのすべてが周期的であると期間はで上位囲まれている2^n-1ことは「ワイヤ」の可能性ゼロでない状態の数だから、
ルイス・Mendo

@LuisMendo:実際には、電子が隣接することはないため、上限は小さくなります。正確にどれだけ少ないかはわかりません。
エレンディアスターマン

The period does not necessarily include the starting state. Some lengths never return to the starting state, but all of them are periodic.例はありますか?
edc65

@ edc65:長さ5のワイヤが最小の例です。
エレンディアスターマン

1
さらに強く、電子は奇数と偶数の位置を交互に繰り返すため、周期は最大2 ^(n / 2 + 1)です。
-xnor

回答:


10

Python 2、148 142 87バイト

n=input()
p=l=1
t=1
h=2
while t!=h:
 if p==l:t,l,p=h,0,p*2
 h=h/2^h*2%2**n;l+=1
print l

ブレントのサイクル検出アルゴリズムを使用するため、実際に高速で実行されます。


また、Pythonでアニメーションを作成しました(2と3の両方の作業)。pyglet実行する必要があります。次を実行して、アニメーションを表示できます。

python -m pip install --user pyglet
curl -s https://gist.githubusercontent.com/orlp/f32d158130259cbae0b0/raw/ | python

(実行する前に要旨をダウンロードしてコードを調べてください。)+キーと-キーを押して、視覚化されるnを増減できます。


そして最後に、この数字列をさらに調査することに興味がある人のために、ここに読みやすいバージョンがあります(これは上記のテストケースを生成するために使用されました):

# Brent's cycle detection, modified from wikipedia.
def electron_period(n):
    wire_mask = (1 << n) - 1
    power = lam = 1
    tortoise, hare = 1, 2
    while tortoise != hare:
        if power == lam:
            tortoise = hare
            power *= 2
            lam = 0
        hare = ((hare << 1) ^ (hare >> 1)) & wire_mask
        lam += 1
    return lam

私はそれが一年以上が過ぎたけど、使ってハッシュライフがすべてでそれをスピードアップしているならば、私は思ったんだけど
ASCIIのみ

7

Mathematica、127バイト

p@n_:=Tr[#2-#]&@@Position[#,Last@#]&@NestWhileList[1~Table~n~ArrayPad~1*18~CellularAutomaton~#&,{1}~ArrayPad~{1,n},Unequal,All]

説明

ルール18

{0,0,0} -> 0
{0,0,1} -> 1
{0,1,0} -> 0
{0,1,1} -> 0
{1,0,0} -> 1
{1,0,1} -> 0
{1,1,0} -> 0
{1,1,1} -> 0

テストケース

p/@Range[10]
(* {1,2,1,6,4,14,1,14,12,62} *)

7

Python 2、68バイト

f=lambda n,k=1,l=[]:k in l and-~l.index(k)or f(n,k/2^k*2%2**n,[k]+l)

サイクルの検出は改善される可能性がありますが、反復ステップは素晴らしいです。

k -> k/2^k*2%2**n

配列を2進数として表すことにより、左に1つ、右に1つシフトしkたXORを取得し、バイトとして切り捨てることで更新を行うことができます。k/2*2n%2**n


4

Pythonの3 2、134の 121 118バイト

Q=input()
h=[]
n=[0,1]+Q*[0]
while n not in h:h+=[n];n=[0]+[n[d]^n[d+2] for d in range(Q)]+[0]
print len(h)-h.index(n)

基本的に私のPythの回答と同じですが、Pythonの特定の組み込み関数が不足しているため、多少適合させました。

ゴルフされていないバージョン:

length = input()
history = []
new = [0] + [1] + length*[0]
while new not in history:
    history += [new]
    new = [0] + [new[cell]^new[cell+2] for cell in range(length)] + [0]
print len(history) - history.index(new)

4

Pyth、39 36バイト

L++Zmx@bd@bhhdQZ-lJ.uyN.[,Z1ZQ)xJyeJ

「累積固定小数点」関数を使用して、構成が繰り返される直前まで反復し、すべての中間構成をリストのリストとして返します。これは、ルールが決定的であり、次世代の構成が現在の構成の関数であるため機能します。これは、同じ構成が再び表示されると、オートマトンがサイクルを完了したことを意味します。

(サイクルの最後の反復)に達した後、「history」リストの最後の要素でnext-gen関数をもう一度呼び出して、次の構成(サイクルの開始構成)を取得します。履歴でそのインデックスを見つけます。現在の期間は、単純に長さ(1 +サイクル終了のインデックス)-サイクル開始のインデックスです。

pythonic擬似コードの場合:

                  Z = 0
                  Q = eval(input())
L                 def y(b):                # generates next-gen from current(param)
  ++Zm                return [Z] + map(    # adds head zero padding
    x@bd@bhhd             lambda d: b[d] ^ b[1+ 1+ d],  # xor the states of adjacent cells
    Q                     range(Q))        # implicit range in map
    Z                     + [Z]            # adds end zero padding
-lJ.uyN.[,Z1ZQ)   J = repeatTilRecur(lambda N,Y:y(N), padRight([Z,1],Z,Q)); print( len(J) -
                  # N:value; Y:iteration count
  JxJyeJ              J.index( y( J[-1] ) ) )

テストスイートはサーバーがそれを強制終了するのに時間がかかりすぎるため、通常のプログラムを使用して1つずつテストするか、Pyth(インストールしていない場合)をインストールしてスクリプトを使用してテストする必要があります。


4

ゼリー、19 18 17バイト

H^Ḥ%®
2*©Ç‘СUµiḢ

このコードは最初の2 n状態を計算するため、特に高速でもメモリ効率もよくありません...

オンラインでお試しください!または、最初の16個のテストケースを確認します。

代替バージョン、13バイト(非競合)

この課題より後のバージョンのJellyには、ループ検出が組み込まれているため、より短く効率的なソリューションを実現できます。

H^Ḥ%®
2*©ÇÐḶL

これにより、最後のテストケースが簡単に処理されます。オンラインでお試しください!

使い方

2*©Ç‘СUµiḢ    Main link. Input: n (integer)

2*             Compute 2 ** n.
  ©            Store the result in the register.
     С        Do the following:
   Ç             Apply the helper link, which updates the state, ...
    ‘            2 ** n + 1 times.
               Collect all 2 ** n + 2 intermediate results in a list.
       U       Upend; reverse the list of results.

        µ      Begin a new, monadic chain. Argument: R (list of results)
          Ḣ    Yield and remove the first element of R (final state).
         i     Find its first index in the remainder or R.
               This is the length of the loop.

H^Ḥ%®        Helper link. Argument: s (state, integer)

H            Halve s. This yields a float, but ^ will cast to integer.
  Ḥ          Double s.
 ^           Compute (s ÷ 2) ^ (s × 2).
    ®        Retrieve the value stored in the register (2 ** n).
   %         Compute ((s ÷ 2) ^ (s × 2)) % (2 ** n).

ヘルパーリンクは最初の反復で2 nに適用され、有効な状態をエンコードしないことに注意してください。ただし、((2 n ÷2)^(2 n ×2))%2 n =(2 n-1 + 2 n + 1)%2 n = 2 n-1は、可能な開始状態の1つです。

2 n + 1回ループするため、状態が2回発生することが保証され、ループ検出が成功します。


3

CJam、41 34 31 27 25バイト

3バイトを節約してくれたDennisに感謝します。彼のゼリーの答えからアイデアを借りることで、さらに4人節約できました。

2ri#_){__4*^2/W$%}*]W%(#)

ここでテストしてください。

説明

実際のビットのリストを使用する代わりに、ワイヤーを単純に整数(ビットは電子の位置を示す)として表しています。状態は、かなり単純なビットごとの計算によって更新されます。

スタック上のすべての中間結果を収集して期間を見つけるには、2 n-1 +1ステップのシミュレーションを実行し、最後に最後の状態が発生してからの要素数(プラス1)として期間を決定します。

コードの内訳は次のとおりです。

2ri#   e# Compute 2^n. This has a 1 in the n+1-th bit and zeroes below it. This is
       e# itself not a valid state but will be turned into 2^(n-1) by the first
       e# update.
_)     e# Duplicate and increment to get number of steps to simulate.
{      e# Repeat that many times...
  __   e#   Duplicate the last state twice.
  4*   e#   Multiply by 4, shifting all bits to the left by two positions.
  ^    e#   XOR - we only keep keep those cells where we have exactly one 1-bit
       e#   between both copies, i.e. those that neighboured a single electron
       e#   but shifted up by one position. We don't need handle the survival rule
       e#   explicitly, since electrons can never be adjacent in the first place.
  2/   e#   Divide by 2 shifting all bits back to the right again.
  W$   e#   Copy the initial number 2^n.
  %    e#   Modulo - this simply sets the first bit to 0.
}*
]      e# Wrap all states in an array.
W%     e# Reverse it.
(      e# Pull off the latest state.
#      e# Find its position in the remainder of the array.
)      e# Increment.

2

JavaScriptの(ES6)99 104

n=>eval("a=[...Array(n)];k={};for(a[0]=i=1;!k[a=a.map((v,i)=>v?0:a[i-1]^a[i+1])];k[a]=i++);i-k[a]")

テスト

f = n=>eval("a=[...Array(n)];k={};for(a[0]=i=1;!k[a=a.map((v,i)=>v?0:a[i-1]^a[i+1])];k[a]=i++);i-k[a]")

console.log = x => O.textContent += x + '\n';

;[...Array(45)].map((_, i) => console.log(++i + ' ' + f(i)))
<pre id=O></pre>


2

Haskell、170バイト

x!p境界内にある場合、インデックスpの要素を返します。それ以外の場合は0。 n次のステップを計算します。 g i与えi番目のステップを。 c xで始まる場合、期間を返しxます。 fすべてをまとめてラップします。

n x|l<-length x-1=[mod(x!(p-1)+x!(p+1))2|p<-[0..l],let y!q|q<0=0|q>=l=0|1<2=y!!p]
c x=[i-j|i<-[1..],j<-[0..i-1],let g k=iterate n x!!k,g i==g j]!!0
f n=c$1:map(*0)[2..n]

(注:完全な機能を備えていないハグインタープリターを備えた電話から投稿されたため、タイプミスがある可能性があります。)


2

MATL38 37 36 35バイト

1Oi(`t0Y)5BX+8L)1=vt6#Xut0)=fdt?w}A

これは、新しい状態が前の状態のいずれかに等しくなるまで新しい状態を計算し続けるループを使用します。各状態は、ゼロと1のベクトルです。これらのベクトルは、成長する2D配列の行として保存されます。

各新しい状態の計算は、現在の状態とシーケンスを畳み込み[1,0,1]、中央部分のみを保持し、0そうでないエントリに設定することによって行われ1ます。

編集(2016年5月13日)次のリンクのコードは、この回答が作成された後に言語に導入された変更に従ってわずかに変更されました

オンラインでお試しください!

1Oi(            % create initial vector [1,0,0,...,0], with size equal to input
`               % do...while loop
  t0Y)          %   duplicate. Get last row of array: most recent vector
  5BX+8L)       %   compute new vector by convolving the most recent one
                %   with [1,0,1] and keeping only the central part
  1=            %   set ones to 1, rest to 0
  v             %   append to 2D array
  t6#Xu         %   compute vector of unique numeric labels, so that equal rows
  t0)=f         %   indices of entries whose value equals that of the last entry.
                %   This will contain the index of the last entry and possibly
                %   another index, in which case we've found a repetition
  d             %   this will either be empty (which is falsy) or contain the
                %   period, which is a nonzero number (and thus truthy)
  t?            %   duplicate. If non-empty (and nonzero)
    w           %     swap to put the 2D-array at the top of the stack. This is
                %     falsy, because it contains at least one zero, even in the
                %     n=1 case (the array is initiallized to 0 in that case)
                %     So the loop will terminate, with the period left on the stack
  }             %   else
    A           %     this transforms the empty array at the top of the stack
                %     into a true value, so that the loop will continue
                %   implicitly end if
                % implicitly end loop
                % implicitly display stack contents (period)

1

Perl 6、81バイト

{my@h=my$w=2;@h.push($w=$w/2+^$w*2%2**$_)while 2>@h.grep($w);[R-] @h.grep($w,:k)}

少し広げて

-> $n {
    my @history = my $wire = 2;
    while 2 > @history.grep($wire) {
        @history.push($wire = $wire/2 +^ $wire*2 % 2**$n)
    }
    [R-] @history.grep($wire,:k)
}

ちょっとした説明:

  • [op]opを使用してリストを縮小します。たとえば、[+] @list合計します@list
  • Ropに与えられた引数を逆にするメタ操作です。たとえば、1 R- 3結果は2になります。

1

C ++、211バイト

ゴルフ

#include <bitset>
#include <cstdio>
#define B std::bitset<1<<10>
B m,t(1),h(2);int main() {int p,l;for(scanf("%d",&p);p--;m.set(p));
for(p=l=1;t!=h;h=(h>>1^h<<1)&m,l++)p==l?t=h,p*=2,l=0:0;return !printf("%d",l);}

読みやすくするために空白を追加しました

#include <bitset>
#include <cstdio>
#define B std::bitset<1<<10>
B m,t(1),h(2);
int main() {    
    int p,l;
    for(scanf("%d",&p);p--;m.set(p));
    for(p=l=1;t!=h;h=(h>>1^h<<1)&m,l++)p==l?t=h,p*=2,l=0:0;    
    return !printf("%d",l);
}

C ++のビットセットの良い習慣。また、ブレントのサイクル検出アルゴリズム(@orlpで使用)について学習する優れた教育




弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.