Passed
Push — master ( 14728e...fb3e58 )
by Thijs
40s
created

Engine   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 59
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 95.24%

Importance

Changes 0
Metric Value
wmc 6
lcom 1
cbo 6
dl 0
loc 59
ccs 20
cts 21
cp 0.9524
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A decide() 0 21 3
A getAnalytics() 0 7 2
1
<?php
2
3
namespace lucidtaz\minimax\engine;
4
5
use BadMethodCallException;
6
use lucidtaz\minimax\game\GameState;
7
use lucidtaz\minimax\game\Player;
8
use RuntimeException;
9
10
/**
11
 * MiniMax game engine
12
 *
13
 * Construct an object of this class, give it the player to optimize for, and
14
 * call decide() when it is time for the player to make a move, in order to get
15
 * the Decision that the engine has taken for the player.
16
 */
17
class Engine
18
{
19
    private $objectivePlayer;
20
21
    private $maxDepth;
22
23
    /**
24
     * @var ?Analytics Only available after run, contains statistics about the
25
     * execution.
26
     */
27
    private $analytics;
28
29
    /**
30
     * @param Player $objectivePlayer The player to play as
31
     * @param int $maxDepth How far ahead should the engine look?
32
     */
33 15
    public function __construct(Player $objectivePlayer, int $maxDepth = 3)
34
    {
35 15
        $this->objectivePlayer = $objectivePlayer;
36 15
        $this->maxDepth = $maxDepth;
37 15
    }
38
39
    /**
40
     * Evaluate possible decisions and take the best one
41
     * @param GameState $state Current state of the game for which there needs
42
     * to be made a decision. This implicitly means that the objective player
43
     * currently must have its turn in the GameState.
44
     * @return GameState The state resulting after the engine made its decision.
45
     */
46 15
    public function decide(GameState $state): GameState
47
    {
48 15
        if (!$state->getNextPlayer()->equals($this->objectivePlayer)) {
49 1
            throw new BadMethodCallException('It is not this players turn');
50
        }
51 14
        if (empty($state->getPossibleMoves())) {
52 1
            throw new RuntimeException('There are no possible moves');
53
        }
54
55 13
        $rootNode = new DecisionNode(
56 13
            $this->objectivePlayer,
57
            $state,
58 13
            $this->maxDepth,
59 13
            NodeType::MAX(),
60 13
            AlphaBeta::initial()
61
        );
62
63 13
        $moveWithEvaluation = $rootNode->traverseGameTree();
64 13
        $this->analytics = $moveWithEvaluation->analytics;
65 13
        return $moveWithEvaluation->move;
66
    }
67
68 1
    public function getAnalytics(): Analytics
69
    {
70 1
        if ($this->analytics === null) {
71
            throw new BadMethodCallException('Please run decide() first.');
72
        }
73 1
        return $this->analytics;
74
    }
75
}
76