Sudoku: make it possible to preserve the RawData from the ScratchPad and use it in the solving process.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7263 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
32ff846113
commit
8d57550d02
@ -3,6 +3,7 @@ object ScratchForm: TScratchForm
|
|||||||
Height = 545
|
Height = 545
|
||||||
Top = 113
|
Top = 113
|
||||||
Width = 799
|
Width = 799
|
||||||
|
BorderIcons = [biSystemMenu]
|
||||||
Caption = 'ScratchPad'
|
Caption = 'ScratchPad'
|
||||||
ClientHeight = 545
|
ClientHeight = 545
|
||||||
ClientWidth = 799
|
ClientWidth = 799
|
||||||
@ -29,14 +30,30 @@ object ScratchForm: TScratchForm
|
|||||||
AnchorSideLeft.Control = ScratchGrid
|
AnchorSideLeft.Control = ScratchGrid
|
||||||
AnchorSideTop.Control = ScratchGrid
|
AnchorSideTop.Control = ScratchGrid
|
||||||
AnchorSideTop.Side = asrBottom
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = btnCopyRaw
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
Left = 16
|
Left = 16
|
||||||
Height = 25
|
Height = 25
|
||||||
Top = 306
|
Top = 306
|
||||||
Width = 253
|
Width = 279
|
||||||
AutoSize = True
|
AutoSize = True
|
||||||
BorderSpacing.Top = 10
|
BorderSpacing.Top = 10
|
||||||
Caption = 'Copy values back and close the ScratchPad'
|
Caption = 'Copy only values back and close the ScratchPad'
|
||||||
OnClick = btnCopyClick
|
OnClick = btnCopyClick
|
||||||
TabOrder = 1
|
TabOrder = 1
|
||||||
end
|
end
|
||||||
|
object btnCopyRaw: TButton
|
||||||
|
AnchorSideLeft.Control = btnCopy
|
||||||
|
AnchorSideTop.Control = btnCopy
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
Left = 16
|
||||||
|
Height = 25
|
||||||
|
Top = 341
|
||||||
|
Width = 354
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Top = 10
|
||||||
|
Caption = 'Copy values and possible digits back and close the ScratchPad'
|
||||||
|
OnClick = btnCopyRawClick
|
||||||
|
TabOrder = 2
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -14,11 +14,14 @@ type
|
|||||||
{ TScratchForm }
|
{ TScratchForm }
|
||||||
|
|
||||||
TCopyValuesEvent = procedure(Sender: TObject; Values: TValues) of Object;
|
TCopyValuesEvent = procedure(Sender: TObject; Values: TValues) of Object;
|
||||||
|
TCopyRawDataEvent = procedure(Sender: TObject; RawData: TRawGrid) of Object;
|
||||||
|
|
||||||
TScratchForm = class(TForm)
|
TScratchForm = class(TForm)
|
||||||
btnCopy: TButton;
|
btnCopy: TButton;
|
||||||
|
btnCopyRaw: TButton;
|
||||||
ScratchGrid: TStringGrid;
|
ScratchGrid: TStringGrid;
|
||||||
procedure btnCopyClick(Sender: TObject);
|
procedure btnCopyClick(Sender: TObject);
|
||||||
|
procedure btnCopyRawClick(Sender: TObject);
|
||||||
procedure FormActivate(Sender: TObject);
|
procedure FormActivate(Sender: TObject);
|
||||||
procedure FormCreate(Sender: TObject);
|
procedure FormCreate(Sender: TObject);
|
||||||
procedure ScratchGridClick(Sender: TObject);
|
procedure ScratchGridClick(Sender: TObject);
|
||||||
@ -27,6 +30,8 @@ type
|
|||||||
private
|
private
|
||||||
FRawData: TRawGrid;
|
FRawData: TRawGrid;
|
||||||
FOnCopyValues: TCopyValuesEvent;
|
FOnCopyValues: TCopyValuesEvent;
|
||||||
|
FOnCopyRawData: TCopyRawDataEvent;
|
||||||
|
procedure GridToRawData(out RawData: TRawGrid);
|
||||||
procedure SetRawData(Data: TRawGrid);
|
procedure SetRawData(Data: TRawGrid);
|
||||||
procedure GridToValues(out Values: TValues);
|
procedure GridToValues(out Values: TValues);
|
||||||
procedure KeepInView;
|
procedure KeepInView;
|
||||||
@ -34,6 +39,7 @@ type
|
|||||||
public
|
public
|
||||||
property RawData: TRawGrid write SetRawData;
|
property RawData: TRawGrid write SetRawData;
|
||||||
property OnCopyValues: TCopyValuesEvent read FOnCopyValues write FOnCopyValues;
|
property OnCopyValues: TCopyValuesEvent read FOnCopyValues write FOnCopyValues;
|
||||||
|
property OnCopyRawData: TCopyRawDataEvent read FOnCopyRawData write FOnCopyRawData;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
@ -101,7 +107,9 @@ begin
|
|||||||
Self.ReAlign;
|
Self.ReAlign;
|
||||||
//ClientHeight := btnCopy.Top + btnCopy.Height + 10;
|
//ClientHeight := btnCopy.Top + btnCopy.Height + 10;
|
||||||
//Above doesn't work: at this time btnCopy.Top still holds designtime value, even when it's top is anchored to the grid
|
//Above doesn't work: at this time btnCopy.Top still holds designtime value, even when it's top is anchored to the grid
|
||||||
ClientHeight := ScratchGrid.Top + ScratchGrid.Height + 10 + btnCopy.Height + 10;
|
ClientHeight := ScratchGrid.Top + ScratchGrid.Height + 10 + btnCopy.Height + 10 + btnCopyRaw.Height + 10;
|
||||||
|
btnCopy.AutoSize := False;
|
||||||
|
btnCopy.Width := btnCopyRaw.Width;
|
||||||
//writeln(format('ClientHeight: %d',[ClientHeight]));
|
//writeln(format('ClientHeight: %d',[ClientHeight]));
|
||||||
KeepInView;
|
KeepInView;
|
||||||
end;
|
end;
|
||||||
@ -110,10 +118,26 @@ procedure TScratchForm.btnCopyClick(Sender: TObject);
|
|||||||
var
|
var
|
||||||
Values: TValues;
|
Values: TValues;
|
||||||
begin
|
begin
|
||||||
if not Assigned(FOnCopyValues) then Exit;
|
if Assigned(FOnCopyValues) then
|
||||||
GridToValues(Values);
|
begin
|
||||||
FOnCopyValues(Self, Values);
|
GridToValues(Values);
|
||||||
Close;
|
FOnCopyValues(Self, Values);
|
||||||
|
ModalResult := mrOk;
|
||||||
|
//Close;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TScratchForm.btnCopyRawClick(Sender: TObject);
|
||||||
|
var
|
||||||
|
ARawData: TRawGrid;
|
||||||
|
begin
|
||||||
|
if Assigned(FOnCopyRawData) then
|
||||||
|
begin
|
||||||
|
GridToRawData(ARawData);
|
||||||
|
FOnCopyRawData(Self, ARawData);
|
||||||
|
ModalResult := mrOk;
|
||||||
|
//Close;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TScratchForm.FormCreate(Sender: TObject);
|
procedure TScratchForm.FormCreate(Sender: TObject);
|
||||||
@ -188,6 +212,35 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TScratchForm.GridToRawData(out RawData: TRawGrid);
|
||||||
|
var
|
||||||
|
Col, Row: Integer;
|
||||||
|
ADigit: TDigits;
|
||||||
|
DigitSet: TDigitSet;
|
||||||
|
S: String;
|
||||||
|
begin
|
||||||
|
for Col := 0 to 8 do
|
||||||
|
begin
|
||||||
|
for Row := 0 to 8 do
|
||||||
|
begin
|
||||||
|
S := ScratchGrid.Cells[Col, Row];
|
||||||
|
if TryCellTextToDigit(S, ADigit) then
|
||||||
|
begin
|
||||||
|
RawData[Col+1,Row+1].Value := ADigit;
|
||||||
|
RawData[Col+1,Row+1].DigitsPossible := [];
|
||||||
|
RawData[Col+1,Row+1].Locked := True;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
DigitSet := StrToDigitSet(S);
|
||||||
|
RawData[Col+1,Row+1].Value := 0;
|
||||||
|
RawData[Col+1,Row+1].DigitsPossible := DigitSet;
|
||||||
|
RawData[Col+1,Row+1].Locked := False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TScratchForm.GridToValues(out Values: TValues);
|
procedure TScratchForm.GridToValues(out Values: TValues);
|
||||||
var
|
var
|
||||||
Col, Row: Integer;
|
Col, Row: Integer;
|
||||||
|
@ -62,19 +62,29 @@ type
|
|||||||
{ private declarations }
|
{ private declarations }
|
||||||
const
|
const
|
||||||
MaxSteps = 50;
|
MaxSteps = 50;
|
||||||
|
private
|
||||||
//theValues: TValues;
|
//theValues: TValues;
|
||||||
|
FSolveUsesRawData: Boolean;
|
||||||
|
FRawData: TRawGrid;
|
||||||
procedure OnCopyBackValues(Sender: TObject; Values: TValues);
|
procedure OnCopyBackValues(Sender: TObject; Values: TValues);
|
||||||
|
procedure OnCopyBackRawData(Sender: TObject; RawData: TRawGrid);
|
||||||
|
procedure SetSolveUsesRawData(AValue: Boolean);
|
||||||
function SolveSudoku(out Values: TValues; out RawData: TRawGrid; out Steps: Integer): Boolean;
|
function SolveSudoku(out Values: TValues; out RawData: TRawGrid; out Steps: Integer): Boolean;
|
||||||
|
function SolveSudoku(var RawData: TRawGrid; out Values: TValues; out Steps: Integer): Boolean;
|
||||||
procedure GridToValues(out Values: TValues);
|
procedure GridToValues(out Values: TValues);
|
||||||
procedure ValuesToGrid(const Values: TValues);
|
procedure ValuesToGrid(const Values: TValues);
|
||||||
|
procedure RawDataToGrid(const RawData: TRawGrid);
|
||||||
procedure ShowScratchPad(RawData: TRawGrid);
|
procedure ShowScratchPad(RawData: TRawGrid);
|
||||||
procedure LoadSudokuFromFile(const Fn: String);
|
procedure LoadSudokuFromFile(const Fn: String);
|
||||||
procedure SaveSudokuToFile(const Fn: String);
|
procedure SaveSudokuToFile(const Fn: String);
|
||||||
function IsValidSudokuFile(Lines: TStrings): Boolean;
|
function IsValidSudokuFile(Lines: TStrings): Boolean;
|
||||||
procedure LinesToGrid(Lines: TStrings);
|
procedure LinesToGrid(Lines: TStrings);
|
||||||
procedure GridToLines(Lines: TStrings);
|
procedure GridToLines(Lines: TStrings);
|
||||||
|
procedure EnableEdit;
|
||||||
|
procedure DisableEdit;
|
||||||
public
|
public
|
||||||
{ public declarations }
|
{ public declarations }
|
||||||
|
property SolveUsesRawData: Boolean read FSolveUsesRawData write SetSolveUsesRawData default False;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ESudokuFile = Class(Exception);
|
ESudokuFile = Class(Exception);
|
||||||
@ -96,7 +106,7 @@ const
|
|||||||
|
|
||||||
procedure TForm1.btnEditClick(Sender: TObject);
|
procedure TForm1.btnEditClick(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
SGrid.Options := SGrid.Options + [goEditing];
|
EnableEdit;
|
||||||
SGrid.SetFocus;
|
SGrid.SetFocus;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -105,6 +115,7 @@ begin
|
|||||||
if OpenDialog.Execute then
|
if OpenDialog.Execute then
|
||||||
try
|
try
|
||||||
LoadSudokuFromFile(OpenDialog.Filename);
|
LoadSudokuFromFile(OpenDialog.Filename);
|
||||||
|
SolveUsesRawData := False;
|
||||||
except
|
except
|
||||||
on E: Exception do ShowMessage(E.Message);
|
on E: Exception do ShowMessage(E.Message);
|
||||||
end;
|
end;
|
||||||
@ -128,13 +139,15 @@ end;
|
|||||||
procedure TForm1.btnSolveClick(Sender: TObject);
|
procedure TForm1.btnSolveClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
Res: Boolean;
|
Res: Boolean;
|
||||||
RawData: TRawGrid;
|
|
||||||
Values: TValues;
|
Values: TValues;
|
||||||
Steps: Integer;
|
Steps: Integer;
|
||||||
begin
|
begin
|
||||||
SGrid.Options := SGrid.Options - [goEditing];
|
DisableEdit;
|
||||||
try
|
try
|
||||||
Res := SolveSudoku(Values, RawData, Steps);
|
if not FSolveUsesRawData then
|
||||||
|
Res := SolveSudoku(Values, FRawData, Steps)
|
||||||
|
else
|
||||||
|
Res := SolveSudoku(FRawData, Values, Steps);
|
||||||
ValuesToGrid(Values);
|
ValuesToGrid(Values);
|
||||||
if Res then
|
if Res then
|
||||||
ShowMessage(Format('Sudoku solved in %d steps.', [Steps]))
|
ShowMessage(Format('Sudoku solved in %d steps.', [Steps]))
|
||||||
@ -144,7 +157,7 @@ begin
|
|||||||
ShowMessage(Format('Unable to solve sudoku (no progress after step %d).',[Steps-1]))
|
ShowMessage(Format('Unable to solve sudoku (no progress after step %d).',[Steps-1]))
|
||||||
else
|
else
|
||||||
ShowMessage(Format('Unable to completely solve sudoku (tried %d steps).',[Steps]));
|
ShowMessage(Format('Unable to completely solve sudoku (tried %d steps).',[Steps]));
|
||||||
ShowScratchPad(RawData);
|
ShowScratchPad(FRawData);
|
||||||
end;
|
end;
|
||||||
except
|
except
|
||||||
on E: ESudoku do ShowMessage(E.Message);
|
on E: ESudoku do ShowMessage(E.Message);
|
||||||
@ -174,6 +187,7 @@ end;
|
|||||||
|
|
||||||
procedure TForm1.FormCreate(Sender: TObject);
|
procedure TForm1.FormCreate(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
|
SolveUsesRawData := False;
|
||||||
OpenDialog.Filter := SudokuFileFilter;
|
OpenDialog.Filter := SudokuFileFilter;
|
||||||
SaveDialog.Filter := SudokuFileFilter;
|
SaveDialog.Filter := SudokuFileFilter;
|
||||||
end;
|
end;
|
||||||
@ -231,6 +245,18 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TForm1.SolveSudoku(var RawData: TRawGrid; out Values: TValues; out Steps: Integer): Boolean;
|
||||||
|
var
|
||||||
|
aSudoku: TSudoku;
|
||||||
|
begin
|
||||||
|
aSudoku := TSudoku.Create;
|
||||||
|
try
|
||||||
|
Result := aSudoku.GiveSolution(RawData, Values, Steps);
|
||||||
|
finally
|
||||||
|
aSudoku.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TForm1.GridToValues(out Values: TValues);
|
procedure TForm1.GridToValues(out Values: TValues);
|
||||||
var
|
var
|
||||||
Col, Row: Integer;
|
Col, Row: Integer;
|
||||||
@ -255,6 +281,26 @@ end;
|
|||||||
procedure TForm1.OnCopyBackValues(Sender: TObject; Values: TValues);
|
procedure TForm1.OnCopyBackValues(Sender: TObject; Values: TValues);
|
||||||
begin
|
begin
|
||||||
ValuesToGrid(Values);
|
ValuesToGrid(Values);
|
||||||
|
SolveUsesRawData := False;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TForm1.OnCopyBackRawData(Sender: TObject; RawData: TRawGrid);
|
||||||
|
begin
|
||||||
|
FRawData := RawData;
|
||||||
|
RawDataToGrid(RawData);
|
||||||
|
SolveUsesRawData := True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TForm1.SetSolveUsesRawData(AValue: Boolean);
|
||||||
|
begin
|
||||||
|
if FSolveUsesRawData = AValue then Exit;
|
||||||
|
FSolveUsesRawData := AValue;
|
||||||
|
if FSolveUsesRawData then
|
||||||
|
DisableEdit
|
||||||
|
else
|
||||||
|
EnableEdit;
|
||||||
|
btnEdit.Enabled := not FSolveUsesRawData;
|
||||||
|
btnClear.Enabled := not FSolveUsesRawData;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -275,13 +321,32 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TForm1.RawDataToGrid(const RawData: TRawGrid);
|
||||||
|
var
|
||||||
|
Col, Row: Integer;
|
||||||
|
Ch: Char;
|
||||||
|
begin
|
||||||
|
for Col := 0 to 8 do
|
||||||
|
begin
|
||||||
|
for Row := 0 to 8 do
|
||||||
|
begin
|
||||||
|
Ch := IntToStr(RawData[Col + 1, Row + 1].Value)[1];
|
||||||
|
if Ch = '0' then
|
||||||
|
Ch := VisualEmptyChar;
|
||||||
|
SGrid.Cells[Col, Row] := Ch;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TForm1.ShowScratchPad(RawData: TRawGrid);
|
procedure TForm1.ShowScratchPad(RawData: TRawGrid);
|
||||||
begin
|
begin
|
||||||
ScratchForm.OnCopyValues := @OnCopyBackValues;
|
ScratchForm.OnCopyValues := @OnCopyBackValues;
|
||||||
|
ScratchForm.OnCopyRawData := @OnCopyBackRawData;
|
||||||
ScratchForm.RawData := RawData;
|
ScratchForm.RawData := RawData;
|
||||||
ScratchForm.ScratchGrid.Options := SGrid.Options - [goEditing];
|
ScratchForm.ScratchGrid.Options := SGrid.Options - [goEditing];
|
||||||
ScratchForm.Left := Left + Width + 10;
|
ScratchForm.Left := Left + Width + 10;
|
||||||
ScratchForm.Show;
|
if (ScratchForm.ShowModal <> mrOK) then
|
||||||
|
SolveUsesRawData := False;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TForm1.LoadSudokuFromFile(const Fn: String);
|
procedure TForm1.LoadSudokuFromFile(const Fn: String);
|
||||||
@ -396,5 +461,15 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TForm1.EnableEdit;
|
||||||
|
begin
|
||||||
|
SGrid.Options := SGrid.Options + [goEditing];
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TForm1.DisableEdit;
|
||||||
|
begin
|
||||||
|
SGrid.Options := SGrid.Options - [goEditing];
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ type
|
|||||||
public
|
public
|
||||||
constructor Create;
|
constructor Create;
|
||||||
function GiveSolution(var Values: TValues; out RawData: TRawGrid; out Steps: Integer): Boolean;
|
function GiveSolution(var Values: TValues; out RawData: TRawGrid; out Steps: Integer): Boolean;
|
||||||
|
function GiveSolution(var RawData: TRawGrid; out Values: TValues; out Steps: Integer): Boolean;
|
||||||
property MaxSteps: Integer read FMaxSteps write FMaxSteps default 50;
|
property MaxSteps: Integer read FMaxSteps write FMaxSteps default 50;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -219,6 +220,17 @@ begin
|
|||||||
RawData := Grid;
|
RawData := Grid;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
Note: no sanity check on RawData is performed!
|
||||||
|
}
|
||||||
|
function TSudoku.GiveSolution(var RawData: TRawGrid; out Values: TValues; out Steps: Integer): Boolean;
|
||||||
|
begin
|
||||||
|
Grid := RawData;
|
||||||
|
Result := Solve(Steps);
|
||||||
|
RawData := Grid;
|
||||||
|
Values := GridToValues;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSudoku.CalculateValues(out IsSolved: Boolean);
|
procedure TSudoku.CalculateValues(out IsSolved: Boolean);
|
||||||
var
|
var
|
||||||
c, r: Integer;
|
c, r: Integer;
|
||||||
|
Loading…
Reference in New Issue
Block a user