home *** CD-ROM | disk | FTP | other *** search
- {************************************************}
- { }
- { Turbo Vision Chess Demo }
- { Copyright (c) 1992 by Borland International }
- { }
- {************************************************}
-
- unit TVBoard;
-
- interface
-
- {$IFDEF DPMI}
- uses Views, Objects, Dialogs, Validate, TVChsCmd, ChessDLL, MoveList,
- Drivers, StdDlg, Dos, CTimers;
- {$ELSE}
- uses Views, Objects, Dialogs, Validate, TVChsCmd, ChessInf, MoveList,
- Drivers, StdDlg, Dos, CTimers;
- {$ENDIF}
-
- const
- ChessSignature : array [0..33] of Char = 'Borland Pascal Chess saved game'#26#0;
-
- type
- { TChessSurface }
-
- PChessSurface = ^TChessSurface;
- TChessSurface = object(TView)
- ValidMoves: array[1..8, 1..8] of Boolean;
- Squares: array[1..8, 1..8] of PView;
- procedure Clear;
- procedure Draw; virtual;
- end;
-
- { TValidateMove }
-
- PValidateMove = ^TValidateMove;
- TValidateMove = object(TValidator)
- function IsValid(const S: String): Boolean; virtual;
- procedure Error; virtual;
- function Transfer(var S: String; Buffer: Pointer; Flag: TVTransfer):
- Word; virtual;
- end;
-
- { Palette layout }
- { 1 = Border }
- { 2 = White square }
- { 3 = Black sqaure }
- { 4 = Black piece }
- { 5 = White piece }
- { 6 = Black in jeopardy }
- { 7 = White in jeopardy }
- { 8 = White hint }
- { 9 = Black hint }
-
- PChessBoard = ^TChessBoard;
- TChessBoard = object(TGroup)
- Surface: PChessSurface;
- Game: HChess;
- Computer, Player: TColor;
- GameMode: Word;
- GameOver: Boolean;
- MoveHistory: PMoveList;
- GameName: PathStr;
- ThinkState: TSearchStatus;
- ChessTimers: array[TColor] of PChessTimer;
- ValidMoves,
- OpponentMoves: array [0..(28*16+1)] of TMove;
- QSquare: TLocation;
- constructor Init(var Bounds: TRect);
- destructor Done; virtual;
- procedure AddToHistory(const AMove: TMove);
- procedure AcceptComputerMove;
- function CanMovePiece(Color: TColor): Boolean;
- function CheckActiveGame: Word;
- procedure ClearBoard;
- procedure DoThink;
- procedure DrawSurface;
- procedure DrawValidMoves(Empty: Boolean);
- function GetComputerTime: Longint;
- function GetPalette: PPalette; virtual;
- procedure HandleEvent(var Event: TEvent); virtual;
- procedure InitGameBoard;
- procedure InsertPiece(Piece: PView; Location: TLocation);
- procedure MovePiece(Piece: PView; FromLoc, ToLoc: TLocation);
- procedure Process;
- procedure ReadGame;
- procedure Redo;
- procedure RemovePiece(Piece: PView; Location: TLocation);
- procedure ResetCurrentPlayer;
- procedure ResetValidMoves;
- function SaveGame: Word;
- function SaveGameAs: Word;
- procedure SetGameBoard(const ABoard: TBoard);
- procedure SetupNewGameBoard;
- procedure ShowEndGame(Reason: Integer);
- procedure StartComputerMove;
- procedure Undo;
- function ValidateMove(var C: TChange): TChessError;
- function Valid(Command: Word): Boolean; virtual;
- procedure Update;
- procedure UpdateCommands;
- end;
-
- const
- ChessBoard: PChessBoard = nil;
-
- function Opponent(Color: TColor): TColor;
-
- implementation
-
- uses TVPieces, TVChsUtl, TVStatus, App, MsgBox, Strings, TVChstat;
-
- function Opponent(Color: TColor): TColor;
- begin
- if Color = cWhite then
- Opponent := cBlack
- else Opponent := cWhite;
- end;
-
- { TValidateMove }
-
- function TValidateMove.IsValid(const S: String): Boolean;
- var
- Change: TChange;
- MoveStr: array[0..20] of Char;
- begin
- StrPCopy(MoveStr, S);
- IsValid := ParseMove(MoveStr, Change) = ceOK;
- end;
-
- procedure TValidateMove.Error;
- begin
- MessageBox(^C'Invalid move syntax', nil, mfError + mfOKButton +
- mfInsertInApp);
- end;
-
- function TValidateMove.Transfer(var S: String; Buffer: Pointer;
- Flag: TVTransfer): Word;
- var
- Change: TChange;
- MoveStr: array[0..20] of Char;
- begin
- case Flag of
- vtGetData:
- begin
- FillChar(Change, SizeOf(Change), 0);
- StrPCopy(MoveStr, S);
- if ParseMove(MoveStr, Change) = ceOK then
- PChange(Buffer)^ := Change
- else FillChar(Buffer^, SizeOf(TChange), 0);
- end;
- end;
- Transfer := SizeOf(TChange);
- end;
-
- { TChessSurface }
-
- procedure TChessSurface.Clear;
- begin
- FillChar(Squares, SizeOf(Squares), 0);
- end;
-
- procedure TChessSurface.Draw;
- var
- Border, White, Black, Color: Word;
- B: TDrawBuffer;
- I, J, K, Line: Integer;
- DrawChr: Char;
- XOfs, XLen: Integer;
-
- procedure TellPieceToDraw(P: PView);
- begin
- if (P <> nil) and (P^.State and sfDragging = 0) then
- PChessPiece(P)^.RawDraw(B, 2 + 6 * K, I, XOfs, XLen);
- end;
-
- begin
- Border := GetColor($0101);
- White := GetColor($0802);
- Black := GetColor($0903);
- Line := 0;
- for J := 7 downto 0 do
- begin
- if J = 7 then
- begin
- MoveChar(B, ' ', Border, 2);
- for I := 0 to 7 do
- begin
- MoveChar(B[2 + 6 * I], ' ', Border, 3);
- MoveChar(B[5 + 6 * I], Chr($41 + I), Border, 1);
- MoveChar(B[6 + 6 * I], ' ', Border, 2);
- end;
- MoveChar(B[Size.X - 2], ' ', Border, 2);
- WriteBuf(0, Line, Size.X, 1, B);
- Inc(Line);
- end;
- for I := 0 to 2 do
- begin
- MoveChar(B, ' ', Border, 2);
- if I = 1 then
- MoveChar(B, Chr($31 + J), Border, 1);
- for K := 0 to 7 do
- begin
- if (K + J) and 1 = 0 then
- begin
- DrawChr := '░';
- Color := Black
- end
- else
- begin
- DrawChr := '▓';
- Color := White;
- end;
- if ValidMoves[K + 1, J + 1] then
- begin
- DrawChr := ' ';
- Color := Swap(Color);
- end;
- MoveChar(B[2 + 6 * K], DrawChr, Color, 6);
- TellPieceToDraw(Squares[K + 1, J + 1])
- end;
- MoveChar(B[Size.X - 2], ' ', Border, 2);
- WriteBuf(0, Line, Size.X, 1, B);
- Inc(Line);
- end;
- end;
- end;
-
- constructor TChessBoard.Init(var Bounds: TRect);
- var
- Color: TColor;
- begin
- inherited Init(Bounds);
- EventMask := EventMask or evMove;
- Options := Options or ofPostprocess;
- Surface := New(PChessSurface, Init(Bounds));
- Insert(Surface);
- Computer := cBlack;
- Player := cWhite;
- GameMode := Settings.Players;
- for Color := cWhite to cBlack do
- ChessTimers[Color] := New(PChessTimer, Init);
- MoveHistory := New(PMoveList, Init(20, 10));
- if NewGame(Game) <> ceOK then
- Game := 0
- else SetupNewGameBoard;
- if (StatusDialog <> nil) and (Game <> 0) then
- StatusDialog^.Update(Game, ChessTimers, 0, 0, GameMode);
- end;
-
- destructor TChessBoard.Done;
- begin
- if Game <> 0 then DisposeGame(Game);
- inherited Done;
- end;
-
- procedure TChessBoard.AcceptComputerMove;
- var
- Move: TMove;
- begin
- if GetLastMove(Game, Move) = ceOK then
- begin
- AddToHistory(Move);
- Message(@Self, evMove, cmMovePiece, @Move);
- Wait(5);
- Message(@Self, evMove, cmUndoMove, @Move);
- Wait(5);
- Message(@Self, evMove, cmMovePiece, @Move);
- if (GameMode and gmDemo <> 0) and not GameOver then
- StartComputerMove
- else
- begin
- if Settings.Hints and hoThinkAhead <> 0 then
- ThinkAhead(Game);
- ChessTimers[GetPlayer(Game)]^.Mark;
- ChessTimers[GetPlayer(Game)]^.Start;
- ThinkState := GetSearchStatus(Game);
- end;
- ResetValidMoves;
- Update;
- end;
- end;
-
- procedure TChessBoard.AddToHistory(const AMove: TMove);
- var
- ChessPiece: PChessPiece;
- begin
- if MoveHistory <> nil then MoveHistory^.AddMove(AMove);
- if StatusDialog <> nil then StatusDialog^.UpdateList(MoveHistory);
- end;
-
- function TChessBoard.CanMovePiece(Color: TColor): Boolean;
- begin
- CanMovePiece := False;
- if (Game <> 0) and (GetSearchStatus(Game) in [ssComplete, ssThinkAhead]) and
- (Color = GetPlayer(Game)) then CanMovePiece := True;
- end;
-
- function TChessBoard.CheckActiveGame: Word;
- var
- Result: Word;
- begin
- if (MoveHistory <> nil) and (MoveHistory^.Count <> 0) then
- begin
- Result := MessageBox('Save currently active game?', nil,
- mfError + mfYesNoCancel + mfInsertInApp);
- if Result = cmYes then
- Result := SaveGame;
- end else Result := cmOK;
- CheckActiveGame := Result;
- end;
-
- procedure TChessBoard.ClearBoard;
- var
- KillCollection: TCollection;
- begin
- Surface^.Clear;
- KillCollection.Init(32, 0);
- Message(@Self, evBroadcast, cmRegisterSave, @KillCollection);
- KillCollection.Done;
- end;
-
- procedure TChessBoard.DoThink;
- begin
- if (Game <> 0) and not GameOver and
- not (ThinkState in [ssComplete, ssGameOver]) then
- Process;
- if not GameOver then Update;
- end;
-
- procedure TChessBoard.DrawSurface;
- begin
- Surface^.DrawView;
- end;
-
- procedure TChessBoard.DrawValidMoves(Empty: Boolean);
-
- procedure TestAndInvert(Test, Show: TLocation);
- var
- R: TRect;
- begin
- if Word(Test) = Word(QSquare) then
- Surface^.ValidMoves[Show.X, Show.Y] := True;
- end;
-
- var
- X : Integer;
- begin
- FillChar(Surface^.ValidMoves, SizeOf(Surface^.ValidMoves), 0);
- if not Empty then
- { Show where this piece can move to }
- begin
- X := 0;
- while (X <= High(ValidMoves)) and
- (ValidMoves[X].Change.Piece <> pEmpty) do
- begin
- with ValidMoves[X].Change do
- TestAndInvert(Source, Dest);
- Inc(X);
- end;
- X := 0;
- while (X <= High(ValidMoves)) and
- (OpponentMoves[X].Change.Piece <> pEmpty) do
- begin
- with OpponentMoves[X].Change do
- TestAndInvert(Source, Dest);
- Inc(X);
- end;
- end
- else
- { Show what pieces can move to this square }
- begin
- X := 0;
- while (X <= High(ValidMoves)) and
- (ValidMoves[X].Change.Piece <> pEmpty) do
- begin
- with ValidMoves[X].Change do
- TestAndInvert(Dest, Source);
- Inc(X);
- end;
- X := 0;
- while (X <= High(OpponentMoves)) and
- (OpponentMoves[X].Change.Piece <> pEmpty) do
- begin
- with OpponentMoves[X].Change do
- TestAndInvert(Dest, Source);
- Inc(X);
- end;
- end;
- end;
-
- function TChessBoard.GetComputerTime: Longint;
- var
- MarkTime: Longint;
- begin
- case Settings.TimeMode of
- tmGameLimit:
- begin
- MarkTime := (Settings.GameTime * 1092 -
- ChessTimers[Computer]^.GetCurrentTicks) div 44;
- if MoveHistory^.UndoPos shr 1 <= 40 then
- MarkTime := 91 + (MarkTime - 91) *
- ((80 - MoveHistory^.UndoPos shr 1) div 40);
- GetComputerTime := MarkTime;
- end;
- tmTurnLimit: GetComputerTime := Settings.TurnTime * 18;
- tmMatchUser:
- begin
- MarkTime := ChessTimers[Opponent(GetPlayer(Game))]^.GetMarkTime;
- if MarkTime > 0 then
- GetComputerTime := MarkTime
- else GetComputerTime := 5 * 18;
- end;
- tmInfinite: GetComputerTime := High(Longint);
- end;
- end;
-
- function TChessBoard.GetPalette: PPalette;
- const
- P: string[Length(CChessBoard)] = CChessBoard;
- begin
- GetPalette := @P;
- end;
-
- procedure TChessBoard.HandleEvent(var Event: TEvent);
- var
- Move: TMove;
- LastSquare: TLocation;
-
- { The chess board holds the board surface and all pieces on that surface.
- Pieces are "hidden" until asked to drag themselves. Since the views are
- hidden they don't recieve mouse events. The following procedures will
- insure that the pieces get mouse events so they can drag themselves. }
-
- procedure HandEventToPiece(P: PView);
- begin
- if Event.What and P^.EventMask <> 0 then P^.HandleEvent(Event);
- end;
-
- function ContainsMouse(P: PView): Boolean; far;
- begin
- ContainsMouse := P^.MouseInView(Event.Where);
- end;
-
- procedure EnterMove;
- var
- Dlg: PDialog;
- R: TRect;
- Control: PView;
- Change: TChange;
- P: PChessPiece;
- Result: TChessError;
- Begin
- R.Assign(0,0,39,7);
- New(Dlg, Init(R, 'Enter Move'));
-
- with Dlg^ do
- begin
- Options := Options or ofCentered;
-
- R.Assign(14, 2, 36, 3);
- Control := New(PInputLine, Init(R, 20));
- PInputLine(Control)^.SetValidator(New(PValidateMove, Init));
- PInputLine(Control)^.Validator^.Options := voTransfer;
- Insert(Control);
- R.Assign(2, 2, 14, 3);
- Insert(New(PLabel, Init(R, '~E~nter move ', Control)));
-
- R.Assign(8, 4, 18, 6);
- Insert(New(PButton, Init(R, 'O~K~', cmOK, bfDefault)));
-
- Inc(R.A.X, 14); Inc(R.B.X, 14);
- Insert(New(PButton, Init(R, 'Cancel', cmCancel, bfNormal)));
-
- SelectNext(False);
- end;
-
- if Application^.ExecView(Dlg) <> cmCancel then
- begin
- Dlg^.GetData(Change);
- Result := ValidateMove(Change);
- if Result in [ceOK, ceAmbiguousMove] then
- begin
- P := Message(@Self, evMove, cmFindPiece, Ptr(0, Word(Change.Source)));
- if P = nil then
- MessageBox(^C'Piece not located there.', nil, mfError + mfOKButton +
- mfInsertInApp)
- else
- begin
- if Result = ceAmbiguousMove then
- Change.Piece := P^.GetPromotionPiece;
- Message(@Self, evMove, cmSubmitMove, @Change);
- end;
- end
- else MessageBox(^C'Invalid move.', nil,
- mfError + mfOKButton + mfInsertInApp);
- end;
-
- Dispose(Dlg, Done);
- end;
-
- procedure ShowHint;
- var
- Move: TMove;
- begin
- GetHintMove(Game, Move);
- if VerifyMove(Game, Move.Change) = ceOK then
- begin
- Message(@Self, evMove, cmMovePiece, @Move);
- Wait(5);
- Message(@Self, evMove, cmUndoMove, @Move);
- Wait(5);
- Message(@Self, evMove, cmMovePiece, @Move);
- Wait(5);
- Message(@Self, evMove, cmUndoMove, @Move);
- Wait(5);
- end
- else MessageBox(^C'No hint available', nil, mfInformation + mfOKButton +
- mfInsertInApp);
- end;
-
- begin
- case Event.What of
- evMove:
- case Event.Command of
- cmSubmitMove:
- begin
- ChessTimers[GetPlayer(Game)]^.Stop;
- if SubmitMove(Game, TChange(Event.InfoPtr^)) = ceOK then
- begin
- if GetLastMove(Game, Move) = ceOK then
- begin
- AddToHistory(Move);
- Message(@Self, evMove, cmMovePiece, @Move);
- ResetValidMoves;
- end;
- if GameMode and gmTwoPlay <> gmTwoPlay then
- StartComputerMove
- else
- begin
- ResetCurrentPlayer;
- ChessTimers[Player]^.Mark;
- ChessTimers[Player]^.Start;
- end;
- Exit;
- end;
- end;
- end;
- evMouseDown:
- begin
-
- { The board handles all right mouse actions }
-
- if Event.Buttons = mbRightButton then
- begin
- if Settings.Hints and hoRtClickHints <> 0 then
- begin
- LastSquare := QSquare;
- repeat
- PointInSquare(Event.Where, QSquare);
- if Word(QSquare) <> Word(LastSquare) then
- begin
- DrawValidMoves(Message(@Self, evMove, cmFindPiece, Ptr(0, Word(QSquare))) = nil);
- Surface^.DrawView;
- LastSquare := QSquare;
- end;
- until not MouseEvent(Event, evMouseMove + evMouseAuto);
- Word(Qsquare) := 0;
- DrawValidMoves(False);
- Surface^.DrawView;
- end;
- ClearEvent(Event);
- Exit;
- end;
-
- { All other mouse actions go to the appropriate piece }
-
- HandEventToPiece(FirstThat(@ContainsMouse));
- end;
- end;
- inherited HandleEvent(Event);
- case Event.What of
- evCommand:
- begin
- case Event.Command of
- cmNew:
- begin
- if GameOver or (CheckActiveGame <> cmCancel) then
- begin
- DisposeGame(Game);
- if NewGame(Game) <> ceOK then
- Game := 0;
- SetupNewGameBoard;
- if Game <> 0 then StatusDialog^.Update(Game, ChessTimers,
- 0, 0, GameMode);
- end;
- end;
- cmComputerMove:
- if ThinkState in [ssComplete, ssThinkAhead] then
- StartComputerMove;
- cmRunDemo:
- if GameMode and gmDemo = 0 then
- begin
- GameMode := GameMode or gmDemo;
- if ThinkState in [ssComplete, ssThinkAhead] then
- StartComputerMove;
- end;
- cmStop:
- if (Game <> 0) and (ThinkState = ssMoveSearch) then
- begin
- ForceMove(Game);
- Computer := GetPlayer(Game);
- Player := Opponent(Computer);
- GameMode := GameMode and not gmDemo;
- end;
- cmUndo: Undo;
- cmRedo: Redo;
- cmGameOver: ShowEndGame(Event.InfoInt);
- cmSave: SaveGame;
- cmSaveAs: SaveGameAs;
- cmOpen: ReadGame;
- cmEnterMove: EnterMove;
- cmShowHint: ShowHint;
- else
- Exit
- end;
- ClearEvent(Event);
- end;
- evKeyDown:
- if ThinkState in [ssComplete, ssThinkAhead] then
- begin
- PutEvent(Event);
- EnterMove;
- ClearEvent(Event);
- end;
- end;
- end;
-
- procedure TChessBoard.InitGameBoard;
- var
- I, J: Integer;
- P: PChessPiece;
- R: TRect;
- Board: TBoard;
- Location: TLocation;
- ChessStatus: TChessStatus;
- begin
- if Game <> 0 then
- begin
- if GetBoard(Game, Board) = ceOK then
- for J := 1 to 8 do
- for I := 1 to 8 do
- if Board[I, J].Piece <> pEmpty then
- begin
- Location.X := I; Location.Y := J;
- SquareToLocal(Location, R.A, Size.Y);
- R.Assign(R.A.X, R.A.Y, R.A.X + 6, R.A.Y + 3);
- P := New(PChessPiece, Init(R, Board[I, J], Location));
- P^.Hide;
- InsertPiece(P, P^.Location);
- end;
- Player := cWhite;
- Computer := cBlack;
- GameMode := GameMode and not gmDemo;
- GameOver := False;
- ThinkState := GetSearchStatus(Game);
- Update;
- end;
- end;
-
- procedure TChessBoard.InsertPiece(Piece: PView; Location: TLocation);
- begin
- Insert(Piece);
- Surface^.Squares[Location.X, Location.Y] := Piece;
- end;
-
- procedure TChessBoard.MovePiece(Piece: PView; FromLoc, ToLoc: TLocation);
- begin
- Surface^.Squares[FromLoc.X, FromLoc.Y] := nil;
- Surface^.Squares[ToLoc.X, ToLoc.Y] := Piece;
- DrawSurface;
- end;
-
- procedure TChessBoard.Process;
- var
- OldState: TSearchStatus;
- ChessStatus: TChessStatus;
- Move: TMove;
- Event: TEvent;
- ComputerPlayer: TColor;
- I: Integer;
- begin
- OldState := ThinkState;
- if (GetPlayer(Game) = Computer) or (GameMode and gmDemo <> 0) then
- begin
- ComputerPlayer := GetPlayer(Game);
- ChessTimers[ComputerPlayer]^.Start;
- Think(Game, 4, ThinkState);
- ChessTimers[ComputerPlayer]^.Stop;
- end else Think(Game, 2, ThinkState);
- if (OldState = ssMoveSearch) and (ThinkState = ssComplete) then
- AcceptComputerMove;
- end;
-
- procedure TChessBoard.ReadGame;
- var
- S: PBufStream;
- Test: array [0..SizeOf(ChessSignature)] of Char;
- NewMoveList : PMoveList;
- FileDialog: PFileDialog;
- AGameName: PathStr;
- X: Integer;
-
- function ReplayMoves(P: PMove): Boolean; far;
- begin
- SubmitMove(Game, P^.Change);
- ReplayMoves := (X >= MoveHistory^.UndoPos);
- Inc(X);
- end;
-
- begin
- if CheckActiveGame <> cmCancel then
- begin
- FileDialog := New(PFileDialog, Init('*.CHS', 'Open a Game', '~G~ame',
- fdOpenButton, 100));
- if Application^.ExecView(FileDialog) <> cmCancel then
- begin
- FileDialog^.GetFileName(AGameName);
- S := New(PBufStream, Init(AGameName, stOpenRead, 1024));
- S^.Read(Test, SizeOf(ChessSignature));
- if S^.Status <> stOK then
- {!!} MessageBox('Error reading file', nil, mfError + mfOKButton + mfInsertInApp)
- else
- if StrLComp(ChessSignature, Test, SizeOf(ChessSignature)) <> 0 then
- {!!} MessageBox('This is not a chess game file', nil, mfError + mfOKButton + mfInsertInApp)
- else
- begin
- NewMoveList := PMoveList(S^.Get);
- if S^.Status <> stOK then
- {!!} MessageBox('Error reading file', nil, mfError + mfOKButton + mfInsertInApp)
- else
- begin
- ClearBoard;
- DisposeGame(Game);
- if NewGame(Game) <> ceOK then
- Game := 0
- else
- begin
- Dispose(MoveHistory, Done);
- MoveHistory := NewMoveList;
- X := 0;
- MoveHistory^.FirstThat(@ReplayMoves);
- if StatusDialog <> nil then
- StatusDialog^.UpdateList(MoveHistory);
- InitGameBoard;
- ResetValidMoves;
- Update;
- end;
- end;
- end;
- Dispose(S, Done);
- end;
- end;
- end;
-
- procedure TChessBoard.Redo;
- var
- Move: TMove;
- begin
- AbortSearch(Game);
- ChessTimers[Player]^.Stop;
- MoveHistory^.Redo(Move);
- if SubmitMove(Game, Move.Change) = ceOK then
- if GetLastMove(Game, Move) = ceOK then
- Message(@Self, evMove, cmMovePiece, @Move);
- if (GameMode = gmOnePlay) and (MoveHistory^.RedoAvail) and
- (Player <> GetPlayer(Game)) then
- begin
- MoveHistory^.Redo(Move);
- if SubmitMove(Game, Move.Change) = ceOK then
- if GetLastMove(Game, Move) = ceOK then
- Message(@Self, evMove, cmMovePiece, @Move);
- end
- else ResetCurrentPlayer;
- ResetValidMoves;
- ChessTimers[Player]^.Mark;
- ChessTimers[Player]^.Start;
- if StatusDialog <> nil then StatusDialog^.UpdateList(MoveHistory);
- Update;
- end;
-
- procedure TChessBoard.RemovePiece(Piece: PView; Location: TLocation);
- begin
- if Surface^.Squares[Location.X, Location.Y] = Piece then
- Surface^.Squares[Location.X, Location.Y] := nil;
- end;
-
- procedure TChessBoard.ResetCurrentPlayer;
- begin
- Player := GetPlayer(Game);
- Computer := Opponent(Player);
- end;
-
- procedure TChessBoard.ResetValidMoves;
- var
- Chg: TChange;
- PlayerColor: TColor;
- EmptyMove: TMove;
-
- procedure DoAttacks(P: PView); far;
- begin
- if TypeOf(P^) = TypeOf(TChessPiece) then
- if PChessPiece(P)^.PieceType.Color <> PlayerColor then
- if Settings.Hints and hoAttacks <> 0 then
- PChessPiece(P)^.CheckJeopardy(ValidMoves)
- else PChessPiece(P)^.CheckJeopardy(EmptyMove);
- end;
-
- procedure DoJeopardies(P : PView); far;
- begin
- if TypeOf(P^) = TypeOf(TChessPiece) then
- if (PChessPiece(P)^.PieceType.Color = PlayerColor) then
- PChessPiece(P)^.CheckJeopardy(OpponentMoves)
- else PChessPiece(P)^.CheckJeopardy(EmptyMove);
- end;
-
- begin
- Chg.Piece := pEmpty;
- Word(Chg.Source) := 0;
- Word(Chg.Dest) := 0;
- FillChar(EmptyMove, SizeOf(EmptyMove), 0);
- PlayerColor := GetPlayer(Game);
- if Settings.Hints and hoJeopardies <> 0 then
- begin
- { Switch players to see which opponent pieces attack ours }
- SetPlayer(Game, Opponent(PlayerColor));
- GetValidMoves(Game, Chg, OpponentMoves);
- SetPlayer(Game, PlayerColor);
- if Settings.Hints and hoJeopardies <> 0 then
- ForEach(@DoJeopardies);
- end
- else
- begin
- OpponentMoves[0] := EmptyMove; { Clear the jeopardy lists }
- ForEach(@DoJeopardies);
- end;
- GetValidMoves(Game, Chg, ValidMoves);
- ForEach(@DoAttacks);
- DrawSurface;
- end;
-
- function TChessBoard.SaveGame: Word;
- var
- S: PBufStream;
- begin
- SaveGame := cmCancel;
- if GameName = '' then
- begin
- SaveGame := SaveGameAs;
- Exit;
- end
- else if Game <> 0 then
- begin
- S := New(PBufStream, Init(GameName, stCreate, 1024));
- S^.Write(ChessSignature, SizeOf(ChessSignature));
- S^.Put(MoveHistory);
- if S^.Status <> stOK then
- {!!} MessageBox('Error writing file', nil, mfError + mfOKButton + mfInsertInApp);
- Dispose(S, Done);
- SaveGame := cmOK;
- end;
- end;
-
- function TChessBoard.SaveGameAs: Word;
- var
- FileDialog: PFileDialog;
- begin
- SaveGameAs := cmCancel;
- FileDialog := New(PFileDialog, Init('*.CHS', 'Save Game As',
- '~S~ave game as', fdOKButton, 101));
- if Application^.ExecView(FileDialog) <> cmCancel then
- begin
- FileDialog^.GetFileName(GameName);
- SaveGameAs := SaveGame;
- end;
- Dispose(FileDialog, Done);
- end;
-
- procedure TChessBoard.SetGameBoard(const ABoard: TBoard);
- begin
- if Game <> 0 then
- if SetBoard(Game, ABoard) <> ceOK then
- MessageBox('Error setting game board', nil,
- mfError + mfOKButton + mfInsertInApp);
- end;
-
- procedure TChessBoard.SetupNewGameBoard;
- var
- Color: TColor;
- begin
- ClearBoard;
- if MoveHistory <> nil then MoveHistory^.Purge;
- GameName := '';
- for Color := cWhite to cBlack do
- if ChessTimers[Color] <> nil then
- ChessTimers[Color]^.Clear;
- InitGameBoard;
- ResetValidMoves;
- end;
-
- procedure TChessBoard.ShowEndGame(Reason: Integer);
- type
- TWinRec = record
- Winner, Loser: PString;
- end;
- var
- ReasonStr: String;
- Winner: TColor;
- WinRec: TWinRec;
- BStr, WStr: String[5];
- begin
- Winner := Opponent(GetPlayer(Game));
- BStr := 'Black';
- WStr := 'White';
- if Winner = cBlack then
- begin
- WinRec.Winner := @BStr;
- WinREc.Loser := @WStr;
- end
- else
- begin
- WinRec.Winner := @WStr;
- WinREc.Loser := @BStr;
- end;
- case TChessStatus(Reason) of
- csCheckMate: ReasonStr := ^C'Checkmate!'#13^C'%s wins!';
- csStaleMate: ReasonStr := ^C'Stalemate!';
- csResigns: ReasonStr := ^C'%s Resigns!'#13^C'%s wins!';
- csFiftyMoveRule:
- ReasonStr := ^C'Stalemate!'#13^C'Fifty move rule.';
- csRepetitionRule:
- ReasonStr := ^C'Stalemate!'#13^C'Repitition rule.';
- end;
- MessageBox(ReasonStr, @WinRec, mfInformation + mfOKButton + mfInsertInApp);
- end;
-
- procedure TChessBoard.StartComputerMove;
- var
- ComputerTime: Longint;
- begin
- AbortSearch(Game);
- Computer := GetPlayer(Game);
- Player := Opponent(Computer);
- ComputerTime := GetComputerTime;
- ChessTimers[GetPlayer(Game)]^.Mark;
- ComputerMove(Game, ComputerTime);
- ThinkState := GetSearchStatus(Game);
- if StatusDialog <> nil then
- StatusDialog^.LastNodes := 0;
- end;
-
- procedure TChessBoard.Undo;
- var
- Move: TMove;
- R: TRect;
- P: PChessPiece;
- begin
- AbortSearch(Game);
- GameOver := False;
- ChessTimers[Player]^.Stop;
- MoveHistory^.Undo(Move);
- if RetractMove(Game, Move) = ceOK then
- Message(@Self, evMove, cmUndoMove, @Move);
- if (GameMode = gmOnePlay) and (MoveHistory^.UndoAvail) and
- (Player <> GetPlayer(Game)) then
- begin
- MoveHistory^.Undo(Move);
- if RetractMove(Game, Move) = ceOK then
- Message(@Self, evMove, cmUndoMove, @Move);
- end
- else ResetCurrentPlayer;
- ResetValidMoves;
- ChessTimers[Player]^.Mark;
- ChessTimers[Player]^.Start;
- if StatusDialog <> nil then StatusDialog^.UpdateList(MoveHistory);
- Update;
- end;
-
- procedure TChessBoard.Update;
- var
- ChessStatus: TChessStatus;
- MateInMoves: Integer;
- Event: TEvent;
- begin
- UpdateCommands;
- ChessStatus := GetChessStatus(Game, MateInMoves);
- if StatusLine <> nil then
- PChessStatusLine(StatusLine)^.SetStatus(ChessStatus, MateInMoves);
- if not (ChessStatus in [csNormal, csCheck, csMateFound]) then
- begin
- ChessTimers[cWhite]^.Stop;
- ChessTimers[cBlack]^.Stop;
- GameOver := True;
- AbortSearch(Game);
- GameMode := GameMode and not gmDemo;
- ThinkState := GetSearchStatus(Game);
- UpdateCommands;
- Event.What := evCommand;
- Event.Command := cmGameOver;
- Event.InfoInt := Integer(ChessStatus);
- PutEvent(Event);
- end;
- end;
-
- procedure TChessBoard.UpdateCommands;
- begin
- if MoveHistory <> nil then
- begin
- if StatusDialog <> nil then
- StatusDialog^.Update(Game, ChessTimers, GetNodes(Game),
- MoveHistory^.GetNumMoves, GameMode);
- SetCmdState([cmRedo], (MoveHistory^.RedoAvail) and
- (ThinkState <> ssMoveSearch));
- SetCmdState([cmUndo], (MoveHistory^.UndoAvail) and
- (ThinkState <> ssMoveSearch));
- SetCmdState([cmComputerMove, cmEnterMove, cmShowHint],
- (ThinkState <> ssMoveSearch) and not GameOver);
- SetCmdState([cmStop], (GameMode and gmDemo <> 0) or
- (ThinkState = ssMoveSearch));
- SetCmdState([cmRunDemo], (GameMode and gmDemo = 0) and not GameOver);
- end;
- end;
-
- function TChessBoard.ValidateMove(var C: TChange): TChessError;
- var
- X: Integer;
- ValidMove: TMove;
- CurMove: TMove;
- begin
- ValidateMove := ceInvalidMove;
- if (ThinkState in [ssComplete, ssThinkAhead]) then
- begin
- X := 0;
- FillChar(CurMove, SizeOf(CurMove), 0);
- while (X <= High(ValidMoves)) and
- (ValidMoves[X].Change.Piece <> pEmpty) do
- begin
- ValidMove := ValidMoves[X];
- with ValidMove do
- if ((Change.Piece = C.Piece) or (C.Piece = pEmpty)) and
- ((Word(Change.Dest) = Word(C.Dest)) or (Word(C.Dest) = 0)) and
- ((Word(Change.Source) = Word(C.Source)) or (Word(C.Source) = 0)) then
- begin
- if CurMove.Change.Piece = pEmpty then
- CurMove := ValidMove
- else
- begin
- if (ValidMove.Change.Piece = pPawn) and
- (CurMove.Change.Piece <> pPawn) then
- CurMove := ValidMove
- else if (ValidMove.Change.Piece <> pPawn) and
- (CurMove.Change.Piece = pPawn) then
- else
- begin
- C := CurMove.Change;
- ValidateMove := ceAmbiguousMove;
- Exit;
- end;
- end;
- end;
- Inc(X);
- end;
- if CurMove.Change.Piece <> pEmpty then
- begin
- C := CurMove.Change;
- ValidateMove := ceOK;
- end;
- end;
- end;
-
- function TChessBoard.Valid(Command: Word): Boolean;
- begin
- Valid := True;
- if Command = cmQuit then
- Valid := CheckActiveGame <> cmCancel;
- end;
-
- end.
-