dos_compilers/Borland Turbo Pascal v6/TVDEMOS/PUZZLE.PAS
2024-07-02 07:11:05 -07:00

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.