home *** CD-ROM | disk | FTP | other *** search
- unit Board;
-
- interface
-
- {$IFDEF DLL}
- uses Views, Objects, ChessCmd, ChessDLL, MoveList, Drivers,
- StdDlg, Dos, CTimers;
- {$ELSE}
- uses Views, Objects, ChessCmd, ChessInf, MoveList, Drivers,
- StdDlg, Dos, CTimers;
- {$ENDIF}
-
- const
- ChessSignature : array [0..33] of Char = 'Borland Pascal Chess saved game'#26#0;
-
- type
- PChessSurface = ^TChessSurface;
- TChessSurface = object(TView)
- procedure Draw; virtual;
- end;
-
- { Palette layout }
- { 1 = Border }
- { 2 = Black square }
- { 3 = White sqaure }
- { 4 = Black piece }
- { 5 = White piece }
-
- PChessBoard = ^TChessBoard;
- TChessBoard = object(TGroup)
- Surface: PChessSurface;
- Game: HChess;
- Computer, Player: TColor;
- GameMode: Word;
- MoveHistory: PMoveList;
- GameName: PathStr;
- ChessTimers: array[TColor] of PChessTimer;
- constructor Init(var Bounds: TRect);
- destructor Done; virtual;
- procedure AddToHistory(const AMove: TMove);
- function CanMovePiece(Color: TColor): Boolean;
- function CheckActiveGame: Word;
- procedure ClearBoard;
- procedure DoThink;
- function GetComputerTime: Longint;
- function GetPalette: PPalette; virtual;
- procedure HandleEvent(var Event: TEvent); virtual;
- procedure InitGameBoard;
- function Opponent: TColor;
- procedure Process;
- procedure ReadGame;
- procedure Redo;
- procedure SaveGame;
- procedure SaveGameAs;
- procedure SetGameBoard(const ABoard: TBoard);
- procedure SetupNewGameBoard;
- procedure StartComputerMove;
- procedure Undo;
- function ValidateMove(C: TChange): TChessError;
- function Valid(Command: Word): Boolean; virtual;
- procedure Update;
- end;
-
- { PStreamBoard = ^TStreamBoard;
- TStreamBoard = object(TObject)
- Board: TBoard;
- Player: TColor;
- constructor Init(const ABoard: TBoard; APlayer: TColor);
- constructor Load(var S: TStream);
- procedure Store(var S: TStream);
- end;
-
- const
- RStreamBoard: TStreamRec = (
- ObjType: 5002;
- VmtLink: Ofs(TypeOf(TStreamBoard)^);
- Load: @TStreamBoard.Load;
- Store: @TStreamBoard.Store);}
-
- const
- ChessBoard: PChessBoard = nil;
-
- implementation
- uses Pieces, ChessUtl, Status, App, MsgBox, Strings, ChessSt;
-
- procedure TChessSurface.Draw;
- var
- Border, White, Black: Word;
- B: TDrawBuffer;
- I, J, K, Line: Integer;
-
- begin
- Border := GetColor($0101);
- White := GetColor($0202);
- Black := GetColor($0303);
- 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
- if (K + J) and 1 = 0 then
- MoveChar(B[2 + 6 * K], '▓', Black, 6)
- else MoveChar(B[2 + 6 * K], '░', White, 6);
- 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;
- Surface := New(PChessSurface, Init(Bounds));
- Insert(Surface);
- if NewGame(Game) <> ceOK then
- Game := 0
- else SetupNewGameBoard;
- Computer := cBlack;
- Player := cWhite;
- MoveHistory := New(PMoveList, Init(20, 10));
- for Color := cWhite to cBlack do
- ChessTimers[Color] := New(PChessTimer, Init);
- if (StatusDialog <> nil) and (Game <> 0) then
- StatusDialog^.Update(Game, ChessTimers);
- GameMode := Settings.Players;
- end;
-
- destructor TChessBoard.Done;
- begin
- if Game <> 0 then DisposeGame(Game);
- inherited Done;
- end;
-
- procedure TChessBoard.AddToHistory(const AMove: TMove);
- var
- ChessPiece: PChessPiece;
- begin
- if MoveHistory <> nil then
- MoveHistory^.AddMove(AMove);
- 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 SaveGame;
- end else Result := cmOK;
- CheckActiveGame := Result;
- end;
-
- procedure TChessBoard.ClearBoard;
- var
- KillCollection: TCollection;
- begin
- KillCollection.Init(32, 0);
- Message(@Self, evBroadcast, cmRegisterSave, @KillCollection);
- KillCollection.Done;
- end;
-
- procedure TChessBoard.DoThink;
- begin
- if (Game <> 0) and
- not (GetSearchStatus(Game) in [ssComplete, ssGameOver]) then
- Process;
- Update;
- end;
-
- function TChessBoard.GetComputerTime: Longint;
- var
- MarkTime: Longint;
- begin
- case Settings.TimeMode of
- tmGameLimit,
- tmTurnLimit: GetComputerTime := Settings.TurnTime * 18;
- tmMatchUser:
- begin
- MarkTime := ChessTimers[Opponent]^.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;
- begin
- if (Event.What = evMove) and (Event.Command = cmSubmitMove) then
- 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);
- end;
- if GameMode and gmTwoPlay = gmOnePlay then
- StartComputerMove;
- Exit;
- end;
- end;
- inherited HandleEvent(Event);
- case Event.What of
- evCommand:
- begin
- case Event.Command of
- cmNew:
- begin
- if CheckActiveGame <> cmCancel then
- begin
- DisposeGame(Game);
- if NewGame(Game) <> ceOK then
- Game := 0;
- SetupNewGameBoard;
- if Game <> 0 then StatusDialog^.Update(Game, ChessTimers);
- end;
- end;
- cmComputerMove:
- if GetSearchStatus(Game) in [ssComplete, ssThinkAhead] then
- begin
- StartComputerMove;
- ClearEvent(Event);
- Exit;
- end;
- cmRunDemo:
- if GameMode and gmDemo = 0 then
- begin
- GameMode := GameMode or gmDemo;
- if GetSearchStatus(Game) in [ssComplete, ssThinkAhead] then
- begin
- StartComputerMove;
- ClearEvent(Event);
- Exit;
- end;
- end;
- cmStop:
- if (Game <> 0) and (GetSearchStatus(Game) = ssMoveSearch) then
- begin
- ForceMove(Game);
- Computer := GetPlayer(Game);
- Player := Opponent;
- GameMode := GameMode and not gmDemo;
- end;
- cmUndo: Undo;
- cmRedo: Redo;
- cmGameOver:
- MessageBox(^C'Checkmate!', nil, mfInformation + mfOKButton + mfInsertInApp);
- cmSave: SaveGame;
- cmSaveAs: SaveGameAs;
- cmOpen: ReadGame;
- else
- Exit
- end;
- 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));
- Insert(P);
- end;
- end;
- end;
-
- function TChessBoard.Opponent: TColor;
- var
- APlayer: TColor;
- begin
- APlayer := GetPlayer(Game);
- Opponent := TColor(Byte(cBlack) - Byte(APlayer));
- end;
-
- procedure TChessBoard.Process;
- var
- Status: TSearchStatus;
- ChessStatus: TChessStatus;
- Move: TMove;
- Event: TEvent;
- ComputerPlayer: TColor;
- I: Integer;
- begin
- if (GetPlayer(Game) = Computer) or (GameMode and gmDemo <> 0) then
- begin
- ComputerPlayer := GetPlayer(Game);
- ChessTimers[ComputerPlayer]^.Start;
- Think(Game, 4, Status);
- ChessTimers[ComputerPlayer]^.Stop;
- end
- else Think(Game, 2, Status);
- case Status of
- ssComplete:
- begin
- if GetLastMove(Game, Move) = ceOK then
- begin
- AddToHistory(Move);
- Message(@Self, evMove, cmMovePiece, @Move);
- if GameMode and gmDemo <> 0 then
- StartComputerMove
- else
- begin
- ChessTimers[GetPlayer(Game)]^.Mark;
- ChessTimers[GetPlayer(Game)]^.Start;
- { ThinkAhead(Game);
- Process;}
- end;
- end;
- end;
- ssGameOver:
- begin
- ChessStatus := GetChessStatus(Game, I);
- Event.What := evCommand;
- Event.Command := cmGameOver;
- Event.InfoInt := Integer(ChessStatus);
- PutEvent(Event);
- end;
- end;
- 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);
- Message(@Self, evMove, cmMovePiece, P);
- 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;
- InitGameBoard;
- MoveHistory^.FirstThat(@ReplayMoves);
- Update;
- end;
- end;
- end;
- Dispose(S, Done);
- end;
- end;
- end;
-
- procedure TChessBoard.Redo;
- var
- Move: TMove;
- begin
- MoveHistory^.Redo(Move);
- if SubmitMove(Game, Move.Change) = ceOK then
- if GetLastMove(Game, Move) = ceOK then
- Message(@Self, evMove, cmMovePiece, @Move);
- if GameMode = gmOnePlay then
- begin
- MoveHistory^.Redo(Move);
- if SubmitMove(Game, Move.Change) = ceOK then
- if GetLastMove(Game, Move) = ceOK then
- Message(@Self, evMove, cmMovePiece, @Move);
- end;
- Update;
- end;
-
- procedure TChessBoard.SaveGame;
- var
- S: PBufStream;
- begin
- if GameName = '' then
- begin
- 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);
- end;
- end;
-
- procedure TChessBoard.SaveGameAs;
- var
- FileDialog: PFileDialog;
- begin
- FileDialog := New(PFileDialog, Init('*.CHS', 'Save Game As',
- '~S~ave game as', fdOKButton, 101));
- if Application^.ExecView(FileDialog) <> cmCancel then
- begin
- FileDialog^.GetFileName(GameName);
- 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;
- InitGameBoard;
- if MoveHistory <> nil then MoveHistory^.FreeAll;
- GameName := '';
- for Color := cWhite to cBlack do
- if ChessTimers[Color] <> nil then
- ChessTimers[Color]^.Clear;
- end;
-
- procedure TChessBoard.StartComputerMove;
- var
- ComputerTime: Longint;
- begin
- ComputerTime := GetComputerTime;
- ChessTimers[GetPlayer(Game)]^.Mark;
- ComputerMove(Game, ComputerTime);
- Process;
- end;
-
- procedure TChessBoard.Undo;
- var
- Move: TMove;
- R: TRect;
- P: PChessPiece;
- begin
- MoveHistory^.Undo(Move);
- if RetractMove(Game, Move) = ceOK then
- Message(@Self, evMove, cmUndoMove, @Move);
- if GameMode = gmOnePlay then
- begin
- MoveHistory^.Undo(Move);
- if RetractMove(Game, Move) = ceOK then
- Message(@Self, evMove, cmUndoMove, @Move);
- end;
- Update;
- end;
-
- procedure TChessBoard.Update;
- var
- ChessStatus: TChessStatus;
- MateInMoves: Integer;
- begin
- if StatusDialog <> nil then StatusDialog^.Update(Game, ChessTimers);
- if MoveHistory <> nil then
- begin
- SetCmdState([cmRedo], (MoveHistory^.RedoAvail) and
- (GameMode and gmDemo = 0) and ((GetPlayer(Game) = Player) or
- (GameMode = gmOnePlay)));
- SetCmdState([cmUndo], (MoveHistory^.UndoAvail) and
- (GameMode and gmDemo = 0) and ((GetPlayer(Game) = Player) or
- (GameMode = gmOnePlay)));
- SetCmdState([cmComputerMove, cmEnterMove, cmShowHint],
- (GameMode and gmDemo = 0) and ((GetPlayer(Game) = Player) or
- (GameMode = gmOnePlay)));
- SetCmdState([cmStop], (GameMode and gmDemo <> 0) or
- (GetSearchStatus(Game) = ssMoveSearch));
- end;
- if StatusLine <> nil then
- begin
- ChessStatus := GetChessStatus(Game, MateInMoves);
- PChessStatusLine(StatusLine)^.SetStatus(ChessStatus, MateInMoves);
- end;
- end;
-
- function TChessBoard.ValidateMove(C: TChange): TChessError;
- begin
- if (GetSearchStatus(Game) in [ssComplete, ssThinkAhead]) then
- ValidateMove := VerifyMove(Game, C)
- else
- ValidateMove := ceInvalidMove;
- end;
-
- function TChessBoard.Valid(Command: Word): Boolean;
- begin
- Valid := True;
- if Command = cmQuit then
- Valid := CheckActiveGame <> cmCancel;
- end;
-
- {constructor TStreamBoard.Init(const ABoard: TBoard; APlayer: TColor);
- begin
- inherited Init;
- Board := ABoard;
- Player := APlayer;
- end;
-
- constructor TStreamBoard.Load(var S: TStream);
- begin
- inherited Init;
- S.Read(Board, SizeOf(Board) + SizeOf(Player));
- end;
-
- procedure TStreamBoard.Store(var S: TStream);
- begin
- S.Write(Board, SizeOf(Board) + SizeOf(Player));
- end;}
-
- end.
-