258 lines
5.9 KiB
Plaintext
258 lines
5.9 KiB
Plaintext
Program soduko;
|
|
{$IFDEF FPC}
|
|
{$CODEALIGN proc=16,loop=8}
|
|
{$ENDIF}
|
|
uses
|
|
sysutils,crt;
|
|
const
|
|
carreeSize = 3;
|
|
maxCoor = carreeSize*carreeSize;
|
|
maxValue = maxCoor;
|
|
maxMask = 1 shl (maxCoor+1)-1;
|
|
type
|
|
tLimit = 0..maxCoor-1;
|
|
tValue = 0..maxCoor;
|
|
tSteps = 0..maxCoor*maxCoor;
|
|
tValField = array[tLimit,tLimit] of NativeInt;//tValue;
|
|
tBitrepr = 0..maxMask;
|
|
tcol = array[tLimit] of NativeInt;// tBitrepr;
|
|
trow = array[tLimit] of NativeInt;// tBitrepr;
|
|
tcar = array[tLimit] of NativeInt;// tBitrepr;
|
|
tpValue = ^NativeInt;//^tValue;
|
|
tpLimit = ^tLimit;
|
|
tpBitrepr= ^NativeInt;//^tBitrepr;
|
|
tchgVal = record
|
|
cvCol,
|
|
cvRow,
|
|
cvCar : tpBitrepr;
|
|
cvVal : tpValue;
|
|
end;
|
|
tpChgVal = ^tchgVal;
|
|
tchgList = array[tSteps] of tchgVal;
|
|
|
|
tField = record
|
|
fdChgList: tchgList;
|
|
fdCol : tcol;
|
|
fdRow : trow;
|
|
fdcar : tcar;
|
|
fdVal : tValField;
|
|
fdChgIdx : tSteps;
|
|
|
|
end;
|
|
const
|
|
Expl0:tValField = ((9,0,7,0,0,0,3,0,0),
|
|
(0,0,0,1,0,0,2,0,0),
|
|
(6,0,0,0,0,8,0,0,0),
|
|
(0,0,5,0,3,0,0,0,0),
|
|
(0,0,0,0,0,0,0,8,4),
|
|
(0,0,0,0,0,0,0,6,0),
|
|
(0,0,0,2,7,0,0,0,0),
|
|
(8,4,0,0,0,0,0,0,0),
|
|
(0,6,0,0,0,0,0,0,0));
|
|
Expl1:tValField=((0,0,0,1,0,0,0,3,8),
|
|
(2,0,0,0,0,5,0,0,0),
|
|
(0,0,0,0,0,0,0,0,0),
|
|
(0,5,0,0,0,0,4,0,0),
|
|
(4,0,0,0,3,0,0,0,0),
|
|
(0,0,0,7,0,0,0,0,6),
|
|
(0,0,1,0,0,0,0,5,0),
|
|
(0,0,0,0,6,0,2,0,0),
|
|
(0,6,0,0,0,4,0,0,0));
|
|
|
|
var
|
|
F,
|
|
solF : TField;
|
|
solCnt,
|
|
callCnt: NativeUint;
|
|
solFound : Boolean;
|
|
|
|
procedure OutField(const F:tField);
|
|
var
|
|
rw,cl : tLimit;
|
|
rowS: AnsiString;
|
|
Begin
|
|
GotoXy(1,1);
|
|
For rw := low(tLimit) to High(tLimit) do
|
|
Begin
|
|
rowS := ' ';
|
|
For cl := low(tLimit) to High(tLimit) do
|
|
RowS :=RowS+IntToStr(F.fdVal[rw,cl]);
|
|
writeln(RowS);
|
|
end;
|
|
end;
|
|
|
|
function CarIdx(rw,cl: NativeInt):NativeInt;
|
|
begin
|
|
CarIdx:= (rw DIV carreeSize)*carreeSize +cl DIV carreeSize;
|
|
end;
|
|
function InsertTest(const F:tField;rw,cl:tLimit;value:tValue):boolean;
|
|
var
|
|
msk: tBitrepr;
|
|
Begin
|
|
result := (Value = 0);
|
|
IF result then
|
|
EXIT;
|
|
msk := 1 shl (value-1);
|
|
with F do
|
|
Begin
|
|
result := fdRow[rw] AND msk = 0;
|
|
result := result AND (fdCol[cl] AND msk = 0);
|
|
rw :=CarIdx(rw,cl);
|
|
result := result AND (fdCar[rw] AND msk = 0);
|
|
end;
|
|
end;
|
|
|
|
function InitField(var F:tField;const InFd:tValField;DoReverse:boolean):boolean;
|
|
var
|
|
TmpchgVal:tchgVal;
|
|
rw,cl,
|
|
value,
|
|
msk : NativeInt;
|
|
leftSteps:tSteps;
|
|
Begin
|
|
Fillchar(F,SizeOf(F),#0);
|
|
leftSteps := High(tSteps)-1;
|
|
//unknown fields inserted from end
|
|
For rw := low(tLimit) to High(tLimit) do
|
|
For cl := low(tLimit) to High(tLimit) do
|
|
Begin
|
|
value := InFd[rw,cl];
|
|
IF InsertTest(F,rw,cl,value) then
|
|
Begin
|
|
with F do
|
|
Begin
|
|
if value > 0 then
|
|
Begin
|
|
msk := 1 shl (value-1);
|
|
//given state
|
|
//use pointer to the relevant places and mark as occupied
|
|
with fdChgList[fdChgIdx] do
|
|
begin
|
|
cvCol := @fdCol[cl];
|
|
cvCol^ +=Msk;
|
|
cvRow := @fdRow[rw];
|
|
cvRow^ +=Msk;
|
|
cvCar := @fdCar[CarIdx(rw,cl)];
|
|
cvCar^ +=Msk;
|
|
cvVal := @fdVal[rw,cl];
|
|
cvVal^ := value;
|
|
end;
|
|
inc(fdChgIdx);
|
|
end
|
|
else
|
|
Begin
|
|
//use pointer to the relevant places
|
|
with fdChgList[leftSteps] do
|
|
begin
|
|
cvCol := @fdCol[cl];
|
|
cvRow := @fdRow[rw];
|
|
cvCar := @fdCar[CarIdx(rw,cl)];
|
|
cvVal := @fdVal[rw,cl];
|
|
end;
|
|
dec(leftSteps);
|
|
end;
|
|
end
|
|
end
|
|
else
|
|
Begin
|
|
writeln(rw:10,cl:10,value:10);
|
|
Writeln(' not solvable SuDoKu ');
|
|
delay(2000);
|
|
result := false;
|
|
EXIT;
|
|
end;
|
|
end;
|
|
//reverse direction of left over
|
|
IF DoReverse then
|
|
Begin
|
|
leftSteps := High(tSteps)-1;
|
|
rw := F.fdChgIdx;
|
|
repeat
|
|
TmpchgVal:= F.fdChgList[leftSteps];
|
|
F.fdChgList[leftSteps]:= F.fdChgList[rw];
|
|
F.fdChgList[rw] :=TmpchgVal;
|
|
dec(leftSteps);
|
|
inc(rw);
|
|
until rw>=leftSteps;
|
|
end;
|
|
//OutField(F);
|
|
solFound := false;
|
|
result := true;
|
|
end;
|
|
procedure SolIsFound;
|
|
begin
|
|
solF := F;
|
|
inc(solCnt);
|
|
solFound := True;
|
|
end;
|
|
|
|
procedure TryCell(var ChgVal:tpchgVal);
|
|
var
|
|
value :NativeInt;
|
|
poss,msk: NativeInt;
|
|
Begin
|
|
IF solFound then EXIT;
|
|
with ChgVal^ do
|
|
poss:= (cvRow^ OR cvCol^ OR cvCar^) XOR maxMask;
|
|
IF Poss = 0 then
|
|
EXIT;
|
|
|
|
value := 1;
|
|
msk := 1;
|
|
|
|
repeat
|
|
IF Poss AND MSK <>0 then
|
|
Begin
|
|
inc(callCnt);
|
|
//insert test value
|
|
with ChgVal^ do
|
|
Begin
|
|
cvCol^ := cvCol^ OR msk;
|
|
cvRow^ := cvRow^ OR msk;
|
|
cvCar^ := cvCar^ OR msk;
|
|
cvVAl^ := value;
|
|
end;
|
|
//try next in list, if beyond last
|
|
inc(ChgVal);
|
|
|
|
IF ChgVal^.cvCol <> NIL then
|
|
TryCell(ChgVal)
|
|
else
|
|
SolIsFound;
|
|
//remove test value
|
|
dec(ChgVal);
|
|
with ChgVal^ do
|
|
Begin
|
|
cvCol^ := cvCol^ XOR msk;
|
|
cvRow^ := cvRow^ XOR msk;
|
|
cvCar^ := cvCar^ XOR msk;
|
|
cvVAl^ := 0;
|
|
end;
|
|
end;
|
|
inc(msk,msk);
|
|
inc(value);
|
|
until value> maxValue;
|
|
end;
|
|
|
|
var
|
|
ChangeBegin : tpChgVal;
|
|
k : NativeInt;
|
|
T1,T0: TDateTime;
|
|
begin
|
|
randomize;
|
|
ClrScr;
|
|
solCnt := 0;
|
|
callCnt:= 0;
|
|
T0 := time;
|
|
k := 0;
|
|
repeat
|
|
InitField(F,Expl1,FALSE);
|
|
ChangeBegin := @F.fdChgList[F.fdChgIdx];
|
|
TryCell(ChangeBegin);
|
|
inc(k);
|
|
until k >= 5;
|
|
T1 := time;
|
|
Outfield(solF);
|
|
writeln(86400*1000*(T1-T0)/k:10:3,' ms Test calls :',callCnt/k:8:0);
|
|
end.
|