unit U_sudoku;
interface uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type T9b = array[1..9] of Byte;
TSA = record AR: T9b;
cp: Integer;
end;
TForm1 = class(TForm) Memo1: TMemo;
SearchBtn: TButton;
procedure SearchBtnClick(Sender: TObject);
public
{ Déclarations publiques }
NbC3x3, // nombre de carrés 3x3 compatibles NbSol: Integer; // nombre de solutions du sudoku Contr: array[1..9] of Integer; // Contraintes
CComp: array[1..10000] of TSA; // Carrés 3x3 compatibles procedure Contraintes;
procedure Generation;
function Test(AX,AY,AZ: T9b; p,q,r: Integer): Boolean;
end;
var Form1: TForm1;
implementation {$R *.DFM}
procedure TForm1.Contraintes;
// transformation des contraintes de l'énoncé en valeur numérique // conservée dans Contr[1..9]
var
j,k,p,q: Integer;
stx: String;
const
v: array[1..9] of String
= ('101001011000','100001101001','011110000100', '100011110101','100110100110','001001011010', '110101100010','010110010100','100101110111');
// contraintes de l'énoncé dans chacun des carrés 3x3:
// 1=> 0=< dans l'ordre de gauche à droite pour les
// lignes 1 à 3, puis de haut en bas pour les colonnes 1 à 3 begin
// conversion chaîne v (écriture binaire) -> nombre for j := 1 to 9 do
begin
stx := v[j]; p := 0; q := 1;
for k := 1 to 12 do begin
if stx[k]='1' then Inc(p,q);
q := q*2;
end;
Contr[j] := p;
end;
end;
procedure TForm1.Generation;
// génération de tous les carrés 3x3 compatibles et classement en // 9 listes (compatible avec la position 'a','b',.. dans le sudoku) // un carré = | a b c |
// | d e f | // | g h i | var
a,b,c,d,e,f,g,h,i,j,s: Integer;
tx: array[1..9] of Integer;
AX: T9b;
stx: String;
begin
NbC3x3 := 0;
for a := 1 to 9 do
for b := 1 to 9 do if (b<>a) then
for c := 1 to 9 do if (c<>a) and (c<>b) then
for d := 1 to 9 do if (d<>a) and (d<>b) and (d<>c) then
for e := 1 to 9 do if (e<>a) and (e<>b) and (e<>c) and (e<>d) then
for f := 1 to 9 do if (f<>a) and (f<>b) and (f<>c) and (f<>d) and (f<>e) then
for g := 1 to 9 do if (g<>a) and (g<>b) and (g<>c) and (g<>d) and (g<>e) and (g<>f) then for h := 1 to 9 do if (h<>a) and (h<>b) and (h<>c) and (h<>d) and (h<>e) and (h<>f) and (h<>g) then
for i := 1 to 9 do if (i<>a) and (i<>b) and (i<>c) and (i<>d) and (i<>e) and (i<>f) and (i<>g) and (i<>h) then
begin s := 0;
if a>b then Inc(s);
if b>c then Inc(s,2);
if d>e then Inc(s,4);
if e>f then Inc(s,8);
if g>h then Inc(s,16);
if h>i then Inc(s,32);
if a>d then Inc(s,64);
if d>g then Inc(s,128);
if b>e then Inc(s,256);
if e>h then Inc(s,512);
if c>f then Inc(s,1024);
if f>i then Inc(s,2048);
for j := 1 to 9 do if s = Contr[j] then begin
Inc(NbC3x3);
AX[1] := a; AX[2] := b; AX[3] := c; AX[4] := d; AX[5] := e;
AX[6] := f; AX[7] := g; AX[8] := h; AX[9] := i;
// on garde dans CComp[1..x] la composition du carré et sa position possible with CComp[NbC3x3] do
begin
AR := AX; cp := j;
end;
end;
end;
// pour connaitre le nombre total NbC3x3 et la répartition tx[1..9]
// des carrés 3x3 compatibles
Memo1.Lines.Add(Format('carrés 3x3 compatibles NbC3x3=%d',[NbC3x3]));
FillChar(tx, SizeOf(tx), 0);
for j := 1 to NbC3x3 do Inc(tx[CComp[j].cp]);
stx := '';
for j := 1 to 9 do stx := stx + Format('%d:%d ',[j,tx[j]]);
Memo1.Lines.Add(stx);
end;
function TForm1.Test(AX,AY,AZ: T9b; p,q,r: Integer): Boolean;
// Test de compatibilité de ligne ou de colonne de 9 chiffres // AX1, AX4, AX7 sont les carrés 3x3 d'où sont extraits les // chiffres en position p, q, r
// un carré = | 1 2 3 | // | 4 5 6 | // | 7 8 9 | var
j: Integer;
bx: array[1..9] of Boolean;
begin
FillChar(bx, SizeOf(bx), 0); // False partout bx[AX[p]] := True;
bx[AX[q]] := True;
bx[AX[r]] := True;
bx[AY[p]] := True;
bx[AY[q]] := True;
bx[AY[r]] := True;
bx[AZ[p]] := True;
bx[AZ[q]] := True;
bx[AZ[r]] := True;
Result := True;
for j := 1 to 9 do if not bx[j] then Result := False;
end;
procedure TForm1.SearchBtnClick(Sender: TObject);
var
j1,j2,j3,j4,j5,j6,j7,j8,j9: Integer;
AX1,AX2,AX3,AX4,AX5,AX6,AX7,AX8,AX9: T9b;
begin
Contraintes;
Generation;
// Et voici la recherche proprement dite
// L'ordre des tests est orienté par les résultats de Génération // de façon à commencer par les carrés compatibles les mooins nombreux
// et introduire en dernier ceux du centre (AX5) NbSol := 0;
for j1 := 1 to NbC3x3 do if CComp[j1].cp=1 then for j4 := 1 to NbC3x3 do if CComp[j4].cp=4 then for j7 := 1 to NbC3x3 do if CComp[j7].cp=7 then begin
AX1 := CComp[j1].AR;
AX4 := CComp[j4].AR;
AX7 := CComp[j7].AR;
if Test(AX1,AX4,AX7,1,4,7) and Test(AX1,AX4,AX7,2,5,8) and Test(AX1,AX4,AX7,3,6,9) then begin
for j2 := 1 to NbC3x3 do if CComp[j2].cp=2 then for j3 := 1 to NbC3x3 do if CComp[j3].cp=3 then begin
AX2 := CComp[j2].AR;
AX3 := CComp[j3].AR;
if Test(AX1,AX2,AX3,1,2,3) and Test(AX1,AX2,AX3,4,5,6) and Test(AX1,AX2,AX3,7,8,9) then begin
for j5 := 1 to NbC3x3 do if CComp[j5].cp=5 then for j6 := 1 to NbC3x3 do if CComp[j6].cp=6 then begin
AX5 := CComp[j5].AR;
AX6 := CComp[j6].AR;
if Test(AX4,AX5,AX6,1,2,3) and Test(AX4,AX5,AX6,4,5,6) and Test(AX4,AX5,AX6,7,8,9) then begin
for j8 := 1 to NbC3x3 do if CComp[j8].cp=8 then for j9 := 1 to NbC3x3 do if CComp[j9].cp=9 then begin
AX8 := CComp[j8].AR;
AX9 := CComp[j9].AR;
if Test(AX7,AX8,AX9,1,2,3) and Test(AX7,AX8,AX9,4,5,6) and Test(AX7,AX8,AX9,7,8,9) and Test(AX3,AX6,AX9,1,4,7) and Test(AX3,AX6,AX9,2,5,8) and Test(AX3,AX6,AX9,3,6,9) and Test(AX2,AX5,AX8,1,4,7) and Test(AX2,AX5,AX8,2,5,8) and Test(AX2,AX5,AX8,3,6,9) then begin
Inc(NbSol);
Memo1.Lines.Add(Format('Essai %d',[NbSol]));
Memo1.Lines.Add(Format('%d %d %d %d %d %d %d %d %d ', [AX1[1],AX1[2],AX1[3],AX2[1],AX2[2],AX2[3],AX3[1],AX3[2],AX3[3]]));
Memo1.Lines.Add(Format('%d %d %d %d %d %d %d %d %d ', [AX1[4],AX1[5],AX1[6],AX2[4],AX2[5],AX2[6],AX3[4],AX3[5],AX3[6]]));
Memo1.Lines.Add(Format('%d %d %d %d %d %d %d %d %d ', [AX1[7],AX1[8],AX1[9],AX2[7],AX2[8],AX2[9],AX3[7],AX3[8],AX3[9]]));
Memo1.Lines.Add(Format('%d %d %d %d %d %d %d %d %d ', [AX4[1],AX4[2],AX4[3],AX5[1],AX5[2],AX5[3],AX6[1],AX6[2],AX6[3]]));
Memo1.Lines.Add(Format('%d %d %d %d %d %d %d %d %d ', [AX4[4],AX4[5],AX4[6],AX5[4],AX5[5],AX5[6],AX6[4],AX6[5],AX6[6]]));
Memo1.Lines.Add(Format('%d %d %d %d %d %d %d %d %d ', [AX4[7],AX4[8],AX4[9],AX5[7],AX5[8],AX5[9],AX6[7],AX6[8],AX6[9]]));
Memo1.Lines.Add(Format('%d %d %d %d %d %d %d %d %d ', [AX7[1],AX7[2],AX7[3],AX8[1],AX8[2],AX8[3],AX9[1],AX9[2],AX9[3]]));
Memo1.Lines.Add(Format('%d %d %d %d %d %d %d %d %d ', [AX7[4],AX7[5],AX7[6],AX8[4],AX8[5],AX8[6],AX9[4],AX9[5],AX9[6]]));
Memo1.Lines.Add(Format('%d %d %d %d %d %d %d %d %d ', [AX7[7],AX7[8],AX7[9],AX8[7],AX8[8],AX8[9],AX9[7],AX9[8],AX9[9]]));
end;
end;
end;
end;
end;
end;
end;
end;
Memo1.Lines.Add('');
Memo1.Lines.Add('Fini');
end;
end.