
15 パズルは、 1 から 15 までのパネルを正しく並べ替えるゲームです。
uCells.pas
unit uCells;
interface
uses SysUtils, Extctrls, Graphics, Types;
const
MAX_ROW_COUNT = 4;
MAX_COL_COUNT = 4;
MAX_CELL_COUNT = 16;
EMPTY_CELL = -1;
type
TCellCollection = class;
TCellCanvas = class
private
FBox: TPaintBox;
FCellWidth: Integer;
FCellHeight: Integer;
FCellCollection: TCellCollection;
procedure DoDrawCell(X, Y: Integer; s: string);
procedure DrawLine;
procedure DrawCell; overload;
procedure DrawCell(TargetCellNum, EmptyCellNum: Integer); overload;
function GetClickedCellNumber(X, Y: Integer): Integer;
public
constructor Create(Box: TPaintBox);
destructor Destroy; override;
procedure Initialize;
procedure CellClick(X, Y: Integer);
end;
TCellCollection = class
private
FCells: array[0..MAX_CELL_COUNT-1] of Integer;
procedure Shuffle;
function GetCell(index: Integer): Integer;
public
procedure Initialize;
function GetEmptyCellNum: Integer;
procedure Exchange(x: Integer);
function IsExchange(x: Integer): Boolean;
property Cells[index: Integer]: Integer read GetCell; default;
end;
implementation
{ TFreeCanvas }
function GetCol(x: Integer): Integer;
begin
Result := x mod MAX_COL_COUNT;
end;
function GetRow(x: Integer): Integer;
begin
Result := x div MAX_ROW_COUNT;
end;
procedure TCellCanvas.CellClick(X, Y: Integer);
begin
if FCellCollection.IsExchange(GetClickedCellNumber(X, Y)) then begin
DrawCell(GetClickedCellNumber(X, Y), FCellCollection.GetEmptyCellNum);
FCellCollection.Exchange(GetClickedCellNumber(X, Y));
end;
end;
constructor TCellCanvas.Create(Box: TPaintBox);
begin
FBox := Box;
FCellCollection := TCellCollection.Create;
end;
destructor TCellCanvas.Destroy;
begin
FCellCollection.Free;
inherited;
end;
procedure TCellCanvas.DrawCell;
var
i, j, Count: Integer;
s: string;
begin
Count := 0;
for i := 0 to MAX_ROW_COUNT-1 do
for j := 0 to MAX_COL_COUNT-1 do begin
if FCellCollection[Count] = EMPTY_CELL then
s := ' '
else
s := IntToStr(FCellCollection[Count]);
DoDrawCell(j*FCellWidth+5, i*FCellHeight+5, s);
Inc(Count);
end;
end;
procedure TCellCanvas.DoDrawCell(X, Y: Integer; s: string);
begin
FBox.Canvas.TextOut(X, Y, s);
end;
procedure TCellCanvas.DrawCell(TargetCellNum, EmptyCellNum: Integer);
begin
DoDrawCell(GetCol(EmptyCellNum)*FCellWidth+5,
GetRow(EmptyCellNum)*FCellHeight+5,
IntToStr(FCellCollection[TargetCellNum]));
DoDrawCell(GetCol(TargetCellNum)*FCellWidth+5,
GetRow(TargetCellNum)*FCellHeight+5,
' ');
end;
procedure TCellCanvas.DrawLine;
var
i: Integer;
begin
FBox.Canvas.Pen.Color := clGray;
for i := 1 to MAX_COL_COUNT-1 do begin
FBox.Canvas.MoveTo(i*FCellWidth, 0);
FBox.Canvas.LineTo(i*FCellWidth, FBox.ClientHeight);
end;
for i := 1 to MAX_ROW_COUNT-1 do begin
FBox.Canvas.MoveTo(0, i*FCellHeight);
FBox.Canvas.LineTo(FBox.ClientWidth, i*FCellHeight);
end;
end;
function TCellCanvas.GetClickedCellNumber(X, Y: Integer): Integer;
var
Col, Row: Integer;
begin
Col := X div FCellWidth;
Row := Y div FCellHeight;
Result := Col + MAX_COL_COUNT*Row;
end;
procedure TCellCanvas.Initialize;
begin
FBox.Canvas.Brush.Color := clWhite;
FBox.Canvas.FillRect(FBox.ClientRect);
FCellWidth := FBox.ClientWidth div MAX_COL_COUNT;
FCellHeight := FBox.ClientHeight div MAX_ROW_COUNT;
FBox.Canvas.Font.Height := FCellHeight div 2;
FCellCollection.Initialize;
DrawLine;
DrawCell;
end;
{ TCellCollection }
procedure TCellCollection.Exchange(x: Integer);
var
tmp, num: Integer;
begin
num := GetEmptyCellNum;
tmp := FCells[x];
FCells[x] := FCells[num];
FCells[num] := tmp;
end;
function TCellCollection.GetCell(index: Integer): Integer;
begin
Result := FCells[index];
end;
function TCellCollection.GetEmptyCellNum: Integer;
var
i: Integer;
begin
Result := 0;
for i := 0 to High(FCells) do
if FCells[i] = EMPTY_CELL then begin
Result := i;
exit;
end;
end;
procedure TCellCollection.Initialize;
var
i: Integer;
begin
for i := 0 to High(FCells)-1 do
fCells[i] := i+1;
fCells[High(FCells)] := EMPTY_CELL;
Shuffle;
end;
function TCellCollection.IsExchange(x: Integer): Boolean;
var
Num, Row, Col,
ClickedRow, ClickedCol: Integer;
begin
Result := false;
Num := GetEmptyCellNum;
Row := GetRow(Num);
Col := GetCol(Num);
ClickedRow := GetRow(x);
ClickedCol := GetCol(x);
if ((Abs(Row-ClickedRow) = 0) and (Abs(Col-ClickedCol) = 1)) or
((Abs(Row-ClickedRow) = 1) and (Abs(Col-ClickedCol) = 0)) then
Result := true;
end;
procedure TCellCollection.Shuffle;
function HasAnswer: Boolean;
var
i, j, tmp, Count: Integer;
begin
Count := 0;
for i := 0 to High(FCells)-1 do begin
tmp := FCells[i];
for j := i+1 to High(FCells)-1 do
if tmp > FCells[j] then Inc(Count);
end;
Result := (Count mod 2) = 0;
end;
var
i, len, a, b, tmp: Integer;
begin
len := High(FCells);
for i := 0 to len do begin
a := Random(len);
b := Random(len);
tmp := FCells[a];
FCells[a] := FCells[b];
FCells[b] := tmp;
end;
if not HasAnswer then Shuffle;
end;
end.
Main.pas
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, uCells;
type
TForm1 = class(TForm)
PaintBox1: TPaintBox;
Button1: TButton;
PaintBox2: TPaintBox;
PaintBox3: TPaintBox;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure PaintBox3MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PaintBox2MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private 宣言 }
FCellCanvas1: TCellCanvas;
FCellCanvas2: TCellCanvas;
FCellCanvas3: TCellCanvas;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
Randomize;
FCellCanvas1 := TCellCanvas.Create(PaintBox1);
FCellCanvas2 := TCellCanvas.Create(PaintBox2);
FCellCanvas3 := TCellCanvas.Create(PaintBox3);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FCellCanvas1.Free;
FCellCanvas2.Free;
FCellCanvas3.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
FCellCanvas1.Initialize;
FCellCanvas2.Initialize;
FCellCanvas3.Initialize;
end;
procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
FCellCanvas1.CellClick(X, Y);
end;
procedure TForm1.PaintBox2MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
FCellCanvas2.CellClick(X, Y);
end;
procedure TForm1.PaintBox3MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
FCellCanvas3.CellClick(X, Y);
end;
end.