home *** CD-ROM | disk | FTP | other *** search
- {************************************************}
- { }
- { ObjectWindows Chess Demo }
- { Copyright (c) 1992 by Borland International }
- { }
- {************************************************}
-
- { The chess programs consist of 3 binary files:
-
- OWLCHESS.EXE - Windows chess program (uses ObjectWindows)
- TVCHESS.EXE - DOS text mode chess program (uses Turbo Vision)
- CHESS.DLL - Chess analysis engine dynamic link library (DLL)
- that is shared by both TVCHESS.EXE and OWLCHESS.EXE
-
- TVCHESS is a DOS protected mode application (DPMI). To build
- it, set Compile|Target to Protected from inside the IDE or type the
- following command-line at a DOS prompt:
-
- bpc /m /cp tvchess
-
- (Note you can also produce a real mode version of TVCHESS which
- will statically link in the CHESS DLL units.)
-
- OWLCHESS is a Windows application. To build it, set Compile|Target to
- Windows from inside the IDE or type the following command-line at a
- DOS prompt:
-
- bpc /m /cw owlchess
-
- CHESS.DLL is a Windows format DLL and comes already built. To rebuild
- it, set Compile|Target to Windows from inside the IDE or type the
- following command-line at a DOS prompt:
-
- bpc /m /cw chess
-
- }
-
- program OWLChess;
-
- {$C Moveable, Preload, Permanent }
-
- uses WinProcs, WinTypes, Objects, OWindows, ODialogs, BWCC, OWUtils,
- Chessdll, OWBoard, MoveList, OWChDlgs, OWConst, OWLCmDlg, Strings,
- CommDlg, WinDos, CTimers, OWAbout;
-
- {$R OWLChess}
-
- const
- ChessSignature : array [0..33] of Char = 'Borland Pascal Chess saved game'#26#0;
- ChessFileFilter = 'Chess games'#0'*.chs'#0#0;
- csEndGame = [csCheckMate, csStaleMate, csResigns,
- csFiftyMoveRule, csRepetitionRule];
-
- type
-
- TGameMode = (mSinglePlayer, mTwoPlayer, mAutoPlay, mStartup);
-
- PChessApp = ^TChessApp;
- TChessApp = object(TXtendedApp)
- procedure InitInstance; virtual;
- procedure InitMainWindow; virtual;
- function IdleAction: Boolean; virtual;
- end;
-
- PChessWindow = ^TChessWindow;
- TChessWindow = object(TWindow)
- Game: HChess;
- Board: TChessBoard;
- BoardFrame: PBoardFrame;
- ThinkState: TSearchStatus;
- Mode : TGameMode;
- Player: TColor;
- MoveHistory: PMoveList;
- InfoPane: PChessInfoWindow;
- ThinkMenu: HMenu;
- GameFileName: array [0..fsPathName] of Char;
- Timer: array [cWhite..cBlack] of PChessTimer;
- ActiveTimer: PChessTimer; { = nil means game is suspended }
- GameOver: Boolean;
- Paused: Boolean;
- constructor Init(AParent: PWindowsObject; ATitle: PChar);
- destructor Done; virtual;
- procedure SetupWindow; virtual; { first place HWindow is valid }
- procedure WMDestroy(var Msg: TMessage); { last place HWindow is valid }
- virtual wm_First + wm_Destroy;
- function GetClassName: PChar; virtual;
- procedure GetWindowClass(var WC: TWndClass); virtual;
- procedure Sleep;
- procedure Revive;
- procedure RestartGame;
- function CanClose: Boolean; virtual;
- function IdleAction: Boolean;
- function ShowMsg(const Ctx, MsgCode: Integer; Override: PChar): Integer;
- function GameTimeExpired: Boolean;
- procedure LockDownGameOver;
- procedure UnlockGameOver;
- procedure ReportGameState;
- function SaveGame(FileName: PChar): Boolean;
- function LoadGame(FileName: PChar): Boolean;
- procedure RecordMove(const Move: TMove);
- procedure StartComputerMove;
- procedure AcceptComputerMove;
- procedure AMSubmitMove(var Msg: TMessage);
- virtual am_SubmitMove;
- procedure AMChoosePawnPromote(var Msg: TMessage);
- virtual am_ChoosePawnPromote;
- procedure CMNewGame(var Msg: TMessage);
- virtual cm_First + cm_NewGame;
- procedure CMLoadGame(var Msg: TMessage);
- virtual cm_First + cm_LoadGame;
- procedure CMSaveGame(var Msg: TMessage);
- virtual cm_First + cm_SaveGame;
- procedure CMSaveAs(var Msg: TMessage);
- virtual cm_First + cm_SaveAs;
- procedure CMAutoPlay(var Msg: TMessage);
- virtual cm_First + cm_AutoPlay;
- procedure CMPauseGame(var Msg: TMessage);
- virtual cm_First + cm_PauseGame;
- procedure CMUndoMove(var Msg: TMessage);
- virtual cm_First + cm_UndoMove;
- procedure CMRedoMove(var Msg: TMessage);
- virtual cm_First + cm_RedoMove;
- procedure CMComputerMove(var Msg: TMessage);
- virtual cm_First + cm_ComputerMove;
- procedure CMEnterMove(var Msg: TMessage);
- virtual cm_First + cm_EnterMove;
- procedure CMSettings(var Msg: TMessage);
- virtual cm_First + cm_Settings;
- procedure CMAbout(var Msg: TMessage);
- virtual cm_First + cm_About;
- procedure CMStopThinking(var Msg: TMessage);
- virtual cm_First + cm_StopThinking;
- procedure WMTimer(var Msg: TMessage);
- virtual wm_First + wm_Timer;
- procedure WMSetCursor(var Msg: TMessage);
- virtual wm_First + wm_SetCursor;
- procedure WMActivate(var Msg: TMessage);
- virtual wm_First + wm_Activate;
- end;
-
- constructor TChessWindow.Init(AParent: PWindowsObject; ATitle: PChar);
- begin
- inherited Init(AParent, ATitle);
- Attr.X := 0;
- Attr.Y := 50;
- Attr.W := 350;
- Attr.H := 350;
- Attr.Style := ws_Overlapped or ws_Caption or ws_Border or
- ws_SysMenu or ws_MinimizeBox;
- Attr.Menu := LoadMenu(HInstance, PChar(idMainMenu));
- ThinkMenu := LoadMenu(HInstance, PChar(idThinkMenu));
- LoadINISettings;
- GameFileName[0] := #0;
- Mode := mStartup;
- Player := cWhite;
- Status := Context(cxChessError, Ord(NewGame(Game)));
- if Status <> 0 then Exit;
- ThinkState := GetSearchStatus(Game);
- Timer[cWhite] := New(PChessTimer, Init);
- Timer[cBlack] := New(PChessTimer, Init);
- ActiveTimer := nil;
- GameOver := False;
- Paused := False;
- MoveHistory := New(PMoveList, Init(20, 10));
- Board.Init(@Self, Game);
- InfoPane := New(PChessInfoWindow, Init(@Self, PChar(dlgInfoPane)));
- BoardFrame := New(PBoardFrame, Init(@Self, @Board));
- end;
-
- destructor TChessWindow.Done;
- begin
- Dispose(MoveHistory, Done);
- Dispose(Timer[cWhite], Done);
- Dispose(Timer[cBlack], Done);
- SaveINISettings;
- DisposeGame(Game);
- DestroyMenu(ThinkMenu);
- RemoveChild(@Board);
- Board.Done;
- inherited Done;
- end;
-
- procedure TChessWindow.SetupWindow;
- var
- W, WX, WY, H: Word;
- WR, CR, IR: TRect;
- XSpacer, YSpacer: Integer;
- DC: HDC;
- begin
- inherited SetupWindow;
- W := BoardFrame^.IdealWidth;
- H := W;
- GetWindowRect(HWindow, WR);
- GetClientRect(HWindow, CR);
- GetClientRect(InfoPane^.HWindow, IR);
- WX := (WR.Right - WR.Left) - CR.Right;
- WY := (WR.Bottom - WR.Top) - CR.Bottom;
- if H < IR.Bottom then
- H := IR.Bottom;
- DC := GetDC(HWindow);
- XSpacer := GetDeviceCaps(DC, LogPixelsX) div 8;
- YSpacer := GetDeviceCaps(DC, LogPixelsY) div 8;
- ReleaseDC(HWindow, DC);
- SetWindowPos(HWindow, 0, 0, 0, W + 3*XSpacer + IR.Right + WX,
- H + 2*YSpacer + WY, swp_NoZOrder or swp_NoMove);
- SetWindowPos(BoardFrame^.HWindow, 0, XSpacer, YSpacer, W, W,swp_NoZOrder);
- SetWindowPos(InfoPane^.HWindow, 0, W + 2*XSpacer, YSpacer, 0, 0,
- swp_NoZOrder or swp_NoSize);
- ShowWindow(BoardFrame^.HWindow, sw_ShowNormal);
- ShowWindow(Board.HWindow, sw_ShowNormal);
- SetTimer(HWindow, 1, ChessSettings.RefreshRate, nil);
- end;
-
- procedure TChessWindow.WMDestroy(var Msg: TMessage);
- begin
- KillTimer(HWindow, 1);
- inherited WMDestroy(Msg);
- end;
-
- function TChessWindow.GetClassName: PChar;
- begin
- GetClassName := 'TPWOWLChess';
- end;
-
- procedure TChessWindow.GetWindowClass(var WC: TWndClass);
- var
- LB: TLogBrush;
- begin
- inherited GetWindowClass(WC);
- WC.Style := cs_ByteAlignWindow;
- WC.hCursor := 0;
- { Duplicate the BWCCPattern brush. hbrBackground brush will be destroyed
- when our window is closed. If we didn't duplicate this brush, but just
- used BWCCGetPattern's result directly, BWCC could be left without
- a valid background brush when our window closes. }
- GetObject(BWCCGetPattern, SizeOf(LB), @LB);
- WC.hbrBackground := CreateBrushIndirect(LB);
- WC.hIcon := LoadIcon(HInstance, PChar(100));
- end;
-
- procedure TChessWindow.Sleep;
- begin
- if not (GameOver or Paused) then
- begin
- if ActiveTimer <> nil then
- ActiveTimer^.Stop;
- ActiveTimer := nil;
- KillTimer(HWindow, 1);
- if ChessSettings.CoverBoard then
- Board.Cover(True);
- Board.Disable;
- end;
- end;
-
- procedure TChessWindow.Revive;
- begin
- if not (GameOver or Paused) then
- begin
- ActiveTimer := Timer[GetPlayer(Game)];
- ActiveTimer^.Start;
- SetTimer(HWindow, 1, ChessSettings.RefreshRate, nil);
- if IsWindowVisible(Board.CoverDlg^.HWindow) then
- Board.Cover(False);
- Board.Enable;
- end;
- end;
-
- procedure TChessWindow.RestartGame;
- var
- Cursor : HCursor;
- begin
- UpdateWindow(HWindow); { Clean up after the dialog that just closed }
- Cursor := SetCursor(LoadCursor(0, idc_Wait));
- if GameOver then
- UnlockGameOver;
- if ActiveTimer <> nil then
- ActiveTimer^.Stop;
- Timer[cWhite]^.Clear;
- Timer[cBlack]^.Clear;
- MoveHistory^.Purge;
- InfoPane^.MoveListBox^.DeleteRest(0);
- EnableMenuItem(Attr.Menu, cm_UndoMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- EnableMenuItem(Attr.Menu, cm_RedoMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- DisposeGame(Game);
- if ChessSettings.OnePlayer then
- Mode := mSinglePlayer
- else
- Mode := mTwoPlayer;
- ShowMsg(cxChessError, Ord(NewGame(Game)), nil);
- Player := cWhite;
- InfoPane^.Update(0, 0, 0, 0, 0, Word(Mode));
- GameOver := False;
- ThinkState := GetSearchStatus(Game);
- Board.ResetBoard(Game);
- SetCursor(Cursor);
- end;
-
- function TChessWindow.CanClose: Boolean;
- begin
- CanClose := inherited CanClose and
- ( GameOver or
- (MoveHistory^.Count = 0) or
- (MessageBox(HWindow, PChar(strCancelGame),
- PChar(strLeaveGame), mb_YesNo) = id_Yes));
- UpdateWindow(HWindow); { Clean up after the message box asap }
- end;
-
- function TChessWindow.IdleAction: Boolean;
- var
- OldState: TSearchStatus;
- Value: Integer;
- Line: array [0..15] of TMove;
- begin
- if not GameOver then
- begin
- OldState := ThinkState;
- if (OldState = ssMoveSearch) and (ActiveTimer <> nil) then
- ActiveTimer^.Start;
- if OldState = ssThinkAhead then
- Think(Game, 1, ThinkState)
- else
- Think(Game, ChessSettings.ThinkTime.Position, ThinkState);
- if (OldState = ssMoveSearch) and (ActiveTimer <> nil) then
- ActiveTimer^.Stop;
- if (ThinkState = ssComplete) and (OldState = ssMoveSearch) then
- AcceptComputerMove
- else
- if not GameOver and (ThinkState = ssGameOver) then
- ReportGameState;
- end;
- { Return True if we want to continue to get IdleAction calls ASAP,
- Return False if we don't need more IdleAction immediately
- ssThinkAhead is not included to minimize performance hits.
- IdleAction will be called frequently enough for ThinkAhead,
- since every wm_Timer message will set off an IdleAction call. }
- IdleAction := (ThinkState = ssMoveSearch) and not GameOver;
- end;
-
- function TChessWindow.ShowMsg(const Ctx, MsgCode: Integer;
- Override: PChar): Integer;
- var
- S: array [0..100] of Char;
- begin
- S[0] := #0;
- if Override <> nil then
- InfoPane^.Msg^.SetText(Override)
- else
- begin
- if (MsgCode <> 0) then
- StrLoadRes(S, Ctx + MsgCode);
- InfoPane^.Msg^.SetText(S);
- end;
- ShowMsg := MsgCode;
- end;
-
- function TChessWindow.GameTimeExpired: Boolean;
- begin
- GameTimeExpired := ChessSettings.LimitGame and
- (Player = GetPlayer(Game)) and { enforce game limit only on computer moves }
- (Timer[cWhite]^.GetCurrentTicks +
- Timer[CBlack]^.GetCurrentTicks > Trunc(ChessSettings.GameTime * 60 * 18.2065));
- end;
-
- procedure TChessWindow.LockDownGameOver;
- var
- M: TMove;
- begin
- AbortSearch(Game);
- if ThinkState = ssMoveSearch then { Computer thought too long }
- begin
- Board.Enable;
- SetMenu(HWindow, Attr.Menu);
- Board.ResetValidMoves;
- end;
- if GameTimeExpired then
- begin
- EnableMenuItem(Attr.Menu, cm_RedoMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- EnableMenuItem(Attr.Menu, cm_UndoMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- end;
- EnableMenuItem(Attr.Menu, cm_ComputerMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- EnableMenuItem(Attr.Menu, cm_AutoPlay, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- end;
-
- procedure TChessWindow.UnlockGameOver;
- begin
- if GameOver then
- begin
- GameOver := False;
- Board.SetGameOver(False);
- if MoveHistory^.UndoAvail then
- EnableMenuItem(Attr.Menu, cm_RedoMove, mf_ByCommand or mf_Enabled);
- if MoveHistory^.RedoAvail then
- EnableMenuItem(Attr.Menu, cm_UndoMove, mf_ByCommand or mf_Enabled);
- EnableMenuItem(Attr.Menu, cm_ComputerMove, mf_ByCommand or mf_Enabled);
- EnableMenuItem(Attr.Menu, cm_AutoPlay, mf_ByCommand or mf_Enabled);
- end;
- end;
-
- procedure TChessWindow.ReportGameState;
- var State: TChessStatus;
- StrID: Word;
- Count: Integer;
- Color: TColor;
- Data : array [0..1] of PChar;
- S : array [0..100] of Char;
- P : PChar;
- WTime, BTime: Longint;
- begin
- State := GetChessStatus(Game, Count);
- Data[0] := nil;
- Data[1] := nil;
- StrID := cxChessState + ord(State);
- case State of
- csCheckMate:
- Data[0] := StrNewRes(strWhite + ord(OtherPlayer(GetPlayer(Game))));
- csResigns:
- begin
- Data[0] := StrNewRes(strWhite + ord(OtherPlayer(GetPlayer(Game))));
- Data[1] := StrNewRes(strWhite + ord(GetPlayer(Game)));
- end;
- csMateFound:
- Data[0] := PChar(Count);
- else
- if GameTimeExpired then
- begin
- StrID := strGameTimeExpired;
- Data[0] := StrNewRes(strWhite + ord(GetPlayer(Game)));
- Data[1] := StrNewRes(strWhite + ord(OtherPlayer(GetPlayer(Game))));
- end;
- end;
- P := StrNewRes(StrID);
- S[0] := #0;
- if P <> nil then
- WVSprintf(S, P, Data);
- if Seg(Data[0]^) <> 0 then StrDispose(Data[0]);
- StrDispose(Data[1]);
- ShowMsg(0,0,S);
- InfoPane^.Update(Game, Timer[cWhite]^.GetCurrentTicks,
- Timer[cBlack]^.GetCurrentTicks,
- Timer[GetPlayer(Game)]^.GetMarkTime,
- (MoveHistory^.UndoPos+1) div 2,
- Word(Mode));
- { Check for game over conditions }
- if GameTimeExpired or
- not (State in [csNormal, csCheck, csMateFound]) then
- begin
- if ActiveTimer <> nil then
- ActiveTimer^.Stop;
- ActiveTimer := nil;
- if Board.Dragger <> nil then
- Board.CancelDrag;
- Data[0] := StrNewRes(strGameOver);
- GameOver := True;
- Board.SetGameOver(True);
- MessageBox(HWindow, S, Data[0], mb_Ok);
- LockDownGameOver;
- end;
- end;
-
- procedure TChessWindow.RecordMove(const Move: TMove);
- var
- S, T: array [0..7] of Char;
- begin
- if MoveHistory^.Count = 0 then { Enable the menu on first move }
- EnableMenuItem(Attr.Menu, cm_UndoMove, mf_ByCommand or mf_Enabled);
- if MoveHistory^.RedoAvail then { not any more...}
- EnableMenuItem(Attr.Menu, cm_RedoMove, mf_ByCommand or mf_Disabled
- or mf_Grayed);
- MoveHistory^.AddMove(Move);
- if Odd(MoveHistory^.UndoPos) then
- begin { Black move, need to package with the previous white move }
- MoveToStr(Move, T);
- MoveToStr(PMove(MoveHistory^.At(MoveHistory^.UndoPos-1))^, S);
- end
- else
- begin { White move, no black move to bundle }
- MoveToStr(Move, S);
- T[0] := ' ';
- T[1] := #0;
- end;
- InfoPane^.MoveListBox^.AddMove(MoveHistory^.UndoPos div 2,S,T);
- end;
-
- procedure TChessWindow.StartComputerMove;
- var
- TimeLimit : Longint;
- begin
- with ChessSettings do
- begin
- if NoLimit then
- TimeLimit := MaxLongint
- else
- if LimitGame then
- begin
- TimeLimit := (ChessSettings.GameTime * 1092 -
- Timer[OtherPlayer(GetPlayer(Game))]^.GetCurrentTicks) div 44;
- if MoveHistory^.UndoPos <= 80 then { Shoot for a 40 move game }
- TimeLimit := 91 + (TimeLimit - 91) *
- ((80 - MoveHistory^.UndoPos div 2) div 40);
- end
- else
- if MatchUser then
- begin
- TimeLimit := Timer[OtherPlayer(GetPlayer(Game))]^.GetMarkTime;
- if TimeLimit <= 1 then
- TimeLimit := 5 * 18;
- end
- else
- TimeLimit := TurnTime * 18;
- end;
- ComputerMove(Game, TimeLimit);
- ThinkState := GetSearchStatus(Game);
- SetMenu(HWindow, ThinkMenu);
- InfoPane^.EnableSearchInfoUpdates(True);
- Board.Disable; { Prevent mouse dragging of pieces }
- EnableMenuItem(Attr.Menu, cm_PauseGame, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- ActiveTimer := Timer[GetPlayer(Game)];
- ActiveTimer^.Mark;
- end;
-
-
- procedure TChessWindow.AcceptComputerMove;
- var
- Move: TMove;
- begin
- if (Mode = mStartup) then
- begin
- if ChessSettings.OnePlayer then
- Mode := mSinglePlayer
- else
- Mode := mTwoPlayer;
- EnableMenuItem(Attr.Menu, cm_PauseGame, mf_ByCommand or mf_Enabled);
- end;
- InfoPane^.EnableSearchInfoUpdates(False);
- GetLastMove(Game, Move);
- RecordMove(Move);
- Board.ExecuteMove(Move);
- ReportGameState;
- if (not GameOver) and
- ((Mode = mAutoPlay) or
- (Mode = mSinglePlayer) and (Player <> GetPlayer(Game))) then
- StartComputerMove
- else
- begin
- Board.Enable;
- SetMenu(HWindow, Attr.Menu);
- if not GameOver then
- begin
- Board.ResetValidMoves;
- ActiveTimer := Timer[GetPlayer(Game)];
- ActiveTimer^.Mark;
- ActiveTimer^.Start;
- EnableMenuItem(Attr.Menu, cm_PauseGame, mf_ByCommand or mf_Enabled);
- if (Mode = mSinglePlayer) and ChessSettings.AllowThinkAhead then
- begin
- Player := GetPlayer(Game);
- ThinkAhead(Game);
- ThinkState := GetSearchStatus(Game);
- InfoPane^.ZeroNodes;
- InfoPane^.EnableSearchInfoUpdates(True);
- end;
- end;
- end;
- end;
-
- function TChessWindow.LoadGame(FileName: PChar): Boolean;
- var
- S: PBufStream;
- Test: array [0..SizeOf(ChessSignature)] of Char;
- Blk: array [0..7] of Char;
- NewMoveList : PMoveList;
- Y, X: Integer;
-
- function ReplayMoves(P: PMove): Boolean; far;
- begin
- SubmitMove(Game, P^.Change);
- Board.ExecuteMove(P^);
- if Odd(X) then
- begin
- MoveToStr(P^, Blk);
- InfoPane^.MoveListBox^.AddMove(X div 2, Test, Blk);
- end
- else
- MoveToStr(P^, Test);
- ReplayMoves := (X >= MoveHistory^.UndoPos);
- Inc(X);
- end;
-
- begin
- LoadGame := False;
- S := New(PBufStream, Init(FileName, stOpenRead, 1024));
- S^.Read(Test, SizeOf(ChessSignature));
- if S^.Status <> stOK then
- MessageBox(HWindow, PChar(Context(cxStreamError, S^.Status)),
- PChar(strLoadError), mb_Ok)
- else
- if StrLComp(ChessSignature, Test, SizeOf(ChessSignature)) <> 0 then
- MessageBox(HWindow, PChar(strNotAChessFile),
- PChar(strInvalidFile), mb_Ok)
- else
- begin
- NewMoveList := PMoveList(S^.Get);
- if S^.Status <> stOK then
- MessageBox(HWindow, PChar(Context(cxStreamError, S^.Status)),
- PChar(strLoadError), mb_Ok)
- else
- begin
- RestartGame;
- Dispose(MoveHistory, Done);
- MoveHistory := NewMoveList;
- X := 0;
- Test[0] := #0;
- MoveHistory^.FirstThat(@ReplayMoves);
-
- { Copy undone moves to the move listbox as well }
- for Y := X+1 to MoveHistory^.Count-1 do
- begin
- if Odd(Y) then
- begin
- MoveToStr(PMove(MoveHistory^.At(Y))^, Blk);
- InfoPane^.MoveListBox^.AddMove(Y div 2, Test, Blk);
- end
- else
- MoveToStr(PMove(MoveHistory^.At(Y))^, Test);
- end;
- if Odd(MoveHistory^.Count) then
- InfoPane^.MoveListBox^.AddMove(
- (MoveHistory^.Count-1) div 2, Test, ' ');
- InfoPane^.MoveListBox^.SetSelIndex(MoveHistory^.UndoPos div 2);
-
- if MoveHistory^.UndoAvail then
- EnableMenuItem(Attr.Menu, cm_UndoMove, mf_ByCommand or mf_Enabled);
- if MoveHistory^.RedoAvail then
- EnableMenuItem(Attr.Menu, cm_RedoMove, mf_ByCommand or mf_Enabled);
- Board.ResetValidMoves;
- ReportGameState;
- LoadGame := True;
- end;
- end;
- Dispose(S, Done);
- end;
-
- function TChessWindow.SaveGame(FileName: PChar): Boolean;
- var
- S: PBufStream;
- begin
- S := New(PBufStream, Init(FileName, stCreate, 1024));
- S^.Write(ChessSignature, SizeOf(ChessSignature));
- S^.Put(MoveHistory);
- if S^.Status <> stOK then
- MessageBox(HWindow, PChar(Context(cxStreamError, S^.Status)),
- PChar(strSaveError), mb_Ok);
- SaveGame := S^.Status = stOK;
- Dispose(S, Done);
- end;
-
- procedure TChessWindow.AMSubmitMove(var Msg: TMessage);
- var
- Move: TMove;
- begin
- if (Mode = mStartup) then
- begin
- if ChessSettings.OnePlayer then
- Mode := mSinglePlayer
- else
- Mode := mTwoPlayer;
- EnableMenuItem(Attr.Menu, cm_PauseGame, mf_ByCommand or mf_Enabled);
- end;
- Msg.Result := ShowMsg(cxChessError, Ord(SubmitMove(Game, PChange(Msg.LParam)^)), nil);
- { Result = True if SubmitMove returns zero, else Result = False }
- LongBool(Msg.Result) := not LongBool(Msg.Result);
- if LongBool(Msg.Result) then
- begin
- if ActiveTimer <> nil then
- ActiveTimer^.Stop;
- GetLastMove(Game, Move); { Retrieve the full move from the engine }
- RecordMove(Move); { Enter in history list, enable Redo menu}
- Board.ExecuteMove(Move); { Adjust the board }
- ReportGameState;
- if not GameOver then
- if ChessSettings.TwoPlayer then
- begin
- Player := GetPlayer(Game);
- Board.ResetValidMoves; { Refresh the valid move tables }
- ActiveTimer := Timer[GetPlayer(Game)];
- ActiveTimer^.Mark;
- ActiveTimer^.Start;
- end
- else
- StartComputerMove;
- end;
- end;
-
- procedure TChessWindow.AMChoosePawnPromote(var Msg: TMessage);
- begin
- XApp^.ExecDialog(New(PChoosePawnPromoteDlg,
- Init(InfoPane, PChar(dlgChoosePawnPromote), PChange(Msg.LParam))));
- end;
-
- procedure TChessWindow.CMNewGame(var Msg: TMessage);
- begin
- if GameOver or
- (MoveHistory^.Count = 0) or
- (MessageBox(HWindow, PChar(strCancelGame),
- PChar(strStartNewGame), mb_YesNo) = id_Yes) then
- begin
- RestartGame;
- end;
- end;
-
- procedure TChessWindow.CMLoadGame(var Msg: TMessage);
- var
- Temp : array [0..fsPathName] of Char;
- Count: Integer;
- begin
- StrCopy(Temp, GameFileName);
- if ( GameOver or
- (GetChessStatus(Game, Count) in csEndGame) or
- (MoveHistory^.Count = 0) or
- (MessageBox(HWindow, PChar(strCancelGame),
- PChar(strLoadSavedGame), mb_YesNo) = id_Yes))
- and
- (XApp^.ExecDialog(New(PCDFileOpen, Init(@Self,
- ofn_FileMustExist, Temp, SizeOf(Temp),
- ChessFileFilter))) = idOk) then
- if LoadGame(Temp) then
- StrCopy(GameFileName, Temp);
- end;
-
- procedure TChessWindow.CMSaveGame(var Msg: TMessage);
- begin
- if GameFileName[0] = #0 then
- CMSaveAs(Msg)
- else
- SaveGame(GameFileName);
- end;
-
- procedure TChessWindow.CMSaveAs(var Msg: TMessage);
- var
- Temp : array [0..fsPathName] of Char;
- begin
- StrCopy(Temp, GameFileName);
- if XApp^.ExecDialog(New(PCDFileSaveAs, Init(@Self,
- ofn_PathMustExist, Temp, SizeOf(Temp), ChessFileFilter))) = idOk then
- if SaveGame(Temp) then
- StrCopy(GameFileName, Temp);
- end;
-
- procedure TChessWindow.CMAutoPlay(var Msg: TMessage);
- begin
- if Paused then { The game is paused }
- CMPauseGame(Msg); { Clear the paused state before entering autoplay }
- Mode := mAutoPlay;
- AbortSearch(Game);
- StartComputerMove;
- end;
-
- procedure TChessWindow.CMPauseGame(var Msg: TMessage);
- var
- S: array [0..20] of Char;
- begin
- if Paused then
- begin
- Paused := False;
- Revive;
- ModifyMenu(Attr.Menu, cm_PauseGame, mf_ByCommand or mf_String,
- cm_PauseGame, StrLoadRes(S, strPauseMenu));
- if MoveHistory^.RedoAvail then
- EnableMenuItem(Attr.Menu, cm_RedoMove, mf_ByCommand or mf_Enabled);
- if MoveHistory^.UndoAvail then
- EnableMenuItem(Attr.Menu, cm_UndoMove, mf_ByCommand or mf_Enabled);
- EnableMenuItem(Attr.Menu, cm_ComputerMove, mf_ByCommand or mf_Enabled);
- EnableMenuItem(Attr.Menu, cm_EnterMove, mf_ByCommand or mf_Enabled);
- end
- else
- begin
- Sleep;
- ModifyMenu(Attr.Menu, cm_PauseGame, mf_ByCommand or mf_String,
- cm_PauseGame, StrLoadRes(S, strResumeMenu));
- ShowMsg(0,strGamePaused,nil);
- if MoveHistory^.RedoAvail then
- EnableMenuItem(Attr.Menu, cm_RedoMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- if MoveHistory^.UndoAvail then
- EnableMenuItem(Attr.Menu, cm_UndoMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- EnableMenuItem(Attr.Menu, cm_ComputerMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- EnableMenuItem(Attr.Menu, cm_EnterMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- Paused := True;
- end;
- end;
-
- procedure TChessWindow.CMUndoMove(var Msg: TMessage);
- var
- M : TMove;
- RedoBefore, UndoBefore: Boolean;
- begin
- { No error checking is performed here - it is assumed that the
- menu enable/disable code will only allow the user
- to select this menu item when there is a valid undo available. }
- UndoBefore := MoveHistory^.UndoAvail;
- RedoBefore := MoveHistory^.RedoAvail;
-
- AbortSearch(Game); { You can't submit or retract moves while thinking }
-
- if GameOver then
- UnlockGameOver;
-
- if ActiveTimer <> nil then
- ActiveTimer^.Stop;
- Revive;
- ActiveTimer^.Stop;
- ActiveTimer^.Mark;
-
- MoveHistory^.Undo(M);
- RetractMove(Game, M);
- Board.RetractMove(M);
-
- if (Mode = mSinglePlayer) and
- MoveHistory^.UndoAvail then { Undo both player's and computer's move }
- begin
- MoveHistory^.Undo(M);
- RetractMove(Game, M);
- Board.RetractMove(M);
- end;
- if MoveHistory^.RedoAvail and not RedoBefore then
- EnableMenuItem(Attr.Menu, cm_RedoMove, mf_ByCommand or mf_Enabled);
- if (not MoveHistory^.UndoAvail) and UndoBefore then
- EnableMenuItem(Attr.Menu, cm_UndoMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- InfoPane^.MoveListBox^.SetSelIndex(MoveHistory^.UndoPos div 2);
- Board.ResetValidMoves;
- InfoPane^.EnableSearchInfoUpdates(False);
- ReportGameState;
- ActiveTimer^.Start;
- end;
-
- procedure TChessWindow.CMRedoMove(var Msg: TMessage);
- var
- M : TMove;
- RedoBefore, UndoBefore: Boolean;
- begin
- { No error checking is performed here - it is assumed that the
- menu enable/disable code will only allow the user
- to select this menu item when there is a valid redo available. }
- UndoBefore := MoveHistory^.UndoAvail;
- RedoBefore := MoveHistory^.RedoAvail;
-
- AbortSearch(Game); { You can't submit or retract moves while thinking }
-
- if GameOver then
- UnlockGameOver;
-
- if ActiveTimer <> nil then
- ActiveTimer^.Stop;
- Revive;
- ActiveTimer^.Stop;
- ActiveTimer^.Mark;
-
- MoveHistory^.Redo(M);
- SubmitMove(Game, M.Change);
- Board.ExecuteMove(M);
-
- if (Mode = mSinglePlayer) and
- MoveHistory^.RedoAvail then
- begin
- MoveHistory^.Redo(M); { Redo both player's and computer's moves }
- SubmitMove(Game, M.Change);
- Board.ExecuteMove(M);
- end;
-
- { Update the menus, but only when the undo/redo state changes
- (to avoid menubar flicker caused by unnecessary menu changes) }
- if (not MoveHistory^.RedoAvail) and RedoBefore then
- EnableMenuItem(Attr.Menu, cm_RedoMove, mf_ByCommand or
- mf_Disabled or mf_Grayed);
- if MoveHistory^.UndoAvail and not UndoBefore then
- EnableMenuItem(Attr.Menu, cm_UndoMove, mf_ByCommand or mf_Enabled);
-
- InfoPane^.MoveListBox^.SetSelIndex(MoveHistory^.UndoPos div 2);
- Board.ResetValidMoves;
- InfoPane^.EnableSearchInfoUpdates(False);
- ReportGameState;
- if ActiveTimer <> nil then
- ActiveTimer^.Start;
- end;
-
- procedure TChessWindow.CMComputerMove(var Msg: TMessage);
- var
- Move: TMove;
- begin
- AbortSearch(Game);
- GetHintMove(Game, Move);
- if VerifyMove(Game, Move.Change) = ceOK then
- begin
- Msg.LParam := Longint(@Move.Change);
- AMSubmitMove(Msg);
- end
- else
- begin
- Player := GetPlayer(Game);
- StartComputerMove;
- end;
- end;
-
- procedure TChessWindow.CMEnterMove(var Msg: TMessage);
- var
- S: array [0..10] of Char;
- Chg: TChange;
- begin
- S[0] := #0;
- Board.CoverDlg^.Lock; { Prevent EnterMoveDlg from covering board }
- if XApp^.ExecDialog(New(PEnterMoveDlg,
- Init(InfoPane, PChar(dlgEnterMove), S))) = IDOK then
- begin
- if (ShowMsg(cxChessError, Ord(ParseMove(S, Chg)),nil) = 0) then
- begin
- Msg.LParam := Longint(@Chg);
- Msg.wParam := 0;
- AMSubmitMove(Msg);
- end
- end;
- Board.CoverDlg^.Unlock;
- end;
-
- procedure TChessWindow.CMSettings(var Msg: TMessage);
- begin
- XApp^.ExecDialog(new(PSettingsDlg, Init(@Self, PChar(dlgSettings),
- ChessSettings)));
- if (Mode <> mStartup) then
- begin
- if ChessSettings.OnePlayer then
- Mode := mSinglePlayer
- else
- Mode := mTwoPlayer;
- Board.ResetValidMoves;
- end;
- if (ChessSettings.CoverBoard <> Board.CoverDlg^.Locked) then
- if ChessSettings.CoverBoard then
- Board.CoverDlg^.Unlock
- else
- Board.CoverDlg^.Lock;
- end;
-
- procedure TChessWindow.CMAbout(var Msg: TMessage);
- begin
- XApp^.ExecDialog(New(PAboutBox,
- Init(@Self, 'About OWLChess', PChar(bmBlaise))));
- end;
-
- procedure TChessWindow.CMStopThinking(var Msg: TMessage);
- begin
- if ThinkState = ssMoveSearch then
- ForceMove(Game); { Move search will terminate at next Think call }
- if Mode = mAutoPlay then
- begin
- Mode := mSinglePlayer; { Stop the demo, if it is running }
- Player := OtherPlayer(GetPlayer(Game));
- end;
- end;
-
- procedure TChessWindow.WMTimer(var Msg: TMessage);
- begin
- if not GameOver then
- ReportGameState;
- end;
-
- procedure TChessWindow.WMSetCursor(var Msg: TMessage);
- begin
- DefWndProc(Msg);
- Msg.Result := 1; { Cancel any pending WMSetCursor in children }
- if Msg.LParamLo = HTClient then
- if (ThinkState = ssMoveSearch) then
- SetCursor(LoadCursor(0, PChar(idc_Wait)))
- else
- begin
- if Msg.WParam = Board.HWindow then
- Msg.Result := 0 { Allow Board to use its own cursor }
- else
- SetCursor(LoadCursor(0, PChar(idc_Arrow)));
- end;
- end;
-
- procedure TChessWindow.WMActivate(var Msg: TMessage);
- begin
- inherited WMActivate(Msg);
- if Mode = mStartup then Exit;
- if Msg.LParamHi = 0 then { we're not minimized }
- if Msg.WParam = 0 then { we're going inactive }
- Sleep
- else
- Revive
- else
- if ActiveTimer <> nil then { we're being minimized }
- Sleep;
- end;
-
-
- procedure TChessApp.InitInstance;
- begin
- inherited InitInstance;
- if Status = 0 then
- begin
- HAccTable := LoadAccelerators(HInstance, 'Accel');
- if HAccTable = 0 then
- Status := em_InvalidWindow;
- end;
- end;
-
- procedure TChessApp.InitMainWindow;
- begin
- MainWindow := new(PChessWindow, Init(nil, 'OWL Chess'));
- end;
-
- function TChessApp.IdleAction: Boolean;
- begin
- IdleAction := PChessWindow(MainWindow)^.IdleAction;
- end;
-
- procedure ShowSplashScreen(var R: TRect);
- var
- BM: HBitmap;
- DC, MemDC: HDC;
- BitInfo: TBitmap;
- begin
- DC := GetDC(0);
- MemDC := CreateCompatibleDC(DC);
- BM := LoadBitmap(HInstance, PChar(bmBlaise));
- GetObject(BM, SizeOf(BitInfo), @BitInfo);
- BM := SelectObject(MemDC, BM); { swap BMs}
- R.Left := GetDeviceCaps(DC,HORZRES) div 2 - BitInfo.bmWidth div 2;
- R.Top := GetDeviceCaps(DC,VERTRES) div 2 - BitInfo.bmHeight div 2;
- BitBlt(DC, R.Left, R.Top, BitInfo.bmWidth, BitInfo.bmHeight,
- MemDC, 0, 0, SrcCopy);
- DeleteObject(SelectObject(MemDC, BM));
- DeleteDC(MemDC);
- ReleaseDC(0, DC);
- R.Right := R.Left + BitInfo.bmWidth;
- R.Bottom := R.Top + BitInfo.bmHeight;
- end;
-
-
- var
- App: TChessApp;
- R: TRect;
- begin
- RegisterType(RMoveList);
-
- { Show Splash screen asap }
- ShowSplashScreen(R);
-
- App.Init('OWL Chess');
-
- { Erase the splash bitmap }
- InvalidateRect(0, @R, True);
-
- App.Run;
- App.Done;
- end.