Passed
Push — master ( c241db...a6f3d5 )
by Thijs
02:46
created

Engine   A

Complexity

Total Complexity 4

Size/Duplication

Total Lines 42
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 4
lcom 1
cbo 4
dl 0
loc 42
ccs 15
cts 15
cp 1
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A decide() 0 17 3
1
<?php
2
3
namespace lucidtaz\minimax\engine;
4
5
use BadMethodCallException;
6
use lucidtaz\minimax\game\Decision;
7
use lucidtaz\minimax\game\GameState;
8
use lucidtaz\minimax\game\Player;
9
use RuntimeException;
10
11
/**
12
 * MiniMax game engine
13
 *
14
 * Construct an object of this class, give it the player to optimize for, and
15
 * call decide() when it is time for the player to make a move, in order to get
16
 * the Decision that the engine has taken for the player.
17
 */
18
class Engine
19
{
20
    private $objectivePlayer;
21
22
    private $maxDepth;
23
24
    /**
25
     * @param Player $objectivePlayer The player to play as
26
     * @param int $maxDepth How far ahead should the engine look?
27
     */
28 13
    public function __construct(Player $objectivePlayer, int $maxDepth = 3)
29
    {
30 13
        $this->objectivePlayer = $objectivePlayer;
31 13
        $this->maxDepth = $maxDepth;
32 13
    }
33
34
    /**
35
     * Evaluate possible decisions and take the best one
36
     * @param GameState $state Current state of the game for which there needs
37
     * to be made a decision. This implicitly means that the objective player
38
     * currently must have its turn in the GameState.
39
     * @return Decision The decision taken by the engine, to be manually applied
40
     * to the GameState
41
     */
42 13
    public function decide(GameState $state): Decision
43
    {
44 13
        if (!$state->getNextPlayer()->equals($this->objectivePlayer)) {
45 1
            throw new BadMethodCallException('It is not this players turn');
46
        }
47 12
        $topLevelNode = new DecisionPoint(
48 12
            $this->objectivePlayer,
49
            $state,
50 12
            $this->maxDepth,
51 12
            DecisionWithScore::getBestComparator()
52
        );
53 12
        $decisionWithScore = $topLevelNode->decide();
54 12
        if ($decisionWithScore->decision === null) {
55 1
            throw new RuntimeException('There are no possible moves');
56
        }
57 11
        return $decisionWithScore->decision;
58
    }
59
}
60