home *** CD-ROM | disk | FTP | other *** search
- unit TTT;
- {
- File: TTT.PAS
- Author: Bob Swart [100434,2072]
- Purpose: Tic-tac-toe game component
-
- Usage: Install on component palette. Make sure MAGIC.DLL is available
- in the WINDOWS\SYSTEM directory or the directory with the final
- application itself. Otherwise, the component will not work and
- raise an exception.
-
- Design: Published in The Delphi Magazine issue #2
- Send your name & (postal)address to Chris Frizelle at 70630,717
- for a free sample issue.
- }
- {$DEFINE EXCEPTIONS}
- interface
- uses SysUtils, Classes, Controls, StdCtrls, Dialogs, Magic;
-
- {$IFDEF EXCEPTIONS}
- Type
- EBadChar = class(Exception);
- EDLLNotLoaded = class(Exception);
- {$ENDIF EXCEPTIONS}
-
- Type
- TTicTacToe = class(TWinControl)
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
-
- private { Magic DLL handle }
- Game: HGame;
-
- private { 9 game buttons }
- Button: Array[TPlace] of TButton;
- procedure ButtonClick(Sender: TObject);
- procedure ComputerMove;
- procedure UserMove(Move: TPlace);
-
- private { start button }
- TheStartButton: TButton;
- procedure StartButtonClick(Sender: TObject);
-
- private { game properties }
- FStartButton: Boolean;
- FUserStarts: Boolean;
- FGameEnded: Boolean;
- FUserChar: Char;
- FCompChar: Char;
- FVersion: Integer;
- FDummy: Integer; { to catch the FVersion changes... }
-
- protected { design interface }
- procedure SetStartButton(Value: Boolean);
- procedure SetUserStarts(Value: Boolean);
- procedure SetUserChar(Value: Char);
- procedure SetCompChar(Value: Char);
- function GetCaption: String;
- procedure SetCaption(Value: String);
-
- published { user interface }
- property StartButton: Boolean
- read FStartButton write FStartButton
- default False;
- property Caption: String
- read GetCaption write SetCaption;
- property UserStarts: Boolean
- read FUserStarts write SetUserStarts
- default False;
- property GameEnded: Boolean
- read FGameEnded
- default False;
- property UserChar: Char
- read FUserChar write SetUserChar
- default 'X';
- property CompChar: Char
- read FCompChar write SetCompChar
- default '0';
- property Version: Integer
- read FVersion write FDummy
- default 2;
- end {TTicTacToe};
-
- implementation
-
- constructor TTicTacToe.Create(AOwner: TComponent);
- var ButtonIndex: TPlace;
- begin
- inherited Create(AOwner);
- Game := 0;
- UserStarts := False;
- FGameEnded := True;
- FUserChar := 'X';
- FCompChar := '0';
- FVersion := 2; { my version number }
-
- TheStartButton := TButton.Create(Self);
- TheStartButton.Parent := Self;
- TheStartButton.Visible := True;
- { TheStartButton.Caption := 'Humor me...'; }
- TheStartButton.OnClick := StartButtonClick;
-
- for ButtonIndex := Low(ButtonIndex) to High(ButtonIndex) do
- begin
- Button[ButtonIndex] := TButton.Create(Self);
- Button[ButtonIndex].Parent := Self;
- Button[ButtonIndex].Caption := '';
- Button[ButtonIndex].Visible := False;
- Button[ButtonIndex].OnClick := ButtonClick;
- end;
- SetBounds(Left,Top,132,132)
- end {Create};
-
- destructor TTicTacToe.Destroy;
- var ButtonIndex: TPlace;
- begin
- if (Game > 0) then EndGame(Game);
- TheStartButton.Destroy;
- for ButtonIndex := Low(ButtonIndex) to High(ButtonIndex) do
- Button[ButtonIndex].Destroy;
- inherited Destroy
- end {Destroy};
-
-
- procedure TTicTacToe.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
- Const Grid = 3;
- GridX = 2;
- GridY = 2;
- var X,DX,W,Y,DY,H: Word;
- begin
- Inherited SetBounds(ALeft,ATop,AWidth,AHeight);
- TheStartButton.SetBounds(0,0,Width,Height);
- X := GridX;
- DX := (Width div (Grid * (GridX+GridX))) * (GridX+GridX);
- W := DX - GridX;
- Y := GridY;
- DY := (Height div (Grid * (GridY+GridY))) * (GridY+GridY);
- H := DY - GridY;
- Button[8].SetBounds(X, Y, W,H);
- Button[1].SetBounds(X, Y+DY, W,H);
- Button[6].SetBounds(X, Y+DY+DY, W,H);
- Inc(X,DX);
- Button[3].SetBounds(X, Y, W,H);
- Button[5].SetBounds(X, Y+DY, W,H);
- Button[7].SetBounds(X, Y+DY+DY, W,H);
- Inc(X,DX);
- Button[4].SetBounds(X, Y, W,H);
- Button[9].SetBounds(X, Y+DY, W,H);
- Button[2].SetBounds(X, Y+DY+DY, W,H)
- end {SetBounds};
-
-
- procedure TTicTacToe.StartButtonClick(Sender: TObject);
- var ButtonIndex: TPlace;
- begin
- if MagicLoaded then
- begin
- Game := NewGame;
- FGameEnded := False;
- TheStartButton.Visible := False;
- for ButtonIndex := Low(ButtonIndex) to High(ButtonIndex) do
- Button[ButtonIndex].Visible := True;
- if UserStarts then
- begin
- MessageDlg('You may start...', mtInformation, [mbOk], 0);
- Button[5].SetFocus; { hint... }
- end
- else
- ComputerMove
- end
- else
- {$IFDEF EXCEPTIONS}
- raise EDLLNotLoaded.Create('MAGIC.DLL could not be loaded!')
- {$ELSE}
- MessageDlg('Error loading MAGIC.DLL...', mtInformation, [mbOk], 0)
- {$ENDIF}
- end {ButtonClick};
-
-
- procedure TTicTacToe.ButtonClick(Sender: TObject);
- var ButtonIndex: TPlace;
- begin
- for ButtonIndex := Low(ButtonIndex) to High(ButtonIndex) do
- if Button[ButtonIndex] = Sender as TButton then
- UserMove(ButtonIndex)
- end {ButtonClick};
-
-
- procedure TTicTacToe.ComputerMove;
- var Move: TMove;
- begin
- if IsWinner(Game) = NoneID then
- begin
- Move := NextMove(Game,CompID);
- if Move = 0 then
- begin
- FGameEnded := True;
- MessageDlg('Neither has won, the game is a draw!', mtInformation, [mbOk], 0)
- end
- else
- begin
- MakeMove(Game,CompID,Move);
- Button[Move].Caption := CompChar;
- if IsWinner(Game) = CompID then
- MessageDlg('I have won!', mtInformation, [mbOk], 0)
- else
- begin
- Move := NextMove(Game,UserID);
- if Move = 0 then
- begin
- FGameEnded := True;
- MessageDlg('Neither has won, the game is a draw!', mtInformation, [mbOk], 0)
- end
- else Button[Move].SetFocus { hint... }
- end
- end
- end
- end {ComputerMove};
-
- procedure TTicTacToe.UserMove(Move: TPlace);
- begin
- if IsWinner(Game) <> NoneID then
- begin
- if IsWinner(Game) = UserID then
- MessageDlg('You have already won!', mtInformation, [mbOk], 0)
- else
- MessageDlg('I have already won!', mtInformation, [mbOk], 0)
- end
- else
- begin
- if FGameEnded then
- MessageDlg('The game has already ended!', mtInformation, [mbOk], 0)
- else
- begin
- if GetValue(Game, Move) <> NoneID then
- MessageDlg('This place is occupied!', mtWarning, [mbOk], 0)
- else
- begin
- Button[Move].Caption := UserChar;
- MakeMove(Game,UserID,Move);
- if IsWinner(Game) = UserID then
- MessageDlg('Congratulations, you have won!', mtInformation, [mbOk], 0)
- else
- ComputerMove
- end
- end
- end
- end {UserMove};
-
-
- procedure TTicTacToe.SetUserChar(Value: Char);
- begin
- if Value = FCompChar then
- {$IFDEF EXCEPTIONS}
- raise EBadChar.Create(Value+' already in use by CompChar!')
- {$ELSE}
- MessageDlg('Character '+Value+' already in use by CompChar!', mtError, [mbOk], 0)
- {$ENDIF}
- else FUserChar := Value
- end {SetUserChar};
-
- procedure TTicTacToe.SetCompChar(Value: Char);
- begin
- if Value = FUserChar then
- {$IFDEF EXCEPTIONS}
- raise EBadChar.Create(Value+' already in use by UserChar!')
- {$ELSE}
- MessageDlg('Character '+Value+' already in use by UserChar!', mtError, [mbOk], 0)
- {$ENDIF}
- else FCompChar := Value
- end {SetCompChar};
-
- procedure TTicTacToe.SetUserStarts(Value: Boolean);
- begin
- FUserStarts := Value;
- {$IFDEF DEBUG}
- if FUserStarts then
- MessageDlg('User Starts!', mtInformation, [mbOk], 0)
- else
- MessageDlg('I''ll Start!', mtInformation, [mbOk], 0)
- {$ENDIF DEBUG}
- end {SetUserStarts};
-
- procedure TTicTacToe.SetStartButton(Value: Boolean);
- begin
- FStartButton := Value
- end {SetStartButton};
-
- function TTicTacToe.GetCaption: String;
- begin
- GetCaption := TheStartButton.Caption
- end {GetCaption};
-
- procedure TTicTacToe.SetCaption(Value: String);
- begin
- TheStartButton.Caption := Value
- end {SetCaption};
- end.
-