Added files for the winboard module: mod_winboard.pas and winboardconn.pas

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1920 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
brian-ch 2011-09-07 18:02:31 +00:00
parent abea05d9e6
commit a833a301a5
2 changed files with 301 additions and 0 deletions

View File

@ -0,0 +1,103 @@
unit mod_winboard;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
StdCtrls, Forms, Controls,
chessmodules, chessgame;
type
{ TWinboardChessModule }
TWinboardChessModule = class(TChessModule)
private
textEnginePatch : TStaticText;
editEnginePatch : TEdit;
EngineStringList: TStringList;
side : boolean; //Side to move true=human.
public
constructor Create;
procedure CreateUserInterface(); override;
procedure ShowUserInterface(AParent: TWinControl); override;
procedure HideUserInterface(); override;
procedure FreeUserInterface(); override;
procedure PrepareForGame(); override;
procedure HandleOnMove(AFrom, ATo: TPoint); override;
end;
implementation
uses winboardConn;
{ TSinglePlayerChessModule }
constructor TWinboardChessModule.Create;
begin
inherited Create;
SelectionDescription := 'Play against a winboard engine';
PlayingDescription := 'Play against a winboard engine';
Kind := cmkAgainstComputer;
end;
procedure TWinboardChessModule.CreateUserInterface;
begin
textEnginePatch := TStaticText.Create(nil);
textEnginePatch.SetBounds(20, 20, 180, 50);
textEnginePatch.Caption := 'Full patch to the engine(with args)';
editEnginePatch := TEdit.Create(nil);
editEnginePatch.SetBounds(200, 20, 150, 50);
editEnginePatch.Text := 'gnuchess -x';
end;
procedure TWinboardChessModule.ShowUserInterface(AParent: TWinControl);
begin
textEnginePatch.Parent := AParent;
editEnginePatch.Parent := AParent;
end;
procedure TWinboardChessModule.HideUserInterface();
begin
textEnginePatch.Parent := nil;
editEnginePatch.Parent := nil;
end;
procedure TWinboardChessModule.FreeUserInterface();
begin
textEnginePatch.Free;
editEnginePatch.Free;
end;
procedure TWinboardChessModule.HandleOnMove(AFrom, ATo: TPoint);
var
moveStr : String;
CompMove: moveInCoord;
begin
moveStr:=vwinboardConn.coordToString(AFrom,ATo,vChessGame.PreviousMove.PieceMoved,vChessGame.PreviousMove.PieceEaten);
vwinboardConn.tellMove(moveStr);
compMove:=vwinboardConn.engineMove;
vChessGame.MovePiece(CompMove[1],CompMove[2]);
end;
procedure TWinboardChessModule.PrepareForGame;
var i: integer;
CompMove: moveInCoord;
begin
vwinboardConn.startEngine(editEnginePatch.text);
if not vChessGame.FirstPlayerIsWhite then
begin
vwinboardConn.tellMove('go');
compMove:=vwinboardConn.engineMove;
vChessGame.MovePiece(CompMove[1],CompMove[2]);
end;
end;
initialization
RegisterChessModule(TWinboardChessModule.Create);
end.

View File

@ -0,0 +1,198 @@
{
Unit with the basics to communicate with engines that use the winboard protocol.
I used some code of the TProcess example also:
https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/examples/process/
}
unit winboardConn;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Process, StdCtrls, chessgame;
type
moveInCoord = array[1..2] of TPoint;
TwinboardConn = class
public
procedure startEngine(path : String);
procedure stopEngine;
procedure tellMove(move : String);
function engineMove() : moveInCoord;
function coordToString(AFrom, ATo : TPoint; pieceFrom, pieceTo : TChessTile) : String;
function stringToCoord(moveStr : String) : moveInCoord;
private
procedure readFromPipe;
function extractMove : string;
function letterToNumber(num:String) : String;
function numberToLetter(n : integer) : String;
function pieceToLetter(piece : TChessTile) : String;
end;
var
engineProcess : TProcess;
outputText : String;
vwinboardConn : TwinboardConn;
implementation
procedure TwinboardConn.startEngine(path : String);
begin
engineProcess:= TProcess.Create(nil);
engineProcess.CommandLine := path;
engineProcess.Options := engineProcess.Options + [poUsePipes];
engineProcess.Execute;
end;
procedure TwinboardConn.stopEngine;
begin
if engineProcess.Running then
engineProcess.Free;
end;
procedure TwinboardConn.tellMove(move : String);
begin
move := move+#13+#10;
EngineProcess.Input.Write(move[1], length(move));
end;
//return the engine move.
function TwinboardConn.engineMove : moveInCoord;
var move : String;
points: moveInCoord;
begin
sleep(500);
repeat
readFromPipe;
until length(outputText)>10;
move := extractMove;
points := stringToCoord(move);
result:=points;
end;
function TwinboardConn.coordToString(AFrom, ATo : TPoint; pieceFrom, pieceTo : TChessTile) : String;
var
move : String;
begin
//still need to verify castle an en passant
move:= move + numberToLetter(AFrom.X);
move:= move + intToStr(AFrom.Y);
move:= move + numberToLetter(ATo.X);
move:= move + IntToStr(ATo.Y);
result:=move;
end;
function TwinboardConn.pieceToLetter(piece : TChessTile) : String;
begin
case piece of
ctWRook : result:= 'R';
ctBRook : result:= 'R';
ctWKnight : result:= 'N';
ctBKnight : result:= 'N';
ctWBishop : result:= 'B';
ctBBishop : result:= 'B';
ctWQueen : result:= 'Q';
ctBQueen : result:= 'Q';
ctWKing : result:= 'K';
ctBKing : result:= 'K';
end;
end;
function TwinboardConn.numberToLetter(n : integer) : String;
begin
case n of
1 : result := 'a';
2 : result := 'b';
3 : result := 'c';
4 : result := 'd';
5 : result := 'e';
6 : result := 'f';
7 : result := 'g';
8 : result := 'h';
end;
end;
function TwinboardConn.stringToCoord(moveStr : String) : moveInCoord;
var move : moveInCoord;
begin
//need to verify castle here
//if moveStr[1] in ['R','N','B','Q','K'] then
// Delete(moveStr,1,1);
move[1].X:=strToInt(letterToNumber(moveStr[1]));
move[1].Y:=strToInt(moveStr[2]);
move[2].X:=strToInt(letterToNumber(moveStr[3]));
move[2].Y:=strToInt(moveStr[4]);
result:=move;
end;
//Transform collum number in letter, ex.: 1=a, 3=c ....
function TwinboardConn.letterToNumber(num:String) : String;
begin
case num[1] of
'a' : result:='1';
'b' : result:='2';
'c' : result:='3';
'd' : result:='4';
'e' : result:='5';
'f' : result:='6';
'g' : result:='7';
'h' : result:='8';
end;
end;
//read all the output text from the TProcess pipe
procedure TwinboardConn.readFromPipe;
var
NoMoreOutput: boolean;
procedure DoStuffForProcess;
var
Buffer: string;
BytesAvailable: DWord;
BytesRead:LongInt;
begin
if engineProcess.Running then
begin
BytesAvailable := engineProcess.Output.NumBytesAvailable;
BytesRead := 0;
while BytesAvailable>0 do
begin
SetLength(Buffer, BytesAvailable);
BytesRead := engineProcess.OutPut.Read(Buffer[1], BytesAvailable);
OutputText := OutputText + copy(Buffer,1, BytesRead);
BytesAvailable := engineProcess.Output.NumBytesAvailable;
NoMoreOutput := false;
end;
end;
end;
begin
if engineProcess.Running then
repeat
NoMoreOutput := true;
DoStuffForProcess;
until noMoreOutput;
end;
function TwinboardConn.extractMove : string;
var move : String;
i,p : integer;
begin
p := pos('My move is: ', outputText);
p:=p+12;
if p>0 then
while outputText[p]<>#10 do
begin
move:= move+outputText[p];
inc(p);
end;
result:=move;
outputText:='';
end;
end.