302 lines
6.5 KiB
Plaintext
302 lines
6.5 KiB
Plaintext
{************************************************}
|
|
{ }
|
|
{ Turbo Pascal 6.0 }
|
|
{ Turbo Vision Demo }
|
|
{ Copyright (c) 1990 by Borland International }
|
|
{ }
|
|
{************************************************}
|
|
|
|
unit Puzzle;
|
|
|
|
{$F+,O+,S-,D-}
|
|
|
|
{ Simple puzzle object. See TVDEMO.PAS for an example
|
|
program that uses this unit.
|
|
}
|
|
|
|
|
|
interface
|
|
|
|
uses views, Drivers, Objects, Crt;
|
|
|
|
const
|
|
CPuzzleView = #6#7;
|
|
|
|
type
|
|
|
|
TBoard = array[0..5,0..5] of Char;
|
|
PPuzzleView = ^TPuzzleView;
|
|
TPuzzleView = object(TView)
|
|
Board: TBoard;
|
|
Moves: Word;
|
|
Solved: Boolean;
|
|
constructor Init(Bounds: TRect);
|
|
constructor Load(var S: TStream);
|
|
procedure HandleEvent(var Event: TEvent); Virtual;
|
|
procedure Draw; Virtual;
|
|
function GetPalette: PPalette; virtual;
|
|
procedure MoveKey(Key: Word);
|
|
procedure MoveTile(Point: TPoint);
|
|
procedure Scramble;
|
|
procedure Store(var S: TStream);
|
|
procedure WinCheck;
|
|
end;
|
|
|
|
PPuzzleWindow = ^TPuzzleWindow;
|
|
TPuzzleWindow = object(TWindow)
|
|
constructor Init;
|
|
end;
|
|
|
|
const
|
|
RPuzzleView: TStreamRec = (
|
|
ObjType: 10010;
|
|
VmtLink: Ofs(TypeOf(TPuzzleView)^);
|
|
Load: @TPuzzleView.Load;
|
|
Store: @TPuzzleView.Store
|
|
);
|
|
RPuzzleWindow: TStreamRec = (
|
|
ObjType: 10011;
|
|
VmtLink: Ofs(TypeOf(TPuzzleWindow)^);
|
|
Load: @TPuzzleWindow.Load;
|
|
Store: @TPuzzleWindow.Store
|
|
);
|
|
|
|
procedure RegisterPuzzle;
|
|
|
|
implementation
|
|
|
|
{ TPuzzleWindow }
|
|
|
|
constructor TPuzzleWindow.Init;
|
|
var
|
|
R: TRect;
|
|
begin
|
|
R.Assign(1, 1, 21, 7);
|
|
TWindow.Init(R, 'Puzzle', 0);
|
|
Flags := Flags and not (wfZoom + wfGrow);
|
|
GrowMode := 0;
|
|
GetExtent(R);
|
|
R.Grow(-1, -1);
|
|
Insert(New(PPuzzleView, Init(R)));
|
|
end;
|
|
|
|
{ TPuzzleView }
|
|
|
|
constructor TPuzzleView.Init(Bounds: TRect);
|
|
type
|
|
TBoardValue = array[1..16] of Char;
|
|
const
|
|
SBoardValue: TBoardValue =
|
|
('A','B','C','D',
|
|
'E','F','G','H',
|
|
'I','J','K','L',
|
|
'M','N','O',' ');
|
|
var
|
|
I, J: Integer;
|
|
begin
|
|
TView.Init(Bounds);
|
|
Randomize;
|
|
Options := Options or ofSelectable;
|
|
FillChar(Board, SizeOf(Board), '?');
|
|
for I := 0 to 3 do
|
|
for J := 0 to 3 do
|
|
Board[I+1, J+1] := SBoardValue[I*4 + J+1];
|
|
Scramble;
|
|
end;
|
|
|
|
constructor TPuzzleView.Load(var S: TStream);
|
|
begin
|
|
TView.Load(S);
|
|
S.Read(Board, SizeOf(Board) + Sizeof(Moves) + SizeOf(Solved));
|
|
end;
|
|
|
|
Procedure TPuzzleView.Draw;
|
|
var
|
|
I, J, K: Integer;
|
|
B: array[0..17] of word;
|
|
S1: String[3];
|
|
Color: array[0..1] of byte;
|
|
ColorBack: Byte;
|
|
const
|
|
Map: array['A'..'O'] of Byte =
|
|
(0, 1, 0, 1,
|
|
1, 0, 1, 0,
|
|
0, 1, 0, 1,
|
|
1, 0, 1);
|
|
begin
|
|
Color[0] := GetColor(1);
|
|
Color[1] := GetColor(2);
|
|
ColorBack := GetColor(1);
|
|
if Solved then Color[1] := Color[0]
|
|
else Color[1] := GetColor(2);
|
|
for I := 1 to 4 do
|
|
begin
|
|
MoveChar(B, ' ', ColorBack, 18);
|
|
if I = 2 then MoveStr(B[13], 'Move', ColorBack);
|
|
if I = 3 Then
|
|
begin
|
|
Str(Moves: 3, S1);
|
|
MoveStr(B[14], S1, ColorBack);
|
|
end;
|
|
for J := 1 to 4 do
|
|
begin
|
|
S1 := ' ' + Board[I, J] + ' ';
|
|
K := (Byte(Board[I, J]) mod 2) +1;
|
|
if Board[I, J] = ' ' then MoveStr(B[(J - 1) * 3], S1, Color[0])
|
|
else
|
|
MoveStr(B[(J - 1) * 3], S1, Color[Map[Board[I, J]]]);
|
|
end;
|
|
WriteLine(0, I - 1, 18, 1, B);
|
|
end;
|
|
end;
|
|
|
|
function TPuzzleView.GetPalette: PPalette;
|
|
const
|
|
P: String[Length(CPuzzleView)] = CPuzzleView;
|
|
begin
|
|
GetPalette := @P;
|
|
end;
|
|
|
|
procedure TPuzzleView.HandleEvent(var Event: TEvent);
|
|
begin
|
|
TView.HandleEvent(Event);
|
|
if Solved and (Event.What and (evKeyDown + evMouseDown) <> 0) then
|
|
begin
|
|
Scramble;
|
|
ClearEvent(Event);
|
|
end;
|
|
case Event.What of
|
|
evMouseDown: MoveTile(Event.Where);
|
|
evKeyDown: MoveKey(Event.KeyCode);
|
|
else
|
|
Exit;
|
|
end;
|
|
ClearEvent(Event);
|
|
WinCheck;
|
|
end;
|
|
|
|
procedure TPuzzleView.MoveKey(Key: Word);
|
|
var
|
|
X, Y, I, J: Integer;
|
|
begin
|
|
for I:=1 To 4 do
|
|
for J:=1 To 4 do
|
|
if Board[i,j] = ' ' then
|
|
begin
|
|
Y:=I;
|
|
X:=J;
|
|
end;
|
|
|
|
case Key of
|
|
kbDown:
|
|
if Y > 1 then
|
|
begin
|
|
Board[Y, X] := Board[Y-1, X];
|
|
Board[Y-1, X] := ' ';
|
|
Inc(moves, Byte(moves<1000));
|
|
end;
|
|
kbUp:
|
|
if Y < 4 then
|
|
begin
|
|
Board[Y, X] := Board[Y+1, X];
|
|
Board[Y+1, X] := ' ';
|
|
Inc(moves, Byte(moves<1000));
|
|
end;
|
|
kbRight:
|
|
if X > 1 then
|
|
begin
|
|
Board[Y, X] := Board[Y, X-1];
|
|
Board[Y, X-1] := ' ';
|
|
Inc(moves, Byte(moves<1000));
|
|
end;
|
|
kbLeft:
|
|
if X < 4 then
|
|
begin
|
|
Board[Y, X] := Board[Y, X+1];
|
|
Board[Y, X+1] := ' ';
|
|
Inc(moves,Byte(moves<1000));
|
|
end;
|
|
end;
|
|
DrawView;
|
|
end;
|
|
|
|
procedure TPuzzleView.MoveTile(Point: TPoint);
|
|
var
|
|
P: TPoint;
|
|
X, Y: Word;
|
|
begin
|
|
MakeLocal(Point, P);
|
|
X := ((P.X + 3) div 3);
|
|
Y := P.Y + 1;
|
|
if (X > 0) and (X < 5) and (Y > 0) and (Y < 5) Then
|
|
begin
|
|
if Board[Y, X-1] = ' ' then
|
|
begin
|
|
Board[Y, X-1] := Board[Y, X];
|
|
Board[Y, X] := ' ';
|
|
Inc(moves, Byte(moves<1000));
|
|
end;
|
|
if Board[Y-1, X] = ' ' then
|
|
begin
|
|
Board[Y-1, X] := Board[Y, X];
|
|
Board[Y, X] := ' ';
|
|
Inc(moves, Byte(moves<1000));
|
|
end;
|
|
if Board[Y, X+1] = ' ' then
|
|
begin
|
|
Board[Y, X+1] := Board[Y, X];
|
|
Board[Y, X] := ' ';
|
|
Inc(moves, Byte(moves<1000));
|
|
end;
|
|
if Board[Y+1, X] = ' ' then
|
|
begin
|
|
Board[Y+1, X] := Board[Y, X];
|
|
Board[Y, X] := ' ';
|
|
Inc(moves, Byte(moves<1000));
|
|
end;
|
|
DrawView;
|
|
end;
|
|
end;
|
|
|
|
procedure TPuzzleView.Scramble;
|
|
begin
|
|
Moves := 0;
|
|
Solved := False;
|
|
repeat
|
|
case Random(4) of
|
|
0: MoveKey(kbUp);
|
|
1: MoveKey(kbDown);
|
|
2: MoveKey(kbRight);
|
|
3: MoveKey(kbLeft);
|
|
end;
|
|
until Moves=500;
|
|
Moves := 0;
|
|
DrawView;
|
|
end;
|
|
|
|
procedure TPuzzleView.Store(var S: TStream);
|
|
begin
|
|
TView.Store(S);
|
|
S.Write(Board, SizeOf(Board) + Sizeof(Moves) + SizeOf(Solved));
|
|
end;
|
|
|
|
procedure TPuzzleView.WinCheck;
|
|
type
|
|
BoardStr = array [0..35] of Char;
|
|
const
|
|
FBoard: BoardStr = '???????ABCD??EFGH??IJKL??MNO ???????';
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Solved := BoardStr(Board) = FBoard;
|
|
DrawView;
|
|
end;
|
|
|
|
procedure RegisterPuzzle;
|
|
begin
|
|
RegisterType(RPuzzleView);
|
|
RegisterType(RPuzzleWindow);
|
|
end;
|
|
|
|
end.
|