--routeMakeBlue.mesa
--1> tidy up rectangle overlaps not visable to user
-- Remove complete overlaps by deleting something
-- Reduce or extend partial overlaps so all connecting things
-- overlap by the width of one wire (2 or 3 lambda)
-- Break long wires into segments ending at contacts or junctions
--2> turn as much as possible of the red wires to blue
-- only works when contacts extend up and right from junctions.
-- PROBLEM current logic doesn't break red wires at junctions
DIRECTORY RouteDefs;
RouteMakeBlue:PROGRAM IMPORTS RouteDefs EXPORTS RouteDefs =BEGIN
OPEN RouteDefs;
Error:SIGNAL=CODE;
--Silicon:TYPE=RECORD[pos,pos2:CoordL←[0,0],level:What←both,
-- solid:BOOLEAN←FALSE, circuit:Circuit←0];
list:SiliconListPtr←NIL;
big:Lambda;
MakeBlue:PUBLIC PROCEDURE=BEGIN
--IF TRUE THEN RETURN;
big←problem.chipSize.x;
MakeBlueX[];
--EnumerateSilicon[Rotate];
--MakeBlueX[];
--EnumerateSilicon[RotateBack];
END;
Rotate:PROCEDURE[s:SiliconPtr]=BEGIN
t:Lambda←s.pos.y;
s.pos.y←big-s.pos2.x;
s.pos2.x←s.pos2.y;
s.pos2.y←big-s.pos.x;
s.pos.x←t;
END;
RotateBack:PROCEDURE[s:SiliconPtr]=BEGIN
t:Lambda←s.pos.x;
s.pos.x←big-s.pos2.y;
s.pos2.y←s.pos2.x;
s.pos2.x←big-s.pos.y;
s.pos.y←t;
END;
MakeBlueX:PROCEDURE=BEGIN
EnumerateSilicon[TidyDoubleContacts];
EnumerateSilicon[TidyWireToContacts];
EnumerateSilicon[TidyWireToWire];
EnumerateSilicon[TidyButtingEnds];
EnumerateSilicon[SplitWiresAtContacts];
ScavengeSilicon[];
EnumerateSilicon[MakeRedBlue];
EnumerateSilicon[TidyWireToContacts];
ScavengeSilicon[];
END;
TidyDoubleContacts:PROCEDURE[s:SiliconPtr]=BEGIN
IF s.level#both THEN RETURN;
FOR sl:SiliconListPtr←layout,sl.t UNTIL sl=NIL DO
s2:SiliconPtr=sl.h;
IF s2.level=both AND s2.pos=s.pos AND s2#s THEN Destroy[s2];
ENDLOOP;
END;
TidyWireToContacts:PROCEDURE[s:SiliconPtr]=BEGIN
seenRed,seenBlue:BOOLEAN←FALSE;
IF s.level#both THEN RETURN;
FOR sl:SiliconListPtr←layout,sl.t UNTIL sl=NIL DO
s2:SiliconPtr=sl.h;
w:INTEGER=IF s2.level=red THEN 2 ELSE 3;
IF s2.level=both THEN LOOP;
IF s2.pos2.y-s2.pos.y=w AND s2.pos.y-s.pos.y IN [0..4-w] THEN BEGIN
IF s2.pos.x-s.pos.x IN [0..4] THEN s2.pos.x←s.pos.x;
IF s2.pos2.x-s.pos.x IN [0..4] THEN s2.pos2.x←s.pos.x+w;
IF s2.level=red THEN seenRed←TRUE ELSE seenBlue←TRUE;
END;
IF s2.pos2.x-s2.pos.x=w AND s2.pos.x-s.pos.x IN [0..4-w] THEN BEGIN
IF s2.pos.y IN [s.pos.y..s.pos.y+4] THEN s2.pos.y←s.pos.y;
IF s2.pos2.y IN [s.pos.y..s.pos.y+4] THEN s2.pos2.y←s.pos.y+w;
IF s2.level=red THEN seenRed←TRUE ELSE seenBlue←TRUE;
END;
ENDLOOP;
IF ~seenRed OR ~seenBlue THEN Destroy[s];
END;
TidyWireToWire:PROCEDURE[s:SiliconPtr]=BEGIN
w:INTEGER=IF s.level=red THEN 2 ELSE 3;
IF s.level=both THEN RETURN;
IF ~(s.pos2.y-s.pos.y=w) THEN RETURN;
FOR sl:SiliconListPtr←layout,sl.t UNTIL sl=NIL DO
s2:SiliconPtr=sl.h;
IF s2.level#s.level THEN LOOP;
IF ~(s2.pos2.x-s2.pos.x=w) THEN LOOP;
IF s=s2 THEN LOOP;
IF s.pos.y IN [s2.pos.y-w..s2.pos2.y+w) THEN BEGIN
IF s.pos.x IN [s2.pos.x..s2.pos2.x] THEN s.pos.x←s2.pos.x;
IF s.pos2.x IN [s2.pos.x..s2.pos2.x] THEN s.pos2.x←s2.pos2.x;
END;
IF s2.pos.x IN [s.pos.x-w..s.pos2.x+w) THEN BEGIN
IF s2.pos.y IN [s.pos.y..s.pos2.y] THEN s2.pos.y←s.pos.y;
IF s2.pos2.y IN [s.pos.y..s.pos2.y] THEN s2.pos2.y←s.pos2.y;
END;
ENDLOOP;
END;
SplitWiresAtContacts:PROCEDURE[s:SiliconPtr]=BEGIN
w:INTEGER=IF s.level=red THEN 2 ELSE 3;
IF s.level=both THEN RETURN;
IF s.pos2.y-s.pos.y=w
THEN FOR sl:SiliconListPtr←layout,sl.t UNTIL sl=NIL DO
s2:SiliconPtr=sl.h;
IF s2.pos.x IN (s.pos.x..s.pos2.x-w)
AND s.pos.y IN (s2.pos.y-w-w..s2.pos2.y+w)
AND (s2.level=both OR s2.level=s.level AND s.pos2.y#s.pos.y+w)
THEN SplitWiresAtContacts[SplitWire[s,s2.pos.x,TRUE]];
ENDLOOP
ELSE FOR sl:SiliconListPtr←layout,sl.t UNTIL sl=NIL DO
s2:SiliconPtr=sl.h;
IF s2.pos.y IN (s.pos.y..s.pos2.y-w)
AND s.pos.x IN (s2.pos.x-w-w..s2.pos2.x+w)
AND (s2.level=both OR s2.level=s.level AND s.pos2.x#s.pos.x+w)
THEN SplitWiresAtContacts[SplitWire[s,s2.pos.y,FALSE]];
ENDLOOP;
END;
SplitWire:PROCEDURE[s:SiliconPtr,where:Lambda,hor:BOOLEAN]
RETURNS[s2:SiliconPtr]=BEGIN
w:INTEGER=IF s.level=red THEN 2 ELSE 3;
listS:SiliconListPtr←AllocateList[];
s2←AllocateSilicon[];
s2↑←s↑;
listS↑←[s2,layout];
layout←listS;
IF hor THEN {s.pos2.x←where+w; s2.pos.x←where}
ELSE {s.pos2.y←where+w; s2.pos.y←where}
END;
TidyButtingEnds:PROCEDURE[s:SiliconPtr]=BEGIN
w:INTEGER=IF s.level=red THEN 2 ELSE 3;
IF s.level=both THEN RETURN;
FOR sl:SiliconListPtr←layout,sl.t UNTIL sl=NIL DO
s2:SiliconPtr=sl.h;
SELECT TRUE FROM
s2.level#s.level OR s2=s => LOOP;
s2.pos.y=s.pos.y AND s2.pos2.y=s.pos2.y => SELECT TRUE FROM
s2.pos.x<=s.pos.x AND s2.pos2.x>=s.pos2.x => {Destroy[s]; RETURN};
s2.pos.x>=s.pos.x AND s2.pos2.x<=s.pos2.x => {Destroy[s2]; LOOP};
s2.pos.x<s.pos.x=>IF s2.pos2.x>=s.pos.x THEN s.pos←s2.pos ELSE LOOP;
ENDCASE=>IF s.pos2.x >=s2.pos.x THEN s.pos2←s2.pos2 ELSE LOOP;
s2.pos.x=s.pos.x AND s2.pos2.x=s.pos2.x => SELECT TRUE FROM
s2.pos.y<=s.pos.y AND s2.pos2.y>=s.pos2.y => {Destroy[s]; RETURN};
s2.pos.y>=s.pos.y AND s2.pos2.y<=s.pos2.y => {Destroy[s2]; LOOP};
s2.pos.y<s.pos.y=>IF s2.pos2.y>=s.pos.y THEN s.pos←s2.pos ELSE LOOP;
ENDCASE=>IF s.pos2.y >=s2.pos.y THEN s.pos2←s2.pos2 ELSE LOOP;
ENDCASE=>LOOP;
Destroy[s2];
TidyButtingEnds[s];
RETURN;
ENDLOOP;
END;
Stuff:TYPE=RECORD[where:CoordL,red,blue:Four,con,passing:SiliconPtr←NIL, cellNearby,onCell:BOOLEAN←FALSE];
Four:TYPE=RECORD[n,s,e,w:SiliconPtr←NIL];
l,r:Stuff←[];
progress:BOOLEAN;
thisWire:SiliconPtr←NIL;--to save passing it
MakeRedBlue:PROCEDURE[s:SiliconPtr]=BEGIN
LastStuff:PROCEDURE[p:POINTER TO Stuff] RETURNS[b:BOOLEAN]=
{b←IF hor THEN p.where.x>=s.pos2.x-2 ELSE p.where.y>=s.pos2.y-2};
hor:BOOLEAN=s.pos2.y-s.pos.y=2;
IF s.level#red THEN RETURN;
thisWire←s;
MakeList[s];
progress←FALSE;
WhatsAtL[hor,s.pos];
UNTIL LastStuff[@l] DO
WhatsAtR[hor,s];
IF hor AND r.where.x>s.pos2.x-2 THEN Error;
IF ~hor AND r.where.y>s.pos2.y-2 THEN Error;
IF hor THEN ProcessH[s] ELSE ProcessV[s];
IF s.level#red OR s.pos=outOfSight OR LastStuff[@r] THEN EXIT;
IF ~progress OR r.where=[s.pos2.x-2,s.pos2.y-2]
THEN l←r ELSE WhatsAtL[hor,r.where];
ENDLOOP;
ScavengeList[];
END;
WhatsAtL:PROCEDURE[hor:BOOLEAN,pos:CoordL]=BEGIN
l←[];
l.where←pos;
FOR sl:SiliconListPtr←list,sl.t UNTIL sl=NIL DO
s:SiliconPtr=sl.h;
parallel:BOOLEAN=IF hor THEN s.pos2.y-s.pos.y<4 ELSE s.pos2.x-s.pos.x<4;
IF s.pos.y=pos.y AND s.pos.x IN [pos.x-2..pos.x+2]
THEN SELECT s.level FROM
both=>l.con←s;
red =>{IF parallel THEN l.red.e←s ELSE l.red.n←s};
blue=>{IF parallel THEN l.blue.e←s ELSE l.blue.n←s};
ENDCASE=>Error
ELSE SELECT s.level FROM
red=>IF s.pos2.y=pos.y+2 AND s.pos2.x IN [pos.x-2..pos.x+4] THEN
{IF parallel THEN l.red.w←s ELSE l.red.s←s};
blue=>BEGIN
IF s.pos2.y=pos.y+3 AND s.pos2.x IN [pos.x-2..pos.x+4] THEN
{IF parallel THEN l.blue.w←s ELSE l.blue.s←s}
ELSE IF pos.x IN (s.pos.x-7..s.pos2.x+3)
AND pos.y IN (s.pos.y-7..s.pos2.y+3)
AND (l.passing=NIL OR parallel) THEN l.passing←s;
END;
ENDCASE;
ENDLOOP;
CellNearby[@l];
END;
WhatsAtR:PROCEDURE[hor:BOOLEAN,ss:SiliconPtr]=BEGIN
end:CoordL=[ss.pos2.x-2,ss.pos2.y-2];
pos:CoordL=[l.where.x+(IF hor THEN 3 ELSE 0),l.where.y];
w:CoordL←end;
FOR dummy:INTEGER IN [0..2) DO
r←[];
FOR sl:SiliconListPtr←list,sl.t UNTIL sl=NIL DO
s:SiliconPtr=sl.h;
h:INTEGER=SELECT s.level FROM blue=>3,red=>2,ENDCASE=>4;
sEnd:CoordL=[s.pos2.x-h,s.pos2.y-h];
color:POINTER TO Four=IF s.level=blue THEN @r.blue ELSE @r.red;
parallel:BOOLEAN = hor=(s.pos2.y-s.pos.y<4);
IF s=ss THEN LOOP;
IF s.level=both THEN BEGIN
IF hor THEN BEGIN
IF s.pos.y#pos.y THEN LOOP;
IF s.pos.x IN (pos.x..w.x) THEN {r←[]; w.x←s.pos.x; Error};
END
ELSE BEGIN
IF s.pos.x#pos.x THEN LOOP;
IF s.pos.y IN (pos.y..w.y) THEN {r←[]; w.y←s.pos.y; Error};
END;
IF s.pos.y=w.y AND s.pos.x-w.x IN [-2..2] THEN r.con←s;
LOOP;
END;
IF hor THEN BEGIN
IF s.level=blue AND pos.y IN (s.pos.y-7..s.pos2.y+3)
AND pos.y#s.pos.y AND pos.y#s.pos2.y-3 THEN BEGIN
IF s.pos.x IN (pos.x..w.x) THEN {r←[]; w.x←s.pos.x};
IF s.pos.x =w.x THEN r.passing←s;
END;
IF pos.y NOT IN [s.pos.y..s.pos2.y-h] THEN LOOP;
IF ~parallel THEN BEGIN
IF s.pos.x IN (pos.x..w.x) THEN {r←[]; w.x←s.pos.x};
IF s.pos.x-w.x IN [0..2] AND s.pos.y=w.y THEN color.n←s;
IF s.pos.x-w.x IN [0..2] AND s.pos2.y=w.y+h THEN color.s←s;
END;
END
ELSE BEGIN
IF s.level=blue AND pos.x IN (s.pos.x-7..s.pos2.x+3)
AND pos.x#s.pos.x AND pos.x#s.pos2.x-3 THEN BEGIN
IF s.pos.y IN (pos.y..w.y) THEN {r←[]; w.y←s.pos.y};
IF s.pos.y=w.y THEN r.passing←s;
END;
IF pos.x NOT IN [s.pos.x..s.pos2.x-h] THEN LOOP;
IF ~parallel THEN BEGIN
IF s.pos.y IN (pos.y..w.y) THEN {r←[]; w.y←s.pos.y};
IF s.pos.y=w.x AND s.pos.x=w.x THEN color.e←s;
IF s.pos.x=w.x AND s.pos2.x=w.x+h THEN color.w←s;
END;
END;
IF parallel
THEN {IF s.pos=w THEN color.e←s; IF sEnd=w THEN color.w←s}
ELSE {IF s.pos=w THEN color.n←s; IF sEnd=w THEN color.s←s};
ENDLOOP;
ENDLOOP;
IF w=end THEN r.red.w←ss;
r.where←w;
CellNearby[@r];
END;
CellNearby:PROCEDURE[stuff:POINTER TO Stuff]=BEGIN
pos:CoordL=stuff.where;
stuff.cellNearby←FALSE;
stuff.onCell←FALSE;
FOR cl:CellListPtr←problem.cells,cl.t UNTIL cl=NIL DO
cell:CellPtr=cl.h;
IF ~ ( pos.x-cell.pos.x IN [-6..cell.sizeL.x+2]
AND pos.y-cell.pos.y IN [-6..cell.sizeL.y+2])
THEN LOOP;
IF (thisWire.pos.y>cell.pos.y+cell.sizeL.y
OR thisWire.pos2.y<cell.pos.y
OR thisWire.pos.x>cell.pos.x+cell.sizeL.x
OR thisWire.pos2.x<cell.pos.x)
THEN {stuff.cellNearby←TRUE; RETURN};
IF thisWire.pos.y=cell.pos.y+cell.sizeL.y AND pos.y=thisWire.pos.y
THEN FOR el:SignalListPtr←cell.signals,el.t UNTIL el=NIL DO
e:SignalPtr=el.h;
IF e.side=n AND cell.pos.x+e.offset=pos.x AND e.level=both
THEN stuff.onCell←TRUE;
ENDLOOP;
IF thisWire.pos.x=cell.pos.x+cell.sizeL.x AND pos.x=thisWire.pos.x
THEN FOR el:SignalListPtr←cell.signals,el.t UNTIL el=NIL DO
e:SignalPtr=el.h;
IF e.side=e AND cell.pos.y+e.offset=pos.y AND e.level=both
THEN stuff.onCell←TRUE;
ENDLOOP;
IF thisWire.pos2.y=cell.pos.y AND pos.y+2=thisWire.pos2.y
THEN FOR el:SignalListPtr←cell.signals,el.t UNTIL el=NIL DO
e:SignalPtr=el.h;
IF e.side=s AND cell.pos.x+e.offset=pos.x AND e.level=both
THEN stuff.onCell←TRUE;
ENDLOOP;
IF thisWire.pos2.x=cell.pos.x AND pos.x+2=thisWire.pos2.x
THEN FOR el:SignalListPtr←cell.signals,el.t UNTIL el=NIL DO
e:SignalPtr=el.h;
IF e.side=w AND cell.pos.y+e.offset=pos.y AND e.level=both
THEN stuff.onCell←TRUE;
ENDLOOP;
ENDLOOP;
END;
ProcessH:PROCEDURE[s:SiliconPtr]=BEGIN
hor:BOOLEAN=TRUE;
y:Lambda=s.pos.y;
noBlueRight:BOOLEAN=r.blue=[] AND r.passing=NIL AND ~r.cellNearby;
noBlueLeft: BOOLEAN=l.blue=[] AND l.passing=NIL AND ~l.cellNearby;
noRedLeft: BOOLEAN=l.red.n=NIL AND l.red.s=NIL AND l.red.w=NIL;
noRedRight: BOOLEAN=r.red.n=NIL AND r.red.s=NIL AND r.red.e=NIL;
buttL:BOOLEAN=noBlueLeft AND ~noRedLeft;
buttR:BOOLEAN=noBlueRight AND ~noRedRight;
newx:Lambda= l.where.x+(IF buttL THEN 0 ELSE 7);
newx2:Lambda=r.where.x-(IF buttR THEN 0 ELSE 7);
PassingParallel:PROCEDURE[p:SiliconPtr] RETURNS[BOOLEAN]=BEGIN
RETURN[p#NIL AND p.pos2.y=p.pos.y+3 AND p.pos.y IN [s.pos.y-2..s.pos2.y+2]];
END;
AdjustRight:PROCEDURE=BEGIN
IF r.blue.n=NIL AND r.blue.s=NIL AND l.blue.e#NIL THEN
{s.pos2.x←r.blue.e.pos2.x; Destroy[r.blue.e]};
END;
AdjustLeft:PROCEDURE=BEGIN
IF l.blue.n=NIL AND l.blue.s=NIL AND l.blue.w#NIL THEN
{s.pos.x←l.blue.w.pos.x; Destroy[l.blue.w]};
END;
ExtendRight:PROCEDURE={NewBlueWireH[l.where.x,s.pos.x←newx2]};
ExtendLeft:PROCEDURE={s.pos2.x←newx+2; NewBlueWireH[newx,r.where.x]};
NewBlueWireH:PROCEDURE[p,q:Lambda]={MakeBlueWire[hor,p,y,q-p+3]; Copy[]};
NewRedWireH:PROCEDURE[p,q:Lambda]={MakeRedWire[hor,p,y,q-p+2]; Copy[]};
NewContact:PROCEDURE[x:Lambda]={MakeContact[x,y]; Copy[]};
progress←FALSE;
IF PassingParallel[l.passing] OR PassingParallel[r.passing] OR r.cellNearby OR l.cellNearby THEN RETURN;
IF (l.con#NIL OR buttL) AND (r.con#NIL OR buttR) THEN Bluify[s];
IF l.con#NIL AND r.onCell THEN {Bluify[s]; Destroy[l.con]};
IF r.con#NIL AND l.onCell THEN {Bluify[s]; Destroy[r.con]};
IF l.con#NIL AND r.con#NIL THEN BEGIN --1 case
IF noRedLeft THEN {Destroy[l.con]; AdjustLeft[]};
IF noRedRight THEN {Destroy[r.con]; AdjustRight[]};
END;
IF l.con#NIL AND r.con=NIL THEN BEGIN --9 cases here
k:INTEGER=IF noRedLeft THEN 0 ELSE 14;
IF ~noBlueRight AND l.where.x>=newx2-k THEN RETURN;
IF noRedLeft THEN l.con.pos.x←newx2 ELSE NewContact[newx2];
IF noRedLeft AND (l.blue.n=NIL AND l.blue.s=NIL AND l.blue.w#NIL)
THEN BEGIN l.blue.w.pos2.x←newx2+3;
IF buttR THEN Destroy[s] ELSE s.pos.x←newx2; END
ELSE {IF ~noBlueRight THEN ExtendRight[]};
END;
IF l.con=NIL AND r.con#NIL THEN BEGIN --9 cases here
k:INTEGER=IF noRedRight THEN 0 ELSE 14;
IF ~noBlueLeft AND r.where.x<=newx+k THEN RETURN;
IF noRedRight THEN r.con.pos.x←newx ELSE NewContact[newx];
IF noRedRight AND (r.blue.n=NIL AND r.blue.s=NIL AND r.blue.w#NIL)
THEN BEGIN r.blue.w.pos.x←newx;
IF buttL THEN Destroy[s] ELSE s.pos2.x←newx+2; END
ELSE {IF ~noBlueLeft THEN ExtendLeft[]};
END;
IF l.con=NIL AND r.con=NIL THEN BEGIN
IF newx2<newx THEN RETURN;
IF noBlueLeft AND noBlueRight THEN {NewContact[newx]; NewContact[newx2]};
IF noBlueLeft AND ~noBlueRight THEN {ExtendRight[]; NewContact[newx2];
IF ~noRedLeft THEN NewContact[l.where.x]};
IF ~noBlueLeft AND noBlueRight THEN {ExtendLeft[]; NewContact[newx];
IF ~noRedRight THEN NewContact[l.where.y]};
IF ~noBlueLeft AND ~noBlueRight THEN BEGIN
IF newx2<newx+14 THEN RETURN;
NewContact[newx2];
NewRedWireH[s.pos.x,newx];
NewBlueWireH[newx,newx2];
NewContact[newx];
s.pos.x←newx2;
END;
END;
progress←TRUE;
END;
ProcessV:PROCEDURE[s:SiliconPtr]=BEGIN
hor:BOOLEAN=FALSE;
x:Lambda=s.pos.x;
noBlueRight:BOOLEAN=r.blue=[] AND r.passing=NIL AND ~r.cellNearby;
noBlueLeft: BOOLEAN=l.blue=[] AND l.passing=NIL AND ~l.cellNearby;
noRedLeft: BOOLEAN=l.red.n=NIL AND l.red.s=NIL AND l.red.w=NIL;
noRedRight: BOOLEAN=r.red.n=NIL AND r.red.s=NIL AND r.red.e=NIL;
buttL:BOOLEAN=noBlueLeft AND ~noRedLeft;
buttR:BOOLEAN=noBlueRight AND ~noRedRight;
newy:Lambda= l.where.y+(IF buttL THEN 0 ELSE 7);
newy2:Lambda=r.where.y-(IF buttR THEN 0 ELSE 7);
PassingParallel:PROCEDURE[p:SiliconPtr] RETURNS[BOOLEAN]=BEGIN
RETURN[p#NIL AND p.pos2.x=p.pos.x+3 AND p.pos.x IN [s.pos.x-2..s.pos2.x+2]];
END;
AdjustRight:PROCEDURE=BEGIN
IF r.blue.n=NIL AND r.blue.s=NIL AND l.blue.e#NIL THEN
{s.pos2.y←r.blue.e.pos2.y; Destroy[r.blue.e]};
END;
AdjustLeft:PROCEDURE=BEGIN
IF l.blue.n=NIL AND l.blue.s=NIL AND l.blue.w#NIL THEN
{s.pos.y←l.blue.w.pos.y; Destroy[l.blue.w]};
END;
ExtendRight:PROCEDURE={NewBlueWireH[l.where.y,s.pos.y←newy2]};
ExtendLeft:PROCEDURE={s.pos2.y←newy+2; NewBlueWireH[newy,r.where.y]};
NewBlueWireH:PROCEDURE[p,q:Lambda]={MakeBlueWire[hor,x,p,q-p+3]; Copy[]};
NewRedWireH:PROCEDURE[p,q:Lambda]={MakeRedWire[hor,x,p,q-p+2]; Copy[]};
NewContact:PROCEDURE[y:Lambda]={MakeContact[x,y]; Copy[]};
progress←FALSE;
IF PassingParallel[l.passing] OR PassingParallel[r.passing] OR r.cellNearby OR l.cellNearby THEN RETURN;
IF (l.con#NIL OR buttL) AND (r.con#NIL OR buttR) THEN Bluify[s];
IF l.con#NIL AND r.onCell THEN {Bluify[s]; Destroy[l.con]};
IF r.con#NIL AND l.onCell THEN {Bluify[s]; Destroy[r.con]};
IF l.con#NIL AND r.con#NIL THEN BEGIN
IF noRedLeft THEN {Destroy[l.con]; AdjustLeft[]};
IF noRedRight THEN {Destroy[r.con]; AdjustRight[]};
END;
IF l.con#NIL AND r.con=NIL THEN BEGIN --9 cases here
k:INTEGER=IF noRedLeft THEN 0 ELSE 14;
IF ~noBlueRight AND l.where.y>=newy2-k THEN RETURN;
IF noRedLeft THEN l.con.pos.y←newy2 ELSE NewContact[newy2];
IF noRedLeft AND (l.blue.n=NIL AND l.blue.s=NIL AND l.blue.w#NIL)
THEN BEGIN l.blue.w.pos2.y←newy2+3;
IF buttR THEN Destroy[s] ELSE s.pos.y←newy2; END
ELSE {IF ~noBlueRight THEN ExtendRight[]};
END;
IF l.con=NIL AND r.con#NIL THEN BEGIN --9 cases here
k:INTEGER=IF noRedRight THEN 0 ELSE 14;
IF ~noBlueLeft AND r.where.y<=newy+k THEN RETURN;
IF noRedRight THEN r.con.pos.y←newy ELSE NewContact[newy];
IF noRedRight AND (r.blue.n=NIL AND r.blue.s=NIL AND r.blue.w#NIL)
THEN BEGIN r.blue.w.pos.y←newy;
IF buttL THEN Destroy[s] ELSE s.pos2.y←newy+2; END
ELSE {IF ~noBlueLeft THEN ExtendLeft[]};
END;
IF l.con=NIL AND r.con=NIL THEN BEGIN
IF newy2<newy THEN RETURN;
IF noBlueLeft AND noBlueRight THEN {NewContact[newy]; NewContact[newy2]};
IF noBlueLeft AND ~noBlueRight THEN {ExtendRight[]; NewContact[newy2];
IF ~noRedLeft THEN NewContact[l.where.y]};
IF ~noBlueLeft AND noBlueRight THEN {ExtendLeft[]; NewContact[newy];
IF ~noRedRight THEN NewContact[l.where.y]};
IF ~noBlueLeft AND ~noBlueRight THEN BEGIN
IF newy2<newy+14 THEN RETURN;
NewContact[newy2];
NewRedWireH[s.pos.y,newy];
NewBlueWireH[newy,newy2];
NewContact[newy];
s.pos.y←newy2;
END;
END;
progress←TRUE;
END;
ScavengeList:PROCEDURE=BEGIN
UNTIL list=NIL DO t:SiliconListPtr=list; list←t.t; FreeList[t]; ENDLOOP;
END;
MakeList:PROCEDURE[ss:SiliconPtr]=BEGIN
IF list#NIL THEN {Error; ScavengeList[]};
FOR sl:SiliconListPtr←layout,sl.t UNTIL sl=NIL DO
s:SiliconPtr=sl.h;
IF s.pos2.x+3<ss.pos.x THEN LOOP;
IF s.pos2.y+3<ss.pos.y THEN LOOP;
IF ss.pos2.x+3< s.pos.x THEN LOOP;
IF ss.pos2.y+3< s.pos.y THEN LOOP;
OnList[s];
ENDLOOP;
END;
OnList:PROCEDURE[s:SiliconPtr]=BEGIN
t:SiliconListPtr=AllocateList[];
t↑←[s,list];
list←t;
END;
Copy:PROCEDURE=BEGIN OnList[layout.h]; END;
Bluify:PROCEDURE[s:SiliconPtr]=BEGIN
s.level←blue;
s.pos2.x←s.pos2.x+1;
s.pos2.y←s.pos2.y+1;
END;
Destroy:PROCEDURE[s:SiliconPtr]=BEGIN
s↑←[outOfSight,outOfSight,both];
END;
ScavengeSilicon:PROCEDURE=BEGIN
back,next:SiliconListPtr←NIL;
FOR sl:SiliconListPtr←layout,next UNTIL sl=NIL DO
s:SiliconPtr=sl.h;
next←sl.t;
IF s.pos#outOfSight THEN {back←sl; LOOP};
FreeSilicon[s];
IF back=NIL THEN layout←next ELSE back.t←next;
FreeList[sl];
ENDLOOP;
END;
END.