2020-01-04 14:39:11 +00:00
|
|
|
unit sudokumain;
|
|
|
|
|
|
|
|
{
|
|
|
|
***************************************************************************
|
|
|
|
* Copyright (C) 2006 Matthijs Willemstein *
|
|
|
|
* *
|
2020-01-04 15:24:53 +00:00
|
|
|
* Note: the original code by Matthijs was checked in as revision 7217 *
|
|
|
|
* in Lazarus-CCR subversion repository *
|
|
|
|
* *
|
2020-01-04 14:39:11 +00:00
|
|
|
* This source is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This code is distributed in the hope that it will be useful, but *
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
|
|
* General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* A copy of the GNU General Public License is available on the World *
|
|
|
|
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
|
|
|
|
* obtain it by writing to the Free Software Foundation, *
|
|
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
|
|
* *
|
|
|
|
***************************************************************************
|
|
|
|
}
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
|
|
|
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Grids,
|
2020-01-04 15:20:09 +00:00
|
|
|
Buttons, StdCtrls, SudokuType;
|
2020-01-04 14:39:11 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
|
|
|
|
{ TForm1 }
|
|
|
|
|
|
|
|
TForm1 = class(TForm)
|
|
|
|
ButtonSolve: TButton;
|
|
|
|
ButtonFill: TButton;
|
2020-01-04 16:41:52 +00:00
|
|
|
SGrid: TStringGrid;
|
2020-01-04 14:39:11 +00:00
|
|
|
procedure ButtonFillClick(Sender: TObject);
|
|
|
|
procedure ButtonSolveClick(Sender: TObject);
|
2020-01-04 17:19:07 +00:00
|
|
|
procedure EditorKeyPress(Sender: TObject; var Key: char);
|
2020-01-04 16:37:48 +00:00
|
|
|
procedure FormActivate(Sender: TObject);
|
2020-01-04 16:41:52 +00:00
|
|
|
procedure SGridPrepareCanvas(sender: TObject; aCol, aRow: Integer;
|
2020-01-04 15:12:28 +00:00
|
|
|
{%H-}aState: TGridDrawState);
|
2020-01-04 17:19:07 +00:00
|
|
|
procedure SGridSelectEditor(Sender: TObject; {%H-}aCol, {%H-}aRow: Integer;
|
|
|
|
var Editor: TWinControl);
|
2020-01-04 14:39:11 +00:00
|
|
|
private
|
|
|
|
{ private declarations }
|
|
|
|
theValues: TValues;
|
2020-01-04 15:20:09 +00:00
|
|
|
function SolveSudoku: Boolean;
|
|
|
|
procedure ShowSolution;
|
2020-01-04 14:39:11 +00:00
|
|
|
public
|
|
|
|
{ public declarations }
|
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
|
|
|
Form1: TForm1;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
2020-01-04 14:55:32 +00:00
|
|
|
{$R *.lfm }
|
2020-01-04 14:39:11 +00:00
|
|
|
|
|
|
|
{ TForm1 }
|
|
|
|
|
|
|
|
procedure TForm1.ButtonFillClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
c, r: Integer;
|
|
|
|
begin
|
2020-01-04 16:41:52 +00:00
|
|
|
for c := 0 to pred(SGrid.ColCount) do
|
|
|
|
for r := 0 to pred(SGrid.RowCount) do
|
|
|
|
SGrid.Cells[c, r] := '';
|
|
|
|
SGrid.Options := SGrid.Options + [goEditing];
|
|
|
|
SGrid.SetFocus;
|
2020-01-04 14:39:11 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TForm1.ButtonSolveClick(Sender: TObject);
|
|
|
|
begin
|
2020-01-04 16:41:52 +00:00
|
|
|
SGrid.Options := SGrid.Options - [goEditing];
|
2020-01-04 14:39:11 +00:00
|
|
|
SolveSudoku;
|
2020-01-04 15:20:09 +00:00
|
|
|
ShowSolution;
|
2020-01-04 14:39:11 +00:00
|
|
|
end;
|
|
|
|
|
2020-01-04 17:19:07 +00:00
|
|
|
procedure TForm1.EditorKeyPress(Sender: TObject; var Key: char);
|
|
|
|
var
|
|
|
|
Ed: TStringCellEditor;
|
|
|
|
begin
|
|
|
|
if (Sender is TStringCellEditor) then
|
|
|
|
begin
|
|
|
|
Ed := TStringCellEditor(Sender);
|
|
|
|
Ed.SelectAll; //Key will now overwrite selection, in effect allowing to enter only 1 key
|
|
|
|
if not (Key in [#8, '1'..'9']) then Key := #0;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-01-04 16:37:48 +00:00
|
|
|
procedure TForm1.FormActivate(Sender: TObject);
|
|
|
|
begin
|
|
|
|
Self.OnActivate := nil;
|
2020-01-04 16:41:52 +00:00
|
|
|
SGrid.ClientWidth := 9 * SGrid.DefaultColWidth;
|
|
|
|
SGrid.ClientHeight := 9 * SGrid.DefaultRowHeight;
|
|
|
|
ClientWidth := 2 * SGrid.Left + SGrid.Width;
|
2020-01-04 16:37:48 +00:00
|
|
|
end;
|
2020-01-04 15:02:45 +00:00
|
|
|
|
2020-01-04 17:19:07 +00:00
|
|
|
|
2020-01-04 16:41:52 +00:00
|
|
|
procedure TForm1.SGridPrepareCanvas(sender: TObject; aCol, aRow: Integer;
|
2020-01-04 15:02:45 +00:00
|
|
|
aState: TGridDrawState);
|
2020-01-04 14:39:11 +00:00
|
|
|
var
|
2020-01-04 15:02:45 +00:00
|
|
|
NeedsColor: Boolean;
|
2020-01-04 14:39:11 +00:00
|
|
|
begin
|
2020-01-04 15:02:45 +00:00
|
|
|
NeedsColor := False;
|
|
|
|
if aCol in [0..2, 6..8] then
|
|
|
|
begin
|
|
|
|
if aRow in [0..2, 6..8] then
|
|
|
|
begin
|
|
|
|
NeedsColor := True;
|
2020-01-04 14:39:11 +00:00
|
|
|
end;
|
2020-01-04 15:02:45 +00:00
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
if aRow in [3..5] then
|
|
|
|
begin
|
|
|
|
NeedsColor := True;
|
2020-01-04 14:39:11 +00:00
|
|
|
end;
|
|
|
|
end;
|
2020-01-04 15:02:45 +00:00
|
|
|
if NeedsColor then
|
|
|
|
(Sender as TStringGrid).Canvas.Brush.Color := $00EEEEEE;
|
2020-01-04 14:39:11 +00:00
|
|
|
end;
|
|
|
|
|
2020-01-04 17:19:07 +00:00
|
|
|
procedure TForm1.SGridSelectEditor(Sender: TObject; aCol, aRow: Integer;
|
|
|
|
var Editor: TWinControl);
|
|
|
|
var
|
|
|
|
Ed: TStringCellEditor;
|
|
|
|
begin
|
|
|
|
if Editor is TStringCellEditor then
|
|
|
|
begin
|
|
|
|
Ed := TStringCellEditor(Editor);
|
|
|
|
Ed.OnKeyPress := @EditorKeyPress;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-01-04 14:39:11 +00:00
|
|
|
|
2020-01-04 15:20:09 +00:00
|
|
|
function TForm1.SolveSudoku: Boolean;
|
2020-01-04 14:39:11 +00:00
|
|
|
var
|
|
|
|
aSudoku: TSudoku;
|
2020-01-04 15:20:09 +00:00
|
|
|
Col, Row: Integer;
|
2020-01-04 17:39:25 +00:00
|
|
|
Steps, AValue: Integer;
|
2020-01-04 14:39:11 +00:00
|
|
|
begin
|
2020-01-04 17:39:25 +00:00
|
|
|
theValues := Default(TValues); //initialize all to zero
|
2020-01-04 15:20:09 +00:00
|
|
|
for Col := 0 to 8 do begin
|
|
|
|
for Row := 0 to 8 do begin
|
2020-01-04 16:41:52 +00:00
|
|
|
if Length(SGrid.Cells[Col, Row]) >= 1 then
|
2020-01-04 15:20:09 +00:00
|
|
|
begin
|
2020-01-04 17:39:25 +00:00
|
|
|
if TryStrToInt(SGrid.Cells[Col, Row][1], AValue) then
|
|
|
|
theValues[Col + 1, Row + 1] := AValue;
|
2020-01-04 14:39:11 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
aSudoku := TSudoku.Create;
|
2020-01-04 15:20:09 +00:00
|
|
|
Result := aSudoku.GiveSolution(theValues, Steps);
|
2020-01-04 14:39:11 +00:00
|
|
|
aSudoku.Free;
|
2020-01-04 15:20:09 +00:00
|
|
|
if Result then
|
|
|
|
ShowMessage(Format('Sudoku solved in %d steps.', [Steps]))
|
|
|
|
else
|
|
|
|
ShowMessage(Format('Unable to completely solve sudoku (tried %d steps).',[Steps]));
|
|
|
|
end;
|
|
|
|
|
2020-01-04 17:19:07 +00:00
|
|
|
|
2020-01-04 15:20:09 +00:00
|
|
|
procedure TForm1.ShowSolution;
|
|
|
|
var
|
|
|
|
Col, Row: Integer;
|
|
|
|
Ch: Char;
|
|
|
|
begin
|
|
|
|
for Col := 0 to 8 do
|
|
|
|
begin
|
|
|
|
for Row := 0 to 8 do
|
|
|
|
begin
|
2020-01-04 17:39:25 +00:00
|
|
|
Ch := IntToStr(theValues[Col + 1, Row + 1])[1];
|
2020-01-04 15:20:09 +00:00
|
|
|
if Ch = '0' then
|
|
|
|
Ch := #32;
|
2020-01-04 16:41:52 +00:00
|
|
|
SGrid.Cells[Col, Row] := Ch;
|
2020-01-04 15:20:09 +00:00
|
|
|
end;
|
|
|
|
end;
|
2020-01-04 14:39:11 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
end.
|
|
|
|
|