fpchess: clean up and fixes of the winboard module

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2843 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
brian-ch
2013-11-20 01:28:33 +00:00
parent 3222dc18bc
commit ce2fa416c9
2 changed files with 78 additions and 79 deletions

View File

@ -18,7 +18,6 @@ type
textEnginePatch : TStaticText; textEnginePatch : TStaticText;
editEnginePatch : TEdit; editEnginePatch : TEdit;
EngineStringList: TStringList; EngineStringList: TStringList;
side : boolean; //Side to move true=human.
public public
constructor Create; override; constructor Create; override;
procedure CreateUserInterface(); override; procedure CreateUserInterface(); override;
@ -27,6 +26,7 @@ type
procedure FreeUserInterface(); override; procedure FreeUserInterface(); override;
procedure PrepareForGame(); override; procedure PrepareForGame(); override;
procedure HandleOnMove(AFrom, ATo: TPoint); override; procedure HandleOnMove(AFrom, ATo: TPoint); override;
procedure HandleOnTimer(); override;
end; end;
implementation implementation
@ -78,9 +78,16 @@ var
CompMove: moveInCoord; CompMove: moveInCoord;
begin begin
moveStr:=vwinboardConn.coordToString(AFrom,ATo,vChessGame.PreviousMove.PieceMoved,vChessGame.PreviousMove.PieceEaten); moveStr:=vwinboardConn.coordToString(AFrom,ATo,vChessGame.PreviousMove.PieceMoved,vChessGame.PreviousMove.PieceEaten);
vwinboardConn.tellMove(moveStr); vwinboardConn.tellMove(moveStr);
compMove:=vwinboardConn.engineMove; end;
procedure TWinboardChessModule.HandleOnTimer;
var
CompMove: moveInCoord;
begin
CompMove[1]:=Point(1,1);
CompMove[2]:=Point(1,1);
CompMove:=vwinboardConn.engineMove;
vChessGame.MovePiece(CompMove[1],CompMove[2]); vChessGame.MovePiece(CompMove[1],CompMove[2]);
end; end;
@ -101,5 +108,5 @@ end;
initialization initialization
RegisterChessModule(TWinboardChessModule.Create); RegisterChessModule(TWinboardChessModule.Create);
finalization finalization
vwinboardConn.stopEngine; vwinboardConn.stopEngine(True);
end. end.

View File

@ -11,15 +11,16 @@ unit winboardConn;
interface interface
uses uses
Classes, SysUtils, Forms, Process, StdCtrls, chessgame; Classes, SysUtils, Forms, Process, StdCtrls, SorokinRegExpr, chessgame;
type type
moveInCoord = array[1..2] of TPoint; moveInCoord = array[1..2] of TPoint;
TwinboardConn = class TWinboardConn = class
public public
procedure startEngine(path : String); procedure startEngine(path : String);
procedure stopEngine; procedure stopEngine(freeProcess : boolean);
destructor Destroy; override;
procedure tellMove(move : String); procedure tellMove(move : String);
function engineMove() : moveInCoord; function engineMove() : moveInCoord;
function coordToString(AFrom, ATo : TPoint; pieceFrom, pieceTo : TChessTile) : String; function coordToString(AFrom, ATo : TPoint; pieceFrom, pieceTo : TChessTile) : String;
@ -29,99 +30,85 @@ type
function extractMove : string; function extractMove : string;
function letterToNumber(num:String) : Integer; function letterToNumber(num:String) : Integer;
function numberToLetter(n : integer) : String; function numberToLetter(n : integer) : String;
procedure detectEngine(path : String); //procedure detectEngine(path : String);
end; end;
var var
engineProcess : TProcess; engineProcess : TProcess;
outputText : String; outputText : String;
vwinboardConn : TwinboardConn; vwinboardConn : TWinboardConn;
algebraicInput: boolean; algebraicInput: boolean;
engineMoveComIndex : integer; engineRegExpression: TRegExpr;
engineMoveCommand : array[1..4,1..2] of String;
implementation implementation
procedure TwinboardConn.startEngine(path : String); destructor TWinboardConn.Destroy;
begin begin
engineMoveCommand[1,1]:='gnuchess 5.07'; stopEngine(True);
engineMoveCommand[1,2]:='My move is: ';
engineMoveCommand[2,1]:='phalanx';
engineMoveCommand[2,2]:='my move is ';
engineMoveCommand[3,1]:='gnuchess 5.08';
engineMoveCommand[3,2]:='move ';
engineMoveCommand[4,1]:='gnuchess 6.0.1';
engineMoveCommand[4,2]:='My move is : ';
if engineProcess<>nil then Inherited Destroy;
if engineProcess.Running then end;
stopEngine;
procedure TWinboardConn.startEngine(path : String);
var extraCommands : String;
begin
//stop engine if it is running
stopEngine(False);
//create TProcess and start the engine in xboard mode
engineProcess:= TProcess.Create(nil); engineProcess:= TProcess.Create(nil);
engineRegExpression:= TRegExpr.Create;
engineProcess.CommandLine := path; engineProcess.CommandLine := path;
engineProcess.Options := engineProcess.Options + [poUsePipes]; engineProcess.Options := engineProcess.Options + [poUsePipes];
engineProcess.Execute; engineProcess.Execute;
extraCommands:='xboard'+#13+#10;
detectEngine(path); EngineProcess.Input.Write(extraCommands[1], length(extraCommands));
end; extraCommands:='level 60 0.5 3'+#13+#10;
EngineProcess.Input.Write(extraCommands[1], length(extraCommands));
procedure TwinboardConn.detectEngine(path : String);
var engineOut : String;
extraCommand : String;
begin
//crafty only show his moves in abbreviated algebraic notation, it's not in
//the array 'engineMoveCommand' because this is not implemented yet.
if pos(path,'crafty')<> 0 then algebraicInput:=true;
sleep(50); //just to guarantee that the engine has already tell his initial output
readFromPipe;
if pos('GNU Chess 5.07',outputText)>0 then
engineMoveComIndex:=1;
if pos('Phalanx',outputText)>0 then
engineMoveComIndex:=2;
if pos('GNU Chess 5.08',outputText)>0 then
engineMoveComIndex:=3;
if pos('GNU Chess 6.0.1',outputText)>0 then
engineMoveComIndex:=4;
extraCommand:='xboard'+#13+#10;
EngineProcess.Input.Write(extraCommand[1], length(extraCommand));
sleep(100);
outputText:=''; outputText:='';
end; end;
procedure TwinboardConn.stopEngine; procedure TWinboardConn.stopEngine(freeProcess : boolean);
begin begin
if engineProcess<>nil then if engineProcess<>nil then
if engineProcess.Running then if engineProcess.Running then
begin
engineProcess.Input.WriteAnsiString('quit'+#13+#10);
engineProcess.Terminate(0); engineProcess.Terminate(0);
engineProcess.free; end;
if freeProcess then
begin
engineProcess.free;
end;
end; end;
procedure TwinboardConn.tellMove(move : String); procedure TWinboardConn.tellMove(move : String);
begin begin
move := move+#13+#10; move := move+#13+#10;
EngineProcess.Input.Write(move[1], length(move)); EngineProcess.Input.Write(move[1], length(move));
end; end;
//return the engine move. //return the engine move.
function TwinboardConn.engineMove : moveInCoord; function TWinboardConn.engineMove : moveInCoord;
var move : String; var move : String;
points: moveInCoord; points: moveInCoord;
begin begin
sleep(500); engineRegExpression.Expression:='(?m)^(My move|my move|move)( is|)(: | : | )';
repeat readFromPipe;
Application.processMessages; if engineRegExpression.Exec(outputText) then
readFromPipe; begin
until pos(engineMoveCommand[engineMoveComIndex][2],outputText)>0; move := extractMove;
move := extractMove; points := stringToCoord(move);
points := stringToCoord(move); result:=points;
result:=points; end;
end; end;
function TwinboardConn.coordToString(AFrom, ATo : TPoint; pieceFrom, pieceTo : TChessTile) : String; function TWinboardConn.coordToString(AFrom, ATo : TPoint; pieceFrom, pieceTo : TChessTile) : String;
var var
move : String; move : String;
begin begin
//still need to verify castle an en passant
move:= move + numberToLetter(AFrom.X); move:= move + numberToLetter(AFrom.X);
move:= move + intToStr(AFrom.Y); move:= move + intToStr(AFrom.Y);
@ -132,7 +119,7 @@ begin
end; end;
function TwinboardConn.numberToLetter(n : integer) : String; function TWinboardConn.numberToLetter(n : integer) : String;
begin begin
case n of case n of
1 : result := 'a'; 1 : result := 'a';
@ -146,10 +133,9 @@ begin
end; end;
end; end;
function TwinboardConn.stringToCoord(moveStr : String) : moveInCoord; function TWinboardConn.stringToCoord(moveStr : String) : moveInCoord;
var move : moveInCoord; var move : moveInCoord;
begin begin
//need to verify castle here
if moveStr[1] in ['P','R','N','B','Q','K'] then if moveStr[1] in ['P','R','N','B','Q','K'] then
Delete(moveStr,1,1); Delete(moveStr,1,1);
move[1].X:=letterToNumber(moveStr[1]); move[1].X:=letterToNumber(moveStr[1]);
@ -163,7 +149,7 @@ begin
result:=move; result:=move;
end; end;
//Transform collum letter to number //Transform collum letter to number
function TwinboardConn.letterToNumber(num:String) : Integer; function TWinboardConn.letterToNumber(num:String) : Integer;
begin begin
case num[1] of case num[1] of
'a' : result:=1; 'a' : result:=1;
@ -178,8 +164,9 @@ begin
end; end;
end; end;
//read all the output text from the TProcess pipe //read all the output text from the TProcess pipe (basically copy/pasted from the
procedure TwinboardConn.readFromPipe; //TProcess example)
procedure TWinboardConn.readFromPipe;
var var
NoMoreOutput: boolean; NoMoreOutput: boolean;
@ -211,22 +198,27 @@ begin
until noMoreOutput; until noMoreOutput;
end; end;
function TwinboardConn.extractMove : string; function TWinboardConn.extractMove : string;
var move : String; var
i,p : integer; initialPos : integer;
begin begin
p := pos(engineMoveCommand[engineMoveComIndex][2],outputText); //delete the text from the start of the engine output
engineRegExpression.Expression:='.*(My move|my move|move)( is|)(: | : | )';
engineRegExpression.Exec(outputText);
initialPos := pos(engineRegExpression.Match[0],outputText);
if p>=0 then Delete(outputText,initialPos,Length(engineRegExpression.Match[0]));
//if there's text after the engine move, delete it too
engineRegExpression.Expression:=' .+';
if (engineRegExpression.Exec(outputText)) then
begin begin
p := p+length(engineMoveCommand[engineMoveComIndex][2]); initialPos := pos(engineRegExpression.Match[0],outputText);
while outputText[p]<>#10 do Delete(outputText,initialPos,Length(engineRegExpression.Match[0]));
begin
move:= move+outputText[p];
inc(p);
end;
end; end;
result:=move;
result:= outputText;
outputText:=''; outputText:='';
end; end;