--Cells2
--this module reorders the column numbers, in the hope that the number of rows being used will decrease. It uses MakeTracks and PrintTracks From Cells to actually compute the new rows.
--this module also happens to be the master control module for the system, calling cells(ParseInput, AssignColumns, MakeTracks), itself, and Cells3(Showtrack).
DIRECTORY
IODefs: FROM "IODefs",
CellsDefs: FROM "CellsDefs";
Cells2:PROGRAM IMPORTS IODefs, CellsDefs=BEGIN OPEN CellsDefs;
Error:SIGNAL=CODE;
Done:SIGNAL=CODE;
Status:TYPE={idle,type1};
status:ARRAY Track OF Status;
where:ARRAY Track OF INTEGER;
when:ARRAY Track OF INTEGER;
reassignments:INTEGER;
Main:PROCEDURE=BEGIN progress:BOOLEAN←TRUE;
ParseInput; ClusterColumns[]; --AssignColumns;
Initialize;
UNTIL ~progress DO AssignRows; progress←ReAssignColumns[]; ENDLOOP;
MakeLayout;
IODefs.WriteChar[Ret];
IODefs.WriteString["Done"];
ReturnStorage[];
END;
Initialize:PROCEDURE={reassignments←oldFixer←oldFixee←0};
AssignRows:PROCEDURE=BEGIN
MakeTracks;
FindTrackBounds;
FOR i:INTEGER IN [0..40] UNTIL ~ExtraTest[] DO ENDLOOP;
FOR i:INTEGER IN [0..4] UNTIL ~ReDoRows[] DO ENDLOOP;
PrintTracks;
END;
MakeLayout:PROCEDURE={Showtrack};
ReAssignColumns:PROCEDURE RETURNS[progress:BOOLEAN]=BEGIN
progress← FindTrouble[];
IF progress THEN MoveTrouble;
END;
FindTrouble:PROCEDURE RETURNS[BOOLEAN]=BEGIN OPEN IODefs;
y,l,j,m,x,f:INTEGER; run,oneRun:BOOLEAN;
FindWorstColumn:PROCEDURE[c,s,z:INTEGER]=BEGIN
k:INTEGER←0;
FOR j IN Track DO SELECT track[c][j] FROM Space,'B=>k←k+1; ENDCASE; ENDLOOP;
IF k<y THEN {y←k; l←0; run←TRUE; m←z; x←c};
IF k=y THEN {l←l+1; oneRun←run; IF run THEN f←z}; --not a select!
IF k>y THEN run←FALSE;
END;
FindAFix:PROCEDURE[c,s,z:INTEGER]=BEGIN
k:INTEGER←-1;
IF z>f THEN RETURN;
FOR j IN Track DO
SELECT track[c][j] FROM 'S,'C,'P=>{k←IF k=-1 THEN j ELSE -2}; ENDCASE; ENDLOOP;
FOR j IN Track DO
SELECT track[c][j] FROM
'1=>IF k>=0 THEN {status[j]←type1; where[j]←k; when[j]←c; LOOP};
'-=>NULL;
ENDCASE=>status[j]←idle;
IF status[j]=type1 AND where[j]#-1 THEN
SELECT track[c][where[j]] FROM 'S,'1,Space=>status[j]←idle; ENDCASE;
ENDLOOP;
END;
FindAnotherFix:PROCEDURE[c,s,z:INTEGER]=BEGIN
k:INTEGER←-1;
IF fixA#-1 THEN RETURN;
FOR j IN Track DO
SELECT track[c][j] FROM
Space,'-,'B=>NULL;
'S=>IF ~TopS[c,j] THEN RETURN ELSE k←j;
ENDCASE=>RETURN;
ENDLOOP;
IF k=-1 THEN RETURN;
FOR p:INTEGER IN (c..signalMax) DO
IF track[p][k]#'- THEN RETURN;
IF Visible[p] THEN {IF c=oldFixer AND p=oldFixee THEN RETURN ELSE EXIT};
ENDLOOP;
where[k]←-1; when[k]←c; fixA←k;
IF print THEN IODefs.WriteString[" Aha! "];
END;
y←trackMax+1;
EnumerateColumns[FindWorstColumn];
IF print THEN BEGIN
WriteChar[Ret];
WriteDecimal[trackMax-y];
WriteString[" wide,starting at "];
WriteDecimal[m];
WriteString[" length = "];
WriteDecimal[l];
WriteString[IF oneRun THEN " in one block" ELSE " scattered"];
END;
status←ALL[idle];
EnumerateColumns[FindAFix];
IF print THEN WriteChar[Ret];
fixA←-1;
FOR j IN Track DO
SELECT status[j] FROM
type1=>{fixA←j; IF print THEN {WriteDecimal[j]; WriteChar[Space]}}; ENDCASE;
ENDLOOP;
IF fixA=-1 THEN EnumerateColumns[FindAnotherFix];
reassignments←reassignments+1;
RETURN[fixA#-1 AND reassignments<10];
END;
Visible:PROCEDURE[p:INTEGER] RETURNS[BOOLEAN]=BEGIN
FOR pp:INTEGER IN [0..trackMax) DO
SELECT track[p][pp] FROM Space,'-,'B=>NULL ENDCASE=>RETURN[TRUE]; ENDLOOP;
RETURN[FALSE];
END;
MoveTrouble:PROCEDURE=BEGIN
fixee:INTEGER;
fixer:INTEGER←when[fixA];
t:INTEGER←column[fixer];
FOR i:INTEGER IN (fixer..signalMax) DO
SELECT track[i][fixA] FROM '-=>NULL; ENDCASE=>{fixee←i-1; EXIT}; ENDLOOP;
UNTIL column[fixee]#0 AND sig[column[fixee]].fixed=none
DO fixee←fixee-1; ENDLOOP;
IF print THEN BEGIN
IODefs.WriteString[Lookup2[t]];
IODefs.WriteString[" swapped for "];
IODefs.WriteString[Lookup2[column[fixee]]];
END;
FOR i:INTEGER IN [fixer..fixee) DO
column[i]←column[i+1];
sig[column[i]].columnNum←i;
ENDLOOP;
column[fixee]←t; sig[t].columnNum←fixee;
oldFixer←fixer; oldFixee←fixee;
END;
fixA:INTEGER;
progress:BOOLEAN←FALSE;
oldFixer,oldFixee:INTEGER;
ReDoRows:PROCEDURE RETURNS[prog:BOOLEAN]=BEGIN
prog←TRUE;
progress←FALSE;
IF print THEN IODefs.WriteChar[Ret];
FOR i:INTEGER IN [0..signalMax) DO
g,d,e,rowG,rowE,colD:INTEGER;
IF sig[i].def=NIL THEN LOOP;
IF sig[i].invisible THEN LOOP;
IF sig[i].def.s.type#pass1 THEN LOOP;
d←sig[i].def.s.d;
colD←sig[d].columnNum;
IF colD=0 OR column[d+1]=0 THEN LOOP;
[g,rowG]←TrueSignal[sig[i].def.s.g];
[e,rowE]←TrueSignal[sig[i].def.s.e];
IF rowG<rowE THEN {t:INTEGER←g; g←e; e←t; t←rowG; rowG←rowE; rowE←t};
IF rowG=-1 OR rowE=-1 THEN {Error; LOOP};
IF rowG=rowE THEN LOOP;
SELECT TRUE FROM
track[colD+1][rowE]=Space AND track[colD-1][rowG]=Space => BEGIN
ShowIt["Type 1 at ",d];
IF FindumDown[rowE,rowG,colD] THEN RETURN;
IF FindumUp[rowG,rowE,colD] THEN RETURN;
END;
track[colD-1][rowE]=Space AND track[colD+1][rowG]=Space => BEGIN
ShowIt["Type 2 at ",d];
IF FindumDown[rowG,rowE,colD] THEN RETURN;
IF FindumUp[rowE,rowG,colD] THEN RETURN;
END;
(rowG=rowE+1)=>NULL;
track[colD+1][rowG]=Space => BEGIN
ShowIt["Type 3 at ",d];
FOR i:INTEGER IN (rowE..rowG) DO
IF track[colD][i]=Space AND FindumDown[rowG,i,colD] THEN RETURN;
ENDLOOP;
END;
track[colD+1][rowE]=Space => BEGIN
ShowIt["Type 4 at ",d];
FOR i:INTEGER DECREASING IN (rowE..rowG) DO
IF track[colD][i]=Space AND FindumDown[rowE,i,colD] THEN RETURN;
ENDLOOP;
END;
track[colD-1][rowE]=Space => BEGIN
ShowIt["Type 5 at ",d];
FOR i:INTEGER DECREASING IN (rowE..rowG) DO
IF track[colD][i]=Space AND FindumUp[rowE,i,colD] THEN RETURN;
ENDLOOP;
END;
track[colD-1][rowG]=Space => BEGIN
ShowIt["Type 6 at ",d];
FOR i:INTEGER IN (rowE..rowG) DO
IF track[colD][i]=Space AND FindumUp[rowG,i,colD] THEN RETURN;
ENDLOOP;
END;
ENDCASE=>ShowIt["Type 7 at ",d];
IF progress THEN Error;
ENDLOOP;
RETURN[FALSE];
END;
trackEnd:Track←0;
columnEnd:INTEGER←0;
FindTrackBounds:PROCEDURE=BEGIN
trackEnd←columnEnd←0;
FOR c:INTEGER IN [0..signalMax) DO FOR t:Track IN Track DO
IF track[c][t]=Space THEN LOOP;
columnEnd←MAX[columnEnd,c+1];
trackEnd←MAX[trackEnd,t+1];
ENDLOOP; ENDLOOP;
END;
ExtraTest:PROCEDURE RETURNS[BOOLEAN]=BEGIN
FOR c:INTEGER IN [0..columnEnd) DO
FOR t:INTEGER IN [0..trackEnd) DO
IF track[c][t]#Space AND (c=0 OR track[c-1][t]=Space) THEN
FOR tt:INTEGER IN [0..trackEnd) DO
IF track[c][tt]=Space AND TTIsBetterThanT[c,t,tt]
THEN {{MoveTtoTT[c,t,tt]; progress←TRUE}};
ENDLOOP;
ENDLOOP;
ENDLOOP;
RETURN[progress];
END;
TTIsBetterThanT:PROCEDURE[c:INTEGER,t,tt:Track] RETURNS[BOOLEAN]=BEGIN
FOR i:INTEGER DECREASING IN [0..c) DO
IF track[i][t] #Space THEN RETURN[FALSE];
IF track[i][tt]#Space THEN RETURN[TRUE];
ENDLOOP;
RETURN[tt<t];
END;
MoveTtoTT:PROCEDURE[c:INTEGER,t,tt:Track]=BEGIN
temp:CHARACTER;
FOR i:INTEGER IN [c..columnEnd) DO
temp←track[i][t]; track[i][t]←track[i][tt]; track[i][tt]←temp;
ENDLOOP;
FOR i:INTEGER IN [0..columnEnd)
DO IF track[i][t]#Space THEN RETURN; ENDLOOP;
FOR i:INTEGER IN [0..columnEnd) DO
temp←track[i][t]; track[i][t]←track[i][trackEnd]; track[i][trackEnd]←temp;
ENDLOOP;
trackEnd←trackEnd-1;
END;
ShowIt:PROCEDURE[s:STRING,d:INTEGER]=BEGIN OPEN IODefs;
IF ~ print THEN RETURN;
WriteChar[Ret];
WriteString[s];
WriteString[Lookup2[d]];
END;
FindumDown:PROCEDURE[e,g,c:INTEGER] RETURNS[BOOLEAN]=BEGIN
FOR q:INTEGER DECREASING IN [0..c-1] DO
SELECT track[q][e] FROM
Space=>Swap[e,g,q+1,c];
'1=>IF track[q][g]=Space THEN Swap[e,g,q,c];
'S=>IF ~TopS[q,e] THEN LOOP ELSE IF track[q][g]=Space THEN Swap[e,g,q,c];
ENDCASE=>IF track[q][g]=Space THEN LOOP;
EXIT;
ENDLOOP;
RETURN[progress];
END;
TopS:PROCEDURE[c,t:INTEGER] RETURNS[BOOLEAN]=BEGIN
FOR j:INTEGER DECREASING IN [0..c] DO
SELECT track[j][t] FROM
'1=>RETURN[FALSE];
'S=>RETURN[TRUE];
Space,'B=>RETURN[TRUE];
ENDCASE;
ENDLOOP;
RETURN[TRUE];
END;
FindumUp:PROCEDURE[e,g,c:INTEGER] RETURNS[BOOLEAN]=BEGIN
end:BOOLEAN←track[c][e]='S;
FOR q:INTEGER IN (c..signalMax) DO
SELECT track[q][e] FROM
Space,'1=>NULL;
'S=>IF ~end THEN {end←TRUE; LOOP};
ENDCASE=>IF track[q][g]=Space THEN LOOP ELSE EXIT;
Swap[e,g,c,q-1];
EXIT;
ENDLOOP;
RETURN[progress];
END;
Swap:PROCEDURE[r1,r2,c1,c2:INTEGER]=BEGIN --r2 is empty
progress←TRUE;
FOR c:INTEGER IN [c1..c2] DO
t:CHARACTER←track[c][r1]; track[c][r1]←track[c][r2]; track[c][r2]←t;
ENDLOOP;
IF track[c2][r1]#Space THEN {track[c2][r1]←Space; track[c2][r2]←'3};
IF track[c1][r1]#Space THEN {track[c1][r1]←Space; track[c1][r2]←'3};
END;
TrueSignal:PROCEDURE[i:INTEGER] RETURNS[j,k:INTEGER]=BEGIN
c:INTEGER;
j←TrueSignal1[i]; k←-1; c←sig[j].columnNum;
FOR l:INTEGER IN [0..trackMax) DO IF track[c][l]='S THEN {k←l; EXIT}; ENDLOOP;
END;
TrueSignal1:PROCEDURE[i:INTEGER] RETURNS[INTEGER]=BEGIN
IF ~sig[i].invisible THEN RETURN[i];
FOR j:INTEGER IN [0..signalMax) DO
IF sig[j].def#NIL AND sig[j].def.s.type=wire THEN
FOR k:TList←sig[j].def, k.next UNTIL k=NIL
DO IF k.s.d=i THEN RETURN[j]; ENDLOOP;
ENDLOOP;
ERROR;
END;
Main[];
END..