Passed
Push — main ( d28073...f4e9d2 )
by Jesse
01:39
created

PuzzleSolverFactory::add()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 12
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Stratadox\PuzzleSolver;
4
5
use Stratadox\PuzzleSolver\SearchStrategy\BestFirstStrategyFactory;
6
use Stratadox\PuzzleSolver\SearchStrategy\BreadthFirstStrategyFactory;
7
use Stratadox\PuzzleSolver\SearchStrategy\DebugLoggerFactory;
8
use Stratadox\PuzzleSolver\SearchStrategy\DepthFirstStrategyFactory;
9
use Stratadox\PuzzleSolver\SearchStrategy\DuplicateNodeSkipperFactory;
10
use Stratadox\PuzzleSolver\SearchStrategy\SearchStrategyFactory;
11
use Stratadox\PuzzleSolver\SearchStrategy\VisitedNodeCostCheckerFactory;
12
use Stratadox\PuzzleSolver\SearchStrategy\VisitedNodeSkipperFactory;
13
use Stratadox\PuzzleSolver\SearchStrategy\WorseThanBestSolutionSkipperFactory;
14
use Stratadox\PuzzleSolver\Solver\EagerSolver;
15
use Stratadox\PuzzleSolver\Solver\LazySolver;
16
17
/**
18
 * Factory for @see PuzzleSolver
19
 *
20
 * @author Stratadox
21
 */
22
final class PuzzleSolverFactory implements SolverFactory
23
{
24
    public function forAPuzzleWith(
25
        PuzzleDescription $puzzle,
26
        SearchSettings $settings
27
    ): PuzzleSolver {
28
        return $puzzle->singleSolution() ?
29
            EagerSolver::using($this->add($settings, $this->eagerStrategy($puzzle))) :
30
            LazySolver::using($this->add($settings, $this->lazyStrategy($puzzle)));
31
    }
32
33
    private function add(
34
        SearchSettings $settings,
35
        SearchStrategyFactory $strategyFactory
36
    ): SearchStrategyFactory {
37
        if (null === $settings->loggingFile()) {
38
            return $strategyFactory;
39
        }
40
        return DebugLoggerFactory::make(
41
            $settings->iterationInterval(),
42
            $strategyFactory,
43
            $settings->logSeparator(),
44
            $settings->loggingFile()
45
        );
46
    }
47
48
    /**
49
     * Retrieves the eagerStrategy, based on the current description.
50
     *
51
     * @return SearchStrategyFactory
52
     *
53
     * @todo Add more test puzzles that require a single solution, to challenge
54
     *       the assumptions currently made.
55
     */
56
    private function eagerStrategy(PuzzleDescription $puzzle): SearchStrategyFactory
57
    {
58
        if (null !== $puzzle->heuristic()) {
59
            return VisitedNodeCostCheckerFactory::using(
60
                BestFirstStrategyFactory::withHeuristic($puzzle->heuristic())
61
            );
62
        }
63
        if ($puzzle->isWeightedMoves()) {
64
            return VisitedNodeCostCheckerFactory::using(
65
                BestFirstStrategyFactory::noHeuristic()
66
            );
67
        }
68
        return VisitedNodeSkipperFactory::using(
69
            $puzzle->isExhausting() ?
70
                DepthFirstStrategyFactory::make() :
71
                BreadthFirstStrategyFactory::make()
72
        );
73
    }
74
75
    /**
76
     * Retrieves the lazyStrategy, based on the current description.
77
     *
78
     * @return SearchStrategyFactory
79
     *
80
     * @todo Add more test puzzles that require multiple solutions, to challenge
81
     *       the assumptions currently made.
82
     */
83
    private function lazyStrategy(PuzzleDescription $puzzle): SearchStrategyFactory
84
    {
85
        if ($puzzle->isExhausting()) {
86
            return VisitedNodeSkipperFactory::using(
87
                DepthFirstStrategyFactory::make()
88
            );
89
        }
90
        if ($puzzle->onlyBest()) {
91
            return WorseThanBestSolutionSkipperFactory::using(
92
                BreadthFirstStrategyFactory::make()
93
            );
94
        }
95
        return DuplicateNodeSkipperFactory::using(
96
            DepthFirstStrategyFactory::make()
97
        );
98
    }
99
}
100