chesslablab / chess-server Goto Github PK
View Code? Open in Web Editor NEWAsynchronous PHP chess server.
Home Page: https://chesslablab.github.io/chess-server/
License: MIT License
Asynchronous PHP chess server.
Home Page: https://chesslablab.github.io/chess-server/
License: MIT License
ChessServer\Command\EventsCommand
should be implemented.
Thus, should be added in the res($argv, $cmd)
method of ChessServer\GameMode\AbstractMode
accordingly.
ChessServer\Command\EventsCommand
is quite similar to ChessServer\Command\CastlingCommand
which could be taken as an example for implementation.
Thanks! Keep it up.
This issue is intended to practice software architecture skills as well as unit testing.
As you may have noted, there's a one-to-one correspondence between the Chess\Game
methods described in the PHP Chess Docs and the commands available in the chess server:
ascii(): string
<-> ChessServer\Command\AsciiCommand.php
captures(): array
<-> ChessServer\Command\CapturesCommand.php
castling(): ?array
<-> ChessServer\Command\CastlingCommand.php
All commands should be unit tested in ChessServer\Tests\Unit\Command
. However, the ChessServer\Tests\Unit\Command\CastlingTest.php
file is missing.
The missing file should be added as per the existing conventions.
Happy learning and coding!
Command names containing several words should be snake cased for better readability, as it is described below.
/heuristicpicture
<--> /heuristic_picture
/ischeck
<--> /is_check
/ismate
<--> /is_mate
/playfen
<--> /play_fen
/undomove
<--> /undo_move
Happy coding and keep it up.
The file should be quite similar to this one.
The number of current connections should be written in the log every time a new connection is open.
At the present moment this is how the log looks like:
$ cat storage/pchess.log
...
[2021-09-18T17:01:14.803013+00:00] pchess.net.INFO: New connection {"id":654} []
[2021-09-18T17:01:14.938909+00:00] pchess.net.INFO: Sent message {"id":654,"res":{"/start":{"mode":"analysis"}}} []
[2021-09-18T17:01:17.293531+00:00] pchess.net.INFO: Sent message {"id":654,"res":{"/piece":{"stdClass":{"color":"w","identity":"P","position":"e2","moves":["e3","e4"]}}}} []
[2021-09-18T17:01:18.115265+00:00] pchess.net.INFO: Sent message {"id":654,"res":{"/playfen":{"turn":"w","legal":true,"check":false,"mate":false,"movetext":"1.e4","fen":"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3"}}} []
However, it should look like this:
$ cat storage/pchess.log
...
[2021-09-18T17:01:14.803013+00:00] pchess.net.INFO: New connection {"id":654, "n":8} []
[2021-09-18T17:01:14.938909+00:00] pchess.net.INFO: Sent message {"id":654,"res":{"/start":{"mode":"analysis"}}} []
[2021-09-18T17:01:17.293531+00:00] pchess.net.INFO: Sent message {"id":654,"res":{"/piece":{"stdClass":{"color":"w","identity":"P","position":"e2","moves":["e3","e4"]}}}} []
[2021-09-18T17:01:18.115265+00:00] pchess.net.INFO: Sent message {"id":654,"res":{"/playfen":{"turn":"w","legal":true,"check":false,"mate":false,"movetext":"1.e4","fen":"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3"}}} []
Thus, it's just the following line that needs an update:
[2021-09-18T17:01:14.803013+00:00] pchess.net.INFO: New connection {"id":654} []
Happy learning and coding!
All files in the src/Commands
folder should be suffixed with the word "Command", for example:
AbstractCommand.php
AcceptFriendRequestCommand.php
AsciiCommand.php
At this moment, the 'Play with a friend' token can be used by multiple players at the same time, however, only one player should be allowed to use it.
A new parameter needs to be added to allow starting games with a time increment of n seconds, as described in the example below.
$ websocat ws://localhost:8080
/start playfriend w 10 3
{"\/start":{"mode":"playfriend","jwt":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwY2hlc3MubmV0IiwiaWF0IjoxNjM4ODc4OTAxLCJjb2xvciI6InciLCJtaW4iOiIxMCIsImluY3JlbWVudCI6IjMiLCJleHAiOjE2Mzg4Nzk1MDF9._miJaIi0Qm-mvHka-vZ6aBVfJVsD2uDZDhnoMAaNfLU","hash":"713333c9ce51fe98a256732cf706215d"}}
In this example, a 10
minutes game is started with a time increment of 3
seconds.
A new command to allow resigning a game should be implemented similarly as with ChessServer\Command\TakebackCommand.
A new command to allow chatting with the oponent should be implemented.
See:
Thus, a new file called ChatCommand
needs to be created in the src/Command
folder, and it should be implemented accordingly to allow chatting with the opponent.
Example:
/chat "What is the scope of a knight on a1?"
Keep it up, and happy learning and coding!
A new method to allow proposing a takeback should be implemented in the Chess\Game
class as described in chesslablab/php-chess#55.
As you may have noted, there's a one-to-one correspondence between the Chess\Game
methods described in the PHP Chess docs and the commands available in the chess server:
ascii(): string
<-> ChessServer\Command\AsciiCommand.php
captures(): array
<-> ChessServer\Command\CapturesCommand.php
castling(): ?array
<-> ChessServer\Command\CastlingCommand.php
...
However, the ChessServer\Command\TakebackCommand.php
is missing.
The missing file should be added once the takeback method has been implemented in Chess\Game
.
Also see chesslablab/spablab#132.
DocBlocks as per phpDocumentor docs should be written for classes, traits, methods and so on.
/legalmoves
will allow highlighting possible moves after a piece is clicked.
The commands used in the main if
block in ChessServer\Socket
should be ordered alphabetically for better readability.
...
if (is_a($cmd, AcceptFriendRequestCommand::class)) {
...
} elseif (is_a($cmd, QuitCommand::class)) {
...
} elseif (is_a($cmd, StartCommand::class)) {
...
} elseif (is_a($cmd, PlayFenCommand::class)) {
...
} elseif (is_a($cmd, TakebackCommand::class)) {
...
} elseif (is_a($cmd, DrawCommand::class)) {
...
} elseif (is_a($cmd, ResignCommand::class)) {
...
} elseif ($gameMode) {
return $this->sendToOne(
$from->resourceId,
$this->gameModes[$from->resourceId]->res($this->parser->argv, $cmd)
);
}
...
A new command to allow offering a rematch should be implemented similarly as with ChessServer\Command\DrawCommand
.
Keep it up, and happy learning!
At this moment /playfen
is responding with a basic {"legal": true}
or {"legal": false}
string, but it makes sense to add some more lightweight data for the client app to display.
Possibly the simplest thing to do at this stage is to just refactor the response as described in the following example:
{
"legal": true,
"movetext": "1.e4 e5"
}
Now that a sandbox chess server has been setup for testing purposes, it seems as if the WebSocket connections should be secured in order for this demo to run without security issues.
Chrome:
Mixed Content: The page at 'https://programarivm.com/demo-redux-chess/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://3.121.169.246:8080/'. This request has been blocked; this endpoint must be available over WSS.
Firefox:
Uncaught (in promise) DOMException: The operation is insecure.
Install Monolog and start recording the activity taking place on the server. Probably a good starting point for the time being is just writing the new connections into the log.
This issue is intended to practice software architecture skills as well as unit testing.
As you may have noted, there's a one-to-one correspondence between the Chess\Game
methods described in the PHP Chess Docs and the commands available in the chess server:
ascii(): string
<-> ChessServer\Command\AsciiCommand.php
captures(): array
<-> ChessServer\Command\CapturesCommand.php
castling(): ?array
<-> ChessServer\Command\CastlingCommand.php
All commands should be unit tested in the ChessServer\Tests\Unit\Command
namespace; however, the ChessServer\Tests\Unit\Command\AsciiTest.php
file is missing at the present moment.
The missing file should be added as per the existing conventions.
Happy learning and coding!
This issue is intended to practice software architecture skills as well as unit testing.
As you may have noted, there's a one-to-one correspondence between the Chess\Game
methods described in the PHP Chess Docs and the commands available in the chess server:
ascii(): string
<-> ChessServer\Command\AsciiCommand.php
captures(): array
<-> ChessServer\Command\CapturesCommand.php
castling(): ?array
<-> ChessServer\Command\CastlingCommand.php
All commands should be unit tested in ChessServer\Tests\Unit\Command
. However, the ChessServer\Tests\Unit\Command\FenTest.php
file is missing.
The missing file should be added as per the existing conventions.
Happy learning and coding!
The chess server will complain with the following PHP notices after trying to load foo
as a FEN string:
$ php cli/ws-server.php
Welcome to PHP Chess Server
Commands available:
/accept {"id":"id"} Accepts a friend request to play a game.
/ascii Prints the ASCII representation of the game.
/castling Gets the castling status.
/captures Gets the pieces captured by both players.
/fen Prints the FEN string representation of the game.
/heuristicpicture Takes a balanced heuristic picture of the current game.
/history The current game's history.
/ischeck Finds out if the game is in check.
/ismate Finds out if the game is over.
/piece {"position":"string"} Gets a piece by its position on the board.
/pieces {"color":["w","b"]} Gets the pieces on the board by color.
/playfen {"fen":"string"} Plays a chess move in shortened FEN format.
/quit Quits a game.
/start {"mode":["analysis","loadfen","playfriend"],"fen":"string","color":["w","b"],"min":"int"} Starts a new game.
/status The current game status.
Listening to commands...
PHP Notice: Undefined offset: 2 in /home/standard/projects/chess-server/vendor/chesslablab/php-chess/src/FEN/StringToBoard.php on line 89
PHP Notice: Undefined offset: 2 in /home/standard/projects/chess-server/vendor/chesslablab/php-chess/src/FEN/StringToBoard.php on line 95
PHP Notice: Undefined offset: 2 in /home/standard/projects/chess-server/vendor/chesslablab/php-chess/src/FEN/StringToBoard.php on line 95
PHP Notice: Undefined offset: 1 in /home/standard/projects/chess-server/vendor/chesslablab/php-chess/src/FEN/StringToBoard.php on line 52
PHP Notice: Undefined offset: 2 in /home/standard/projects/chess-server/vendor/chesslablab/php-chess/src/FEN/StringToBoard.php on line 52
PHP Notice: Undefined offset: 3 in /home/standard/projects/chess-server/vendor/chesslablab/php-chess/src/FEN/StringToBoard.php on line 52
A new command to allow offering a draw should be implemented similarly as with ChessServer\Command\TakebackCommand.
Now that the online games are broadcast to all connected clients as described in both cli/ws-server.php and cli/wss-server.php, ChessServer\Command\OnlineGamesCommand can be removed.
Keep it up, and happy coding and learning!
The new command should be called /heuristicpicture
.
For further information, please visit:
At the present moment, the chess server can differentiate among these game modes:
src/GameMode/AnalysisMode.php
src/GameMode/LoadFenMode.php
src/GameMode/PlayFriendMode.php
However, a new game mode needs to be added to allow loading PGN games:
src/GameMode/LoadPgnMode.php
Keep it up, and happy learning!
See:
At the present moment, the Chess\Game
class can differentiate between two different modes:
MODE_AI
MODE_ANALYSIS
However, a third game mode needs to be added:
MODE_FEN
Keep it up, and happy learning!
The command should be used as it is described in the following example.
/start fen "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
The word Command
should be appended to all files in the ChessServer\Tests\Unit\Command
namespace as it is described next:
CapturesCommandTest.php
HistoryCommandTest.php
IsCheckCommandTest.php
UndoMoveCommandTest.php
This issue is intended to practice software architecture skills as well as unit testing.
As you may have noted, there's a one-to-one correspondence between the Chess\Game
methods described in the PHP Chess docs and the commands available in the chess server:
ascii(): string
<-> ChessServer\Command\AsciiCommand.php
captures(): array
<-> ChessServer\Command\CapturesCommand.php
castling(): ?array
<-> ChessServer\Command\CastlingCommand.php
However, the ChessServer\Command\EventsCommand.php
is missing.
The missing file should be added. Also, the corresponding unit test should be written in the tests/unit/Command
folder as per the existing conventions.
Happy learning and coding!
Once the /rematch
command has been successfully added, a new command should be implemented now in order to allow restarting a game if accepting a rematch. The /restart
command is to be used by passing the hash of the game as an argument as described in the example below.
/restart 51e2e0b55f862b69e0f6fad3951b44c1
See:
Happy learning and coding!
At the present moment, the chess server can differentiate among these game modes:
src/GameMode/AnalysisMode.php
src/GameMode/LoadFenMode.php
src/GameMode/LoadPgnMode.php
src/GameMode/PlayFriendMode.php
However, a new game mode needs to be added to allow playing chess like a grandmaster:
src/GameMode/GrandmasterMode.php
Keep it up, and happy learning!
See:
The $dependsOn
property should be updated in all files in the ChessServer\Command
namespace depending on the StartCommand
.
src/Command/AcceptFriendRequestCommand.php
src/Command/AsciiCommand.php
src/Command/StatusCommand.php
Specifically, Start::class
should be replaced with StartCommand::class
as it is shown in the following example.
<?php
namespace ChessServer\Command;
class AsciiCommand extends AbstractCommand
{
public function __construct()
{
$this->name = '/ascii';
$this->description = 'Prints the ASCII representation of the game.';
$this->dependsOn = [
StartCommand::class,
];
}
public function validate(array $argv)
{
return count($argv) - 1 === 0;
}
}
Happy learning and coding!
Keep it up.
The invitation token is a JWT token, which is quite unmanageable for users to copypaste and share.
Review the server's responses since they all should follow the same convention. So for example, any response should return the name of the command run e.g., start
, rather than a generic keyword e.g., message
.
I've had some problems with the setup:
composer install
can only be run using PHP 7.4, it will not run on PHP 8.
I'm happy to bump PHPUnit to 9.5, which will give PHP 7.4 & PHP 8. I can fix the deprecated annotation(s) for expecting exceptions, is this Ok? Would you be willing to tag with Hacktoberfest?
At the present moment, the ChessServer\Socket
class can differentiate among three different modes:
MODE_AI
MODE_ANALYSIS
MODE_LOAD_FEN
However, a fourth game mode should be used as well:
MODE_PLAY_FRIEND
Keep it up, and happy learning!
At the present moment, when a player sends the /undomove
command to the server their opponent won't receive any confirmation from it and won't be able to undo the move accordingly. This is because by default the Socket.php sends a message to one player only as it is described in the code below.
<?php
namespace ChessServer;
..
class Socket implements MessageComponentInterface
{
...
public function onMessage(ConnectionInterface $from, $msg)
{
...
if (is_a($cmd, AcceptFriendRequestCommand::class)) {
if ($gameMode = $this->findGameMode($this->parser->argv[1])) {
if ($this->syncGameModeWith($gameMode, $from)) {
$jwt = $gameMode->getJwt();
$decoded = JWT::decode($jwt, $_ENV['JWT_SECRET'], array('HS256'));
return $this->sendToMany($gameMode->getResourceIds(), [
$cmd->name => [
'jwt' => $jwt,
'hash' => md5($jwt),
],
]);
}
}
return $this->sendToOne($from->resourceId, [
$cmd->name => [
'mode' => PlayFriendMode::NAME,
'message' => 'This friend request could not be accepted.',
],
]);
} elseif (is_a($cmd, DrawCommand::class)) {
if (is_a($gameMode, PlayFriendMode::class)) {
return $this->sendToMany(
$gameMode->getResourceIds(),
$gameMode->res($this->parser->argv, $cmd)
);
}
} elseif (is_a($cmd, PlayFenCommand::class)) {
...
} elseif (is_a($cmd, QuitCommand::class)) {
...
} elseif (is_a($cmd, ResignCommand::class)) {
...
} elseif (is_a($cmd, StartCommand::class)) {
...
} elseif (is_a($cmd, TakebackCommand::class)) {
...
} elseif ($gameMode) {
return $this->sendToOne(
$from->resourceId,
$this->gameModes[$from->resourceId]->res($this->parser->argv, $cmd)
);
}
}
...
}
Thus, the UndoMoveCommand
should be added to the main if
statement in a similar way as with DrawCommand
in that the response needs to be sent to both players.
Described below is the sequence of commands that would allow Bob to propose a takeback to Alice after playing 1.e4 e5
.
Alice:
$ websocat ws://localhost:8080
/start playfriend w 10
{"\/start":{"mode":"playfriend","jwt":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwY2hlc3MubmV0IiwiaWF0IjoxNjMyOTI4OTY4LCJjb2xvciI6InciLCJtaW4iOiIxMCIsImV4cCI6MTYzMjkyOTU2OH0.KAlahRGFjyg2NF7o7xlh4nV4HrcFng9JhM65IeiPPOQ","hash":"b9bef730966d51284303d9054d33fabb"}}
{"\/accept":{"jwt":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwY2hlc3MubmV0IiwiaWF0IjoxNjMyOTI4OTY4LCJjb2xvciI6InciLCJtaW4iOiIxMCIsImV4cCI6MTYzMjkyOTU2OH0.KAlahRGFjyg2NF7o7xlh4nV4HrcFng9JhM65IeiPPOQ","hash":"b9bef730966d51284303d9054d33fabb"}}
/playfen "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b"
{"\/playfen":{"turn":"w","legal":true,"check":false,"mate":false,"movetext":"1.e4","fen":"rnbqkbnr\/pppppppp\/8\/8\/4P3\/8\/PPPP1PPP\/RNBQKBNR b KQkq e3"}}
{"\/playfen":{"turn":"b","legal":true,"check":false,"mate":false,"movetext":"1.e4 e5","fen":"rnbqkbnr\/pppp1ppp\/8\/4p3\/4P3\/8\/PPPP1PPP\/RNBQKBNR w KQkq e6"}}
{"\/takeback":"propose"}
/takeback accept
{"\/takeback":"accept"}
Bob:
$ websocat ws://localhost:8080
/accept b9bef730966d51284303d9054d33fabb
{"\/accept":{"jwt":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwY2hlc3MubmV0IiwiaWF0IjoxNjMyOTI4OTY4LCJjb2xvciI6InciLCJtaW4iOiIxMCIsImV4cCI6MTYzMjkyOTU2OH0.KAlahRGFjyg2NF7o7xlh4nV4HrcFng9JhM65IeiPPOQ","hash":"b9bef730966d51284303d9054d33fabb"}}
{"\/playfen":{"turn":"w","legal":true,"check":false,"mate":false,"movetext":"1.e4","fen":"rnbqkbnr\/pppppppp\/8\/8\/4P3\/8\/PPPP1PPP\/RNBQKBNR b KQkq e3"}}
/playfen "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w"
{"\/playfen":{"turn":"b","legal":true,"check":false,"mate":false,"movetext":"1.e4 e5","fen":"rnbqkbnr\/pppp1ppp\/8\/4p3\/4P3\/8\/PPPP1PPP\/RNBQKBNR w KQkq e6"}}
/takeback propose
{"\/takeback":"propose"}
{"\/takeback":"accept"}
/undomove
{"\/undomove":true}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.