home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Pascal / BPASCAL.700 / D12 / CHESSTV.ZIP / BOARD.PAS next >
Encoding:
Pascal/Delphi Source File  |  1992-10-01  |  15.7 KB  |  601 lines

  1. unit Board;
  2.  
  3. interface
  4.  
  5. {$IFDEF DLL}
  6. uses Views, Objects, ChessCmd, ChessDLL, MoveList, Drivers,
  7.   StdDlg, Dos, CTimers;
  8. {$ELSE}
  9. uses Views, Objects, ChessCmd, ChessInf, MoveList, Drivers,
  10.   StdDlg, Dos, CTimers;
  11. {$ENDIF}
  12.  
  13. const
  14.   ChessSignature : array [0..33] of Char = 'Borland Pascal Chess saved game'#26#0;
  15.  
  16. type
  17.   PChessSurface = ^TChessSurface;
  18.   TChessSurface = object(TView)
  19.     procedure Draw; virtual;
  20.   end;
  21.  
  22.   { Palette layout }
  23.   { 1 = Border }
  24.   { 2 = Black square }
  25.   { 3 = White sqaure }
  26.   { 4 = Black piece }
  27.   { 5 = White piece }
  28.  
  29.   PChessBoard = ^TChessBoard;
  30.   TChessBoard = object(TGroup)
  31.     Surface: PChessSurface;
  32.     Game: HChess;
  33.     Computer, Player: TColor;
  34.     GameMode: Word;
  35.     MoveHistory: PMoveList;
  36.     GameName: PathStr;
  37.     ChessTimers: array[TColor] of PChessTimer;
  38.     constructor Init(var Bounds: TRect);
  39.     destructor Done; virtual;
  40.     procedure AddToHistory(const AMove: TMove);
  41.     function CanMovePiece(Color: TColor): Boolean;
  42.     function CheckActiveGame: Word;
  43.     procedure ClearBoard;
  44.     procedure DoThink;
  45.     function GetComputerTime: Longint;
  46.     function GetPalette: PPalette; virtual;
  47.     procedure HandleEvent(var Event: TEvent); virtual;
  48.     procedure InitGameBoard;
  49.     function Opponent: TColor;
  50.     procedure Process;
  51.     procedure ReadGame;
  52.     procedure Redo;
  53.     procedure SaveGame;
  54.     procedure SaveGameAs;
  55.     procedure SetGameBoard(const ABoard: TBoard);
  56.     procedure SetupNewGameBoard;
  57.     procedure StartComputerMove;
  58.     procedure Undo;
  59.     function ValidateMove(C: TChange): TChessError;
  60.     function Valid(Command: Word): Boolean; virtual;
  61.     procedure Update;
  62.   end;
  63.  
  64. {  PStreamBoard = ^TStreamBoard;
  65.   TStreamBoard = object(TObject)
  66.     Board: TBoard;
  67.     Player: TColor;
  68.     constructor Init(const ABoard: TBoard; APlayer: TColor);
  69.     constructor Load(var S: TStream);
  70.     procedure Store(var S: TStream);
  71.   end;
  72.  
  73. const
  74.   RStreamBoard: TStreamRec = (
  75.     ObjType: 5002;
  76.     VmtLink: Ofs(TypeOf(TStreamBoard)^);
  77.     Load:    @TStreamBoard.Load;
  78.     Store:   @TStreamBoard.Store);}
  79.  
  80. const
  81.   ChessBoard: PChessBoard = nil;
  82.  
  83. implementation
  84. uses Pieces, ChessUtl, Status, App, MsgBox, Strings, ChessSt;
  85.  
  86. procedure TChessSurface.Draw;
  87. var
  88.   Border, White, Black: Word;
  89.   B: TDrawBuffer;
  90.   I, J, K, Line: Integer;
  91.  
  92. begin
  93.   Border := GetColor($0101);
  94.   White := GetColor($0202);
  95.   Black := GetColor($0303);
  96.   Line := 0;
  97.   for J := 7 downto 0 do
  98.   begin
  99.     if J = 7 then
  100.     begin
  101.       MoveChar(B, ' ', Border, 2);
  102.       for I := 0 to 7 do
  103.       begin
  104.         MoveChar(B[2 + 6 * I], ' ', Border, 3);
  105.         MoveChar(B[5 + 6 * I], Chr($41 + I), Border, 1);
  106.         MoveChar(B[6 + 6 * I], ' ', Border, 2);
  107.       end;
  108.       MoveChar(B[Size.X - 2], ' ', Border, 2);
  109.       WriteBuf(0, Line, Size.X, 1, B);
  110.       Inc(Line);
  111.     end;
  112.     for I := 0 to 2 do
  113.     begin
  114.       MoveChar(B, ' ', Border, 2);
  115.       if I = 1 then
  116.         MoveChar(B, Chr($31 + J), Border, 1);
  117.       for K := 0 to 7 do
  118.         if (K + J) and 1 = 0 then
  119.           MoveChar(B[2 + 6 * K], '▓', Black, 6)
  120.         else MoveChar(B[2 + 6 * K], '░', White, 6);
  121.       MoveChar(B[Size.X - 2], ' ', Border, 2);
  122.       WriteBuf(0, Line, Size.X, 1, B);
  123.       Inc(Line);
  124.     end;
  125.   end;
  126. end;
  127.  
  128. constructor TChessBoard.Init(var Bounds: TRect);
  129. var
  130.   Color: TColor;
  131. begin
  132.   inherited Init(Bounds);
  133.   EventMask := EventMask or evMove;
  134.   Surface := New(PChessSurface, Init(Bounds));
  135.   Insert(Surface);
  136.   if NewGame(Game) <> ceOK then
  137.     Game := 0
  138.   else SetupNewGameBoard;
  139.   Computer := cBlack;
  140.   Player := cWhite;
  141.   MoveHistory := New(PMoveList, Init(20, 10));
  142.   for Color := cWhite to cBlack do
  143.     ChessTimers[Color] := New(PChessTimer, Init);
  144.   if (StatusDialog <> nil) and (Game <> 0) then
  145.     StatusDialog^.Update(Game, ChessTimers);
  146.   GameMode := Settings.Players;
  147. end;
  148.  
  149. destructor TChessBoard.Done;
  150. begin
  151.   if Game <> 0 then DisposeGame(Game);
  152.   inherited Done;
  153. end;
  154.  
  155. procedure TChessBoard.AddToHistory(const AMove: TMove);
  156. var
  157.   ChessPiece: PChessPiece;
  158. begin
  159.   if MoveHistory <> nil then
  160.     MoveHistory^.AddMove(AMove);
  161. end;
  162.  
  163. function TChessBoard.CanMovePiece(Color: TColor): Boolean;
  164. begin
  165.   CanMovePiece := False;
  166.   if (Game <> 0) and (GetSearchStatus(Game) in [ssComplete, ssThinkAhead]) and
  167.     (Color = GetPlayer(Game)) then CanMovePiece := True;
  168. end;
  169.  
  170. function TChessBoard.CheckActiveGame: Word;
  171. var
  172.   Result: Word;
  173. begin
  174.   if ((MoveHistory <> nil) and (MoveHistory^.Count <> 0)) then
  175.   begin
  176.     Result := MessageBox('Save currently active game?', nil,
  177.       mfError + mfYesNoCancel + mfInsertInApp);
  178.     if Result = cmYes then SaveGame;
  179.   end else Result := cmOK;
  180.   CheckActiveGame := Result;
  181. end;
  182.  
  183. procedure TChessBoard.ClearBoard;
  184. var
  185.   KillCollection: TCollection;
  186. begin
  187.   KillCollection.Init(32, 0);
  188.   Message(@Self, evBroadcast, cmRegisterSave, @KillCollection);
  189.   KillCollection.Done;
  190. end;
  191.  
  192. procedure TChessBoard.DoThink;
  193. begin
  194.   if (Game <> 0) and
  195.     not (GetSearchStatus(Game) in [ssComplete, ssGameOver]) then
  196.     Process;
  197.   Update;
  198. end;
  199.  
  200. function TChessBoard.GetComputerTime: Longint;
  201. var
  202.   MarkTime: Longint;
  203. begin
  204.   case Settings.TimeMode of
  205.     tmGameLimit,
  206.     tmTurnLimit: GetComputerTime := Settings.TurnTime * 18;
  207.     tmMatchUser:
  208.       begin
  209.         MarkTime := ChessTimers[Opponent]^.GetMarkTime;
  210.         if MarkTime > 0 then
  211.           GetComputerTime := MarkTime
  212.         else GetComputerTime := 5 * 18;
  213.       end;
  214.     tmInfinite:  GetComputerTime := High(Longint);
  215.   end;
  216. end;
  217.  
  218. function TChessBoard.GetPalette: PPalette;
  219. const
  220.   P: string[Length(CChessBoard)] = CChessBoard;
  221. begin
  222.   GetPalette := @P;
  223. end;
  224.  
  225. procedure TChessBoard.HandleEvent(var Event: TEvent);
  226. var
  227.   Move: TMove;
  228. begin
  229.   if (Event.What = evMove) and (Event.Command = cmSubmitMove) then
  230.   begin
  231.     ChessTimers[GetPlayer(Game)]^.Stop;
  232.     if SubmitMove(Game, TChange(Event.InfoPtr^)) = ceOK then
  233.     begin
  234.       if GetLastMove(Game, Move) = ceOK then
  235.       begin
  236.         AddToHistory(Move);
  237.         Message(@Self, evMove, cmMovePiece, @Move);
  238.       end;
  239.       if GameMode and gmTwoPlay = gmOnePlay then
  240.         StartComputerMove;
  241.       Exit;
  242.     end;
  243.   end;
  244.   inherited HandleEvent(Event);
  245.   case Event.What of
  246.     evCommand:
  247.       begin
  248.         case Event.Command of
  249.           cmNew:
  250.             begin
  251.               if CheckActiveGame <> cmCancel then
  252.               begin
  253.                 DisposeGame(Game);
  254.                 if NewGame(Game) <> ceOK then
  255.                   Game := 0;
  256.                 SetupNewGameBoard;
  257.                 if Game <> 0 then StatusDialog^.Update(Game, ChessTimers);
  258.               end;
  259.             end;
  260.           cmComputerMove:
  261.             if GetSearchStatus(Game) in [ssComplete, ssThinkAhead] then
  262.             begin
  263.               StartComputerMove;
  264.               ClearEvent(Event);
  265.               Exit;
  266.             end;
  267.           cmRunDemo:
  268.             if GameMode and gmDemo = 0 then
  269.             begin
  270.               GameMode := GameMode or gmDemo;
  271.               if GetSearchStatus(Game) in [ssComplete, ssThinkAhead] then
  272.               begin
  273.                 StartComputerMove;
  274.                 ClearEvent(Event);
  275.                 Exit;
  276.               end;
  277.             end;
  278.           cmStop:
  279.             if (Game <> 0) and (GetSearchStatus(Game) = ssMoveSearch) then
  280.             begin
  281.               ForceMove(Game);
  282.               Computer := GetPlayer(Game);
  283.               Player := Opponent;
  284.               GameMode := GameMode and not gmDemo;
  285.             end;
  286.           cmUndo: Undo;
  287.           cmRedo: Redo;
  288.           cmGameOver:
  289.             MessageBox(^C'Checkmate!', nil, mfInformation + mfOKButton + mfInsertInApp);
  290.           cmSave: SaveGame;
  291.           cmSaveAs: SaveGameAs;
  292.           cmOpen: ReadGame;
  293.         else
  294.           Exit
  295.         end;
  296.         ClearEvent(Event);
  297.       end;
  298.   end;
  299. end;
  300.  
  301. procedure TChessBoard.InitGameBoard;
  302. var
  303.   I, J: Integer;
  304.   P: PChessPiece;
  305.   R: TRect;
  306.   Board: TBoard;
  307.   Location: TLocation;
  308.   ChessStatus: TChessStatus;
  309. begin
  310.   if Game <> 0 then
  311.   begin
  312.     if GetBoard(Game, Board) = ceOK then
  313.       for J := 1 to 8 do
  314.         for I := 1 to 8 do
  315.           if Board[I, J].Piece <> pEmpty then
  316.           begin
  317.             Location.X := I; Location.Y := J;
  318.             SquareToLocal(Location, R.A, Size.Y);
  319.             R.Assign(R.A.X, R.A.Y, R.A.X + 6, R.A.Y + 3);
  320.             P := New(PChessPiece, Init(R, Board[I, J], Location));
  321.             Insert(P);
  322.           end;
  323.   end;
  324. end;
  325.  
  326. function TChessBoard.Opponent: TColor;
  327. var
  328.   APlayer: TColor;
  329. begin
  330.   APlayer := GetPlayer(Game);
  331.   Opponent := TColor(Byte(cBlack) - Byte(APlayer));
  332. end;
  333.  
  334. procedure TChessBoard.Process;
  335. var
  336.   Status: TSearchStatus;
  337.   ChessStatus: TChessStatus;
  338.   Move: TMove;
  339.   Event: TEvent;
  340.   ComputerPlayer: TColor;
  341.   I: Integer;
  342. begin
  343.   if (GetPlayer(Game) = Computer) or (GameMode and gmDemo <> 0) then
  344.   begin
  345.     ComputerPlayer := GetPlayer(Game);
  346.     ChessTimers[ComputerPlayer]^.Start;
  347.     Think(Game, 4, Status);
  348.     ChessTimers[ComputerPlayer]^.Stop;
  349.   end
  350.   else Think(Game, 2, Status);
  351.   case Status of
  352.     ssComplete:
  353.       begin
  354.         if GetLastMove(Game, Move) = ceOK then
  355.         begin
  356.           AddToHistory(Move);
  357.           Message(@Self, evMove, cmMovePiece, @Move);
  358.           if GameMode and gmDemo <> 0 then
  359.             StartComputerMove
  360.           else
  361.           begin
  362.             ChessTimers[GetPlayer(Game)]^.Mark;
  363.             ChessTimers[GetPlayer(Game)]^.Start;
  364. {            ThinkAhead(Game);
  365.             Process;}
  366.           end;
  367.         end;
  368.       end;
  369.     ssGameOver:
  370.       begin
  371.         ChessStatus := GetChessStatus(Game, I);
  372.         Event.What := evCommand;
  373.         Event.Command := cmGameOver;
  374.         Event.InfoInt := Integer(ChessStatus);
  375.         PutEvent(Event);
  376.       end;
  377.   end;
  378. end;
  379.  
  380. procedure TChessBoard.ReadGame;
  381. var
  382.   S: PBufStream;
  383.   Test: array [0..SizeOf(ChessSignature)] of Char;
  384.   NewMoveList : PMoveList;
  385.   FileDialog: PFileDialog;
  386.   AGameName: PathStr;
  387.   X: Integer;
  388.  
  389.   function ReplayMoves(P: PMove): Boolean; far;
  390.   begin
  391.     SubmitMove(Game, P^.Change);
  392.     ReplayMoves := (X >= MoveHistory^.UndoPos);
  393.     Message(@Self, evMove, cmMovePiece, P);
  394.     Inc(X);
  395.   end;
  396.  
  397. begin
  398.   if CheckActiveGame <> cmCancel then
  399.   begin
  400.     FileDialog := New(PFileDialog, Init('*.CHS', 'Open a Game', '~G~ame',
  401.       fdOpenButton, 100));
  402.     if Application^.ExecView(FileDialog) <> cmCancel then
  403.     begin
  404.       FileDialog^.GetFileName(AGameName);
  405.       S := New(PBufStream, Init(AGameName, stOpenRead, 1024));
  406.       S^.Read(Test, SizeOf(ChessSignature));
  407.       if S^.Status <> stOK then
  408.         {!!} MessageBox('Error reading file', nil, mfError + mfOKButton + mfInsertInApp)
  409.       else
  410.       if StrLComp(ChessSignature, Test, SizeOf(ChessSignature)) <> 0 then
  411.         {!!} MessageBox('This is not a chess game file', nil, mfError + mfOKButton + mfInsertInApp)
  412.       else
  413.       begin
  414.         NewMoveList := PMoveList(S^.Get);
  415.         if S^.Status <> stOK then
  416.           {!!} MessageBox('Error reading file', nil, mfError + mfOKButton + mfInsertInApp)
  417.         else
  418.         begin
  419.           ClearBoard;
  420.           DisposeGame(Game);
  421.           if NewGame(Game) <> ceOK then
  422.             Game := 0
  423.           else
  424.           begin
  425.             Dispose(MoveHistory, Done);
  426.             MoveHistory := NewMoveList;
  427.             X := 0;
  428.             InitGameBoard;
  429.             MoveHistory^.FirstThat(@ReplayMoves);
  430.             Update;
  431.           end;
  432.         end;
  433.       end;
  434.       Dispose(S, Done);
  435.     end;
  436.   end;
  437. end;
  438.  
  439. procedure TChessBoard.Redo;
  440. var
  441.   Move: TMove;
  442. begin
  443.   MoveHistory^.Redo(Move);
  444.   if SubmitMove(Game, Move.Change) = ceOK then
  445.     if GetLastMove(Game, Move) = ceOK then
  446.       Message(@Self, evMove, cmMovePiece, @Move);
  447.   if GameMode = gmOnePlay then
  448.   begin
  449.     MoveHistory^.Redo(Move);
  450.     if SubmitMove(Game, Move.Change) = ceOK then
  451.       if GetLastMove(Game, Move) = ceOK then
  452.         Message(@Self, evMove, cmMovePiece, @Move);
  453.   end;
  454.   Update;
  455. end;
  456.  
  457. procedure TChessBoard.SaveGame;
  458. var
  459.   S: PBufStream;
  460. begin
  461.   if GameName = '' then
  462.   begin
  463.     SaveGameAs;
  464.     Exit;
  465.   end
  466.   else if Game <> 0 then
  467.   begin
  468.     S := New(PBufStream, Init(GameName, stCreate, 1024));
  469.     S^.Write(ChessSignature, SizeOf(ChessSignature));
  470.     S^.Put(MoveHistory);
  471.     if S^.Status <> stOK then
  472.       {!!} MessageBox('Error writing file', nil, mfError + mfOKButton + mfInsertInApp);
  473.     Dispose(S, Done);
  474.   end;
  475. end;
  476.  
  477. procedure TChessBoard.SaveGameAs;
  478. var
  479.   FileDialog: PFileDialog;
  480. begin
  481.   FileDialog := New(PFileDialog, Init('*.CHS', 'Save Game As',
  482.     '~S~ave game as', fdOKButton, 101));
  483.   if Application^.ExecView(FileDialog) <> cmCancel then
  484.   begin
  485.     FileDialog^.GetFileName(GameName);
  486.     SaveGame;
  487.   end;
  488.   Dispose(FileDialog, Done);
  489. end;
  490.  
  491. procedure TChessBoard.SetGameBoard(const ABoard: TBoard);
  492. begin
  493.   if Game <> 0 then
  494.     if SetBoard(Game, ABoard) <> ceOK then
  495.       MessageBox('Error setting game board', nil,
  496.         mfError + mfOKButton + mfInsertInApp);
  497. end;
  498.  
  499. procedure TChessBoard.SetupNewGameBoard;
  500. var
  501.   Color: TColor;
  502. begin
  503.   ClearBoard;
  504.   InitGameBoard;
  505.   if MoveHistory <> nil then MoveHistory^.FreeAll;
  506.   GameName := '';
  507.   for Color := cWhite to cBlack do
  508.     if ChessTimers[Color] <> nil then
  509.       ChessTimers[Color]^.Clear;
  510. end;
  511.  
  512. procedure TChessBoard.StartComputerMove;
  513. var
  514.   ComputerTime: Longint;
  515. begin
  516.   ComputerTime := GetComputerTime;
  517.   ChessTimers[GetPlayer(Game)]^.Mark;
  518.   ComputerMove(Game, ComputerTime);
  519.   Process;
  520. end;
  521.  
  522. procedure TChessBoard.Undo;
  523. var
  524.   Move: TMove;
  525.   R: TRect;
  526.   P: PChessPiece;
  527. begin
  528.   MoveHistory^.Undo(Move);
  529.   if RetractMove(Game, Move) = ceOK then
  530.     Message(@Self, evMove, cmUndoMove, @Move);
  531.   if GameMode = gmOnePlay then
  532.   begin
  533.     MoveHistory^.Undo(Move);
  534.     if RetractMove(Game, Move) = ceOK then
  535.       Message(@Self, evMove, cmUndoMove, @Move);
  536.   end;
  537.   Update;
  538. end;
  539.  
  540. procedure TChessBoard.Update;
  541. var
  542.   ChessStatus: TChessStatus;
  543.   MateInMoves: Integer;
  544. begin
  545.   if StatusDialog <> nil then StatusDialog^.Update(Game, ChessTimers);
  546.   if MoveHistory <> nil then
  547.   begin
  548.     SetCmdState([cmRedo], (MoveHistory^.RedoAvail) and
  549.       (GameMode and gmDemo = 0) and ((GetPlayer(Game) = Player) or
  550.       (GameMode = gmOnePlay)));
  551.     SetCmdState([cmUndo], (MoveHistory^.UndoAvail) and
  552.       (GameMode and gmDemo = 0) and ((GetPlayer(Game) = Player) or
  553.       (GameMode = gmOnePlay)));
  554.     SetCmdState([cmComputerMove, cmEnterMove, cmShowHint],
  555.       (GameMode and gmDemo = 0) and ((GetPlayer(Game) = Player) or
  556.       (GameMode = gmOnePlay)));
  557.     SetCmdState([cmStop], (GameMode and gmDemo <> 0) or
  558.       (GetSearchStatus(Game) = ssMoveSearch));
  559.   end;
  560.   if StatusLine <> nil then
  561.   begin
  562.     ChessStatus := GetChessStatus(Game, MateInMoves);
  563.     PChessStatusLine(StatusLine)^.SetStatus(ChessStatus, MateInMoves);
  564.   end;
  565. end;
  566.  
  567. function TChessBoard.ValidateMove(C: TChange): TChessError;
  568. begin
  569.   if (GetSearchStatus(Game) in [ssComplete, ssThinkAhead]) then
  570.     ValidateMove := VerifyMove(Game, C)
  571.   else
  572.     ValidateMove := ceInvalidMove;
  573. end;
  574.  
  575. function TChessBoard.Valid(Command: Word): Boolean;
  576. begin
  577.   Valid := True;
  578.   if Command = cmQuit then
  579.     Valid := CheckActiveGame <> cmCancel;
  580. end;
  581.  
  582. {constructor TStreamBoard.Init(const ABoard: TBoard; APlayer: TColor);
  583. begin
  584.   inherited Init;
  585.   Board := ABoard;
  586.   Player := APlayer;
  587. end;
  588.  
  589. constructor TStreamBoard.Load(var S: TStream);
  590. begin
  591.   inherited Init;
  592.   S.Read(Board, SizeOf(Board) + SizeOf(Player));
  593. end;
  594.  
  595. procedure TStreamBoard.Store(var S: TStream);
  596. begin
  597.   S.Write(Board, SizeOf(Board) + SizeOf(Player));
  598. end;}
  599.  
  600. end.
  601.