Python、ゴルフのスパゲッティコード
まあ。
def will_it_halt(instructions):
tape_length = 1
LOOP_BOUND = 1000
registry = [0] * tape_length
pos = 0
jumpbacks = []
reached_states = set()
pos_instructions = 0
while True:
letter = instructions[pos_instructions]
if letter == "+":
registry[pos] = (registry[pos] + 1) % 256
elif letter == "-":
registry[pos] = (registry[pos] - 1) % 256
elif letter == ">":
pos += 1
if pos >= tape_length:
registry += [0]*tape_length
tape_length = len(registry)
elif letter == "<":
pos -= 1
if pos <= 0:
registry = [0]*tape_length+registry
tape_length = len(registry)
pos += tape_length
elif letter == "[":
if registry[pos] == 0:
nests = 1
while nests:
pos_instructions += 1
if instructions[pos_instructions] == "[": nests += 1
elif instructions[pos_instructions] == "]": nests -= 1
if jumpbacks == []:
reached_states.clear()
else:
jumpbacks.append(pos_instructions-1)
elif letter == "]":
stripped_registry = [str(x) for x in registry if x != 0]
translated_pos = pos - (len(registry) - len(stripped_registry))
state = (translated_pos, pos_instructions, ".".join(stripped_registry))
if state in reached_states: return "Does not halt"
elif len(reached_states) > LOOP_BOUND: return "Unknown"
else:
reached_states.add(state)
pos_instructions = jumpbacks.pop()
pos_instructions += 1
if pos_instructions >= len(instructions): break
return "Halts"
問題のかなり強力な解決策:bfコードを実行するだけです。テープの長さは任意に長く、個々のセルは256で折り返すと想定します。すべてのループの終わりに、セットでテープの状態を保存します。状態は形式です(テープ上の私たちの位置、指示上の私たちの位置、先行する0が取り除かれたテープの外観)。
同じ状態を2回保存すると、無限ループのどこかにいるため、プログラムは停止しません。1,000以上の州を保存している場合は、損失を削減し、不明を返します。ループを抜けたら、大きなループになっていないかどうかを確認します。そうでない場合は、以前の状態が二度と表示されることはありません(少なくとも、命令の位置は常に異なります)。これにより、状態のセットをクリアできます。
これにより、ループが1,000回の反復より長くないBFプログラムや、ループで1,000回の反復の前に状態を繰り返す多くのプログラムが正確に判断されます。ただし、すべてではありません。「{100万+がここにある} [-]> + [+-]」のようなものは最終的に状態を繰り返しますが、[-]ループは最初に1,000回の繰り返しを通過します。
いくつかの例:
>+>->+>-
ループがないため、最後に到達して停止します。
+[+]
ループは256回の反復後に終了するため、ループは最後に到達して停止します。
+[+-]
最終的に状態(0,5、 "1")を繰り返すため、停止しません。
+[->+]
これは状態を繰り返しませんが、ループが終了することはないため、「不明」と出力されます。しかし、プログラムはここで詐欺のようなものです。テープに位置を保存する代わりに、元のレジストリとストリップされたレジストリの間にオフセットを追加します。ループがテープをいくつかのスペースだけ平行移動する場合、それは(ライフグライダーのように)テープを無期限に平行移動し続けるので、停止しないと言えます。
+[>+]
翻訳しない、状態を繰り返さない、不明と出力する。
+++++++++++[-]
これは停止しますが、LOOP_BOUNDが10の場合は「不明」と出力されます。
これをよりスマートにする方法はいくつかあります。LOOP_BOUNDを増やして、未知数の数を減らすことは明らかです。ネストされたループをよりスマートに処理できます。BB番号とループのサイズを工夫して、何かが停止するかどうかをより適切に検出できるかもしれませんが、CSでもPythonでもまだそれを行うには不十分です。
>
最後に追加されたs(これらはPが停止した場合に停止するため)、および他のすべての入力でSの回答を出力 この新しいソリューションを解きS.よりも無限に多くの問題