main
John Lauer Corrected Astra ESC routing: native zero-open result, full accounting and voiceover handoff a80479d 23d ago
from planner import *
import planner as m,ast,random,copy,sys
src=Path('repair2.py').read_text().replace('width/2-.04','width/2-.005')
exec(compile(ast.Module(body=[n for n in ast.parse(src).body if isinstance(n,ast.FunctionDef)],type_ignores=[]),'functions','exec'),globals())
base=json.load(open(sys.argv[1] if len(sys.argv)>1 else 'repair3.json'))
def loadplans(plans):
 m.copper.clear()
 for plan in plans:
  for path in plan['paths']:register(plan['net'],path,plan['width'])
def gaps(plans):
 return {p['net']:len(groups(p['net']))-1 for p in plans if p['net'] not in ['GND','+3V3'] and len(groups(p['net']))>1}
def routeplan(plan):
 net=plan['net'];width=plan['width'];gr=groups(net);tried=set()
 while len(gr)>1:
  pairs=sorted((math.hypot(p['x']-q['x'],p['y']-q['y']),i,j,p,q) for i,pp in enumerate(gr) for j,qq in enumerate(gr[:i]) for p in pp for q in qq)
  found=False
  for dist,i,j,p,q in pairs:
   key=(p['name'],q['name'])
   if key in tried:continue
   tried.add(key);route=search2(masks(net,width),p,(q['x'],q['y']),[(0,t['g']) for t in gr[j]],width)
   if route:
    register(net,route,width);plan['paths'].append(route);found=True;break
  if not found:break
  gr=groups(net)
 return len(gr)-1
loadplans(base);initial=gaps(base);print('INITIAL',initial,flush=True)
# Rip up complete affected signal nets and re-route all of their connections.
selected=set(initial)|{'/HSE_IN','/HSE_OUT','/MCU_LED','/TIM1_CH2N_INLB','/TIM1_CH3N_INLA','/TIM1_CH2_INHB','/DRV_GHA','/DRV_GHB','/DRV_GHC','/DRV_BSTB','/DRV_BSTC','/DRV_GLA'}
best=sum(initial.values())
for iteration in range(30):
 random.seed(iteration)
 plans=copy.deepcopy(base);sel=[p for p in plans if p['net'] in selected]
 for p in sel:p['paths']=[]
 loadplans(plans)
 early=[p for p in sel if p['net'] in initial];late=[p for p in sel if p['net'] not in initial]
 if iteration:random.shuffle(early);random.shuffle(late)
 for plan in early+late:
  missing=routeplan(plan);print(iteration,plan['net'],missing,flush=True)
 remaining=gaps(plans);score=sum(remaining.values());print('ROUND',iteration,score,remaining,flush=True)
 Path(f'evidence/ripup-{iteration}.json').write_text(json.dumps(plans))
 if score<best:
  best=score;Path('ripup-best.json').write_text(json.dumps(plans,indent=2));print('BEST',best,flush=True)
 if score==0:break
 # Expand to routes that crowd newly unresolved pads; keep fixed planes intact.
 if iteration%3==2:
  for p in plans:
   if p['net'] not in remaining:continue
   for pad in by[p['net']]:
    for q in base:
     if q['net'] in selected or q['net'] in ['GND','+3V3']:continue
     for path in q['paths']:
      coords=[(v['x'],v['y']) if isinstance(v,dict) else v for v in path]
      if len(coords)>1 and LineString(coords).distance(pad['g'])<.9:selected.add(q['net']);break
  print('EXPAND',sorted(selected),flush=True)