Skip to content

Commit

Permalink
Merge pull request #397 from chesslablab/issue/384-Parallelize-the-st…
Browse files Browse the repository at this point in the history
…ockfish-command

Issue/384 parallelize the stockfish command
  • Loading branch information
programarivm authored Oct 3, 2024
2 parents b1dcc5d + 9f8da51 commit 02897b1
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 70 deletions.
2 changes: 1 addition & 1 deletion src/Command/Game/Cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function __construct(Pool $pool, Db $db)
$this->commands->attach(new ResignCommand($db));
$this->commands->attach(new RestartCommand($db));
$this->commands->attach(new StartCommand($db));
$this->commands->attach(new StockfishCommand());
$this->commands->attach((new StockfishCommand())->setPool($pool));
$this->commands->attach(new TutorFenCommand());
}

Expand Down
36 changes: 2 additions & 34 deletions src/Command/Game/Game.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

namespace ChessServer\Command\Game;

use Chess\Computer\GrandmasterMove;
use Chess\UciEngine\UciEngine;
use Chess\UciEngine\Details\Limit;
use Chess\Variant\AbstractBoard;
use Chess\Variant\Chess960\Board as Chess960Board;
use Chess\Variant\Chess960\StartPosition as Chess960StartPosition;
Expand Down Expand Up @@ -33,20 +30,14 @@ class Game

private string $mode;

private null|GrandmasterMove $gmMove;

private string $resignation = '';

private string $abandoned = '';

public function __construct(
string $variant,
string $mode,
null|GrandmasterMove $gmMove = null
) {
public function __construct(string $variant, string $mode)
{
$this->variant = $variant;
$this->mode = $mode;
$this->gmMove = $gmMove;

if ($this->variant === self::VARIANT_960) {
$startPos = (new Chess960StartPosition())->create();
Expand Down Expand Up @@ -123,29 +114,6 @@ public function state(): object
];
}

public function computer(array $options = [], array $params = []): ?array
{
if ($this->gmMove) {
if ($move = $this->gmMove->move($this->board)) {
return $move;
}
}

$limit = new Limit();
$limit->depth = $params['depth'];
$stockfish = (new UciEngine('/usr/games/stockfish'))->setOption('Skill Level', $options['Skill Level']);
$analysis = $stockfish->analysis($this->board, $limit);

$clone = $this->board->clone();
$clone->playLan($this->board->turn, $analysis['bestmove']);
$history = $clone->history;
$end = end($history);

return [
'pgn' => $end['move']['pgn'],
];
}

public function play(string $color, string $pgn): bool
{
return $this->board->play($color, $pgn);
Expand Down
17 changes: 1 addition & 16 deletions src/Command/Game/Mode/AbstractMode.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use ChessServer\Command\Game\Game;
use ChessServer\Command\Game\LegalCommand;
use ChessServer\Command\Game\PlayLanCommand;
use ChessServer\Command\Game\StockfishCommand;
use ChessServer\Command\Game\UndoCommand;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
Expand Down Expand Up @@ -91,21 +90,7 @@ public function res($params, $cmd)
'isValid' => $isValid,
],
];

case StockfishCommand::class:
if (!isset($this->game->state()->end)) {
$computer = $this->game->computer($params['options'], $params['params']);
if ($computer['pgn']) {
$this->game->play($this->game->state()->turn, $computer['pgn']);
}
}
return [
$cmd->name => [
...(array) $this->game->state(),
'variant' => $this->game->getVariant(),
],
];


case UndoCommand::class:
$board = $this->game->getBoard()->undo();
$this->game->setBoard($board);
Expand Down
2 changes: 1 addition & 1 deletion src/Command/Game/StartCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public function run(AbstractSocket $socket, array $argv, int $id)
$board = FenToBoardFactory::create($params['settings']['fen'], new ClassicalBoard());
$game = (new Game($params['variant'], $params['mode']))->setBoard($board);
} else {
$game = new Game($params['variant'], $params['mode'], $socket->getGmMove());
$game = new Game($params['variant'], $params['mode']);
}
$payload = [
'iss' => $_ENV['JWT_ISS'],
Expand Down
52 changes: 52 additions & 0 deletions src/Command/Game/StockfishAsyncTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace ChessServer\Command\Game;

use Chess\Computer\GrandmasterMove;
use Chess\UciEngine\UciEngine;
use Chess\UciEngine\Details\Limit;
use Chess\Variant\Classical\Board;
use ChessServer\Socket\AbstractSocket;
use Spatie\Async\Task;

class StockfishAsyncTask extends Task
{
private array $params;

private Board $board;

private GrandmasterMove $gmMove;

public function __construct($params, $board)
{
$this->params = $params;
$this->board = $board;
}

public function configure()
{
$this->gmMove = new GrandmasterMove(AbstractSocket::DATA_FOLDER.'/players.json');
}

public function run()
{
if ($move = $this->gmMove->move($this->board)) {
return $move;
}

$limit = new Limit();
$limit->depth = $this->params['params']['depth'];
$stockfish = (new UciEngine('/usr/games/stockfish'))
->setOption('Skill Level', $this->params['options']['Skill Level']);
$analysis = $stockfish->analysis($this->board, $limit);

$clone = $this->board->clone();
$clone->playLan($this->board->turn, $analysis['bestmove']);
$history = $clone->history;
$end = end($history);

return [
'pgn' => $end['move']['pgn'],
];
}
}
19 changes: 15 additions & 4 deletions src/Command/Game/StockfishCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,21 @@ public function validate(array $argv)
public function run(AbstractSocket $socket, array $argv, int $id)
{
$params = json_decode(stripslashes($argv[1]), true);
$gameMode = $socket->getGameModeStorage()->getById($id);
$game = $socket->getGameModeStorage()->getById($id)->getGame();

return $socket->getClientStorage()->send([$id],
$gameMode->res($params, $this)
);
if (!isset($game->state()->end)) {
$this->pool->add(new StockfishAsyncTask($params, $game->getBoard()))
->then(function ($result) use ($socket, $id, $game) {
if ($result['pgn']) {
$game->play($game->state()->turn, $result['pgn']);
}
return $socket->getClientStorage()->send([$id], [
$this->name => [
...(array) $game->state(),
'variant' => $game->getVariant(),
],
]);
});
}
}
}
7 changes: 0 additions & 7 deletions src/Socket/Ratchet/GameWebSocket.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace ChessServer\Socket\Ratchet;

use Chess\Computer\GrandmasterMove;
use ChessServer\Command\Parser;
use ChessServer\Command\Game\GameModeStorage;
use ChessServer\Socket\DbReconnectTrait;
Expand All @@ -20,15 +19,9 @@ public function __construct(Parser $parser)
$this->reconnect();
});

$this->gmMove = new GrandmasterMove(self::DATA_FOLDER.'/players.json');
$this->gameModeStorage = new GameModeStorage();
}

public function getGmMove(): GrandmasterMove
{
return $this->gmMove;
}

public function getGameModeStorage(): GameModeStorage
{
return $this->gameModeStorage;
Expand Down
7 changes: 0 additions & 7 deletions src/Socket/Workerman/GameWebSocket.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace ChessServer\Socket\Workerman;

use Chess\Computer\GrandmasterMove;
use ChessServer\Command\Parser;
use ChessServer\Command\Game\GameModeStorage;
use ChessServer\Socket\DbReconnectTrait;
Expand All @@ -26,17 +25,11 @@ public function __construct(string $socketName, array $context, Parser $parser)
});
};

$this->gmMove = new GrandmasterMove(self::DATA_FOLDER.'/players.json');
$this->gameModeStorage = new GameModeStorage();

$this->connect()->message()->error()->close();
}

public function getGmMove(): GrandmasterMove
{
return $this->gmMove;
}

public function getGameModeStorage(): GameModeStorage
{
return $this->gameModeStorage;
Expand Down

0 comments on commit 02897b1

Please sign in to comment.