diff --git a/html/index.php b/html/index.php
index 2c0c09d..3ab3363 100644
--- a/html/index.php
+++ b/html/index.php
@@ -2,6 +2,10 @@
require_once '../src/core.php';
+use Engine\GameOutcome;
+use Engine\MinimaxDF;
+use Engine\PieceValues;
+use Engine\WeightedHeuristics;
use Game\Game;
use Game\Move;
@@ -12,7 +16,10 @@ if (isset($_SESSION["game"])) {
$engine = $_SESSION["engine"];
} else {
$game = Game::fromStartPosition();
- $engine = new \Engine\Random();
+ $engine = new MinimaxDF(1, new WeightedHeuristics([
+ [new GameOutcome(), 1.0],
+ [new PieceValues(), 1.0]
+ ]));
$_SESSION["game"] = $game;
$_SESSION["engine"] = $engine;
diff --git a/src/Engine/GameOutcome.php b/src/Engine/GameOutcome.php
new file mode 100644
index 0000000..fc9b651
--- /dev/null
+++ b/src/Engine/GameOutcome.php
@@ -0,0 +1,15 @@
+getGameState()) {
+ GameState::CHECKMATE => -INF,
+ default => 0
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/Engine/Heuristic.php b/src/Engine/Heuristic.php
new file mode 100644
index 0000000..5d7e06c
--- /dev/null
+++ b/src/Engine/Heuristic.php
@@ -0,0 +1,9 @@
+depth = $depth;
+ $this->heuristic = $heuristic;
+ }
+
+ private function findMaxMoveRating(array $moves): array {
+ $max = $moves[0];
+
+ foreach ($moves as $move) {
+ if ($move[1] > $max[1]) {
+ $max = $move;
+ }
+ }
+
+ return $max;
+ }
+
+ private function invertRating(array $move): array {
+ return [$move[0], -$move[1]];
+ }
+
+ private function maxWithHeuristic(Game $game): array {
+ $moves = array_map(fn($move) => [
+ $move,
+ -$this->heuristic->ratePosition($game->apply($move))
+ ], $game->getLegalMoves());
+
+ return $this->findMaxMoveRating($moves);
+ }
+
+ private function maxWithoutHeuristic(Game $game, int $remaindingDepth): array {
+ $moves = array_map(function ($move) use ($game, $remaindingDepth) {
+ $future = $game->apply($move);
+
+ if ($future->getGameState() == GameState::CHECKMATE) {
+ return [$move, INF];
+ }
+
+ $opponentMove = $this->max($future, $remaindingDepth - 1);
+
+ return $this->invertRating([$move, $opponentMove[1]]);
+ }, $game->getLegalMoves());
+
+ foreach ($moves as $move) {
+ error_log($remaindingDepth . ": " . $move[0]->getLong() . ": " . $move[1]);
+ }
+
+ return $this->findMaxMoveRating($moves);
+ }
+
+ private function max(Game $game, int $remaindingDepth): array {
+ if ($remaindingDepth <= 0) {
+ return $this->maxWithHeuristic($game);
+ } else {
+ return $this->maxWithoutHeuristic($game, $remaindingDepth);
+ }
+ }
+
+ public function nextMove(Game $game): Move {
+ return $this->max($game, $this->depth)[0];
+ }
+}
\ No newline at end of file
diff --git a/src/Engine/PieceValues.php b/src/Engine/PieceValues.php
new file mode 100644
index 0000000..2a2bba4
--- /dev/null
+++ b/src/Engine/PieceValues.php
@@ -0,0 +1,30 @@
+getType()) {
+ PieceType::PAWN => 1,
+ PieceType::BISHOP => 3,
+ PieceType::KNIGHT => 3,
+ PieceType::ROOK => 5,
+ PieceType::QUEEN => 9,
+ default => 0,
+ };
+ }
+
+ public function ratePosition(Game $game): float {
+ $ownPieces = $game->getPieces($game->getCurrentSide());
+ $opponentPieces = $game->getPieces($game->getCurrentSide()->getNext());
+
+ $ownValue = array_sum(array_map([$this, "valueOfPiece"], $ownPieces));
+ $opponentValue = array_sum(array_map([$this, "valueOfPiece"], $opponentPieces));
+
+ return $ownValue - $opponentValue;
+ }
+}
\ No newline at end of file
diff --git a/src/Engine/Random.php b/src/Engine/Random.php
index ac83d73..56717aa 100644
--- a/src/Engine/Random.php
+++ b/src/Engine/Random.php
@@ -10,4 +10,4 @@ class Random implements Engine {
$legalMoves = $game->getLegalMoves();
return $legalMoves[array_rand($legalMoves, 1)];
}
-}
\ No newline at end of file
+}
diff --git a/src/Engine/WeightedHeuristics.php b/src/Engine/WeightedHeuristics.php
new file mode 100644
index 0000000..81f6815
--- /dev/null
+++ b/src/Engine/WeightedHeuristics.php
@@ -0,0 +1,25 @@
+heuristics = array_map(fn($heuristicWithWeight) => $heuristicWithWeight[0], $heuristicsWithWeights);
+ $this->weights = array_map(fn($heuristicWithWeight) => $heuristicWithWeight[1], $heuristicsWithWeights);
+ }
+
+ public function ratePosition(Game $game): float {
+ return array_sum(
+ array_map(
+ fn($heuristic, $weight) => $weight * $heuristic->ratePosition($game),
+ $this->heuristics,
+ $this->weights,
+ )
+ );
+ }
+}
\ No newline at end of file