Completed
Push — master ( 26fe90...eb810e )
by Jérémy
03:39
created

Calculator::calculate()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 28
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 21
nc 1
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/*
4
 * (c) Jérémy Marodon <[email protected]>
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Th3Mouk\PokemonGoIVCalculator\Calculator;
10
11
use Illuminate\Support\Collection;
12
use Th3Mouk\PokemonGoIVCalculator\Entities\IvCombinaison;
13
use Th3Mouk\PokemonGoIVCalculator\Entities\Level;
14
use Th3Mouk\PokemonGoIVCalculator\Entities\Pokemon;
15
use Th3Mouk\PokemonGoIVCalculator\Entities\StaminaLevelCombinaison;
16
use Th3Mouk\PokemonGoIVCalculator\Extractors\LevelExtractor;
17
use Th3Mouk\PokemonGoIVCalculator\Extractors\Pokedex;
18
19
class Calculator
20
{
21
    private const AVAILABLE_OPTIONS = ['atk', 'def', 'hp'];
22
23
    private $attack_range;
24
    private $defense_range;
25
    private $stamina_range;
26
27
    /**
28
     * @var Collection
29
     */
30
    private $potentialLevels;
31
32
    /**
33
     * @var Collection
34
     */
35
    private $potentialStamina;
36
37
    /**
38
     * @var Collection
39
     */
40
    private $potentialCombinaisons;
41
42
    /**
43
     * Calculator constructor.
44
     */
45
    public function __construct()
46
    {
47
        $this->attack_range = range(0, 15);
48
        $this->defense_range = range(0, 15);
49
        $this->stamina_range = range(0, 15);
50
51
        $this->potentialLevels = new Collection();
52
        $this->potentialStamina = new Collection();
53
        $this->potentialCombinaisons = new Collection();
54
    }
55
56
    public function calculate(
57
        string $pokemonName,
58
        int $cp,
59
        int $hp,
60
        int $dusts,
61
        int $global,
62
        int $maxStat,
63
        array $bestStats,
64
        bool $upgraded = false
65
    ): Pokemon {
66
        $pokemon = (new Pokedex())->get($pokemonName);
67
68
        $pokemon->setCp($cp);
69
        $pokemon->setHp($hp);
70
71
        $this->setRanges($bestStats, $maxStat);
72
73
        $this->potentialLevels = (new LevelExtractor())->getDustFiltered($dusts);
74
75
        $this
76
            ->findPotentialStamina($pokemon, $hp, $upgraded)
77
            ->findPotentialCombinaisons($pokemon, $cp)
78
            ->cleanImpossibleCombinaisons($bestStats, $global);
79
80
        $pokemon->setIvCombinaisons($this->potentialCombinaisons);
81
82
        return $pokemon;
83
    }
84
85
    /**
86
     * @param Pokemon $pokemon
87
     * @param int $hp
88
     *
89
     * @param bool $upgraded
90
     * @return $this
91
     */
92
    private function findPotentialStamina(
93
        Pokemon $pokemon,
94
        int $hp,
95
        bool $upgraded
96
    ) {
97
        foreach ($this->potentialLevels as $data) {
98
            $level = new Level(
99
                $data->level, $data->dust, $data->cpScalar, $upgraded
100
            );
101
102
            foreach ($this->stamina_range as $staminaIV) {
103
                if ($this->testHP($pokemon, $level, $hp, $staminaIV)) {
104
                    $combinaison = new StaminaLevelCombinaison(
105
                        $level,
106
                        $staminaIV
107
                    );
108
                    $this->potentialStamina->push($combinaison);
109
                }
110
            }
111
        }
112
113
        return $this;
114
    }
115
116
    /**
117
     * @param Pokemon $pokemon
118
     * @param int $cp
119
     * @return $this
120
     */
121
    private function findPotentialCombinaisons(Pokemon $pokemon, int $cp)
122
    {
123
        foreach ($this->potentialStamina as $staminaCombinaison) {
124
            foreach ($this->attack_range as $attackIV) {
125
                foreach ($this->defense_range as $defenseIV) {
126
                    if ($this->testCP(
127
                        $pokemon,
128
                        $staminaCombinaison->getLevel(),
129
                        $cp,
130
                        $attackIV,
131
                        $defenseIV,
132
                        $staminaCombinaison->getStamina())
133
                    ) {
134
                        $combinaison = new IvCombinaison(
135
                            $staminaCombinaison->getLevel(),
136
                            $attackIV,
137
                            $defenseIV,
138
                            $staminaCombinaison->getStamina()
139
                        );
140
141
                        $this->potentialCombinaisons->push($combinaison);
142
                    }
143
                }
144
            }
145
        }
146
147
        return $this;
148
    }
149
150
    private function cleanImpossibleCombinaisons(array $bestStats, int $global)
151
    {
152
        $this->potentialCombinaisons = $this->potentialCombinaisons
153
            // Eliminate impossible combinaison for global combinaison
154
            ->filter(function ($combinaison) use ($global) {
155
                if ($combinaison->getTotal() < $this->getMaxGlobalEvaluation($global)) {
156
                    return true;
157
                }
158
                return false;
159
            })
160
            // Eliminate impossible combinaisons with best stats
161
            ->filter(function ($combinaison) use ($bestStats) {
162
                $nonBestStats = array_diff(self::AVAILABLE_OPTIONS, $bestStats);
163
                foreach ($nonBestStats as $nonBestStat) {
164
                    if ($combinaison->getAbbreviated($nonBestStat) < $combinaison->getMaximalIv()) {
165
                        return true;
166
                    }
167
                    return false;
168
                }
169
            });
170
        return $this;
171
    }
172
173
    private function setRanges(array $bestStats, int $maxStat)
174
    {
175
        $this->setRange($bestStats, $maxStat, 'atk', $this->attack_range);
176
        $this->setRange($bestStats, $maxStat, 'def', $this->defense_range);
177
        $this->setRange($bestStats, $maxStat, 'hp', $this->stamina_range);
178
    }
179
180
    private function setRange($bestStats, $maxStat, $option, &$property)
181
    {
182
        if (in_array($option, $bestStats)) {
183
            $property = $this->getMaxRange($maxStat);
184
        } else {
185
            $property = $this->getLowerRange($maxStat);
186
        }
187
    }
188
189
    /**
190
     * @param Pokemon $pokemon
191
     * @param Level $level
192
     * @param int $cp
193
     * @param int $attackIV
194
     * @param int $defenseIV
195
     * @param int $staminaIV
196
     * @return bool
197
     */
198
    private function testCP(
199
        Pokemon $pokemon,
200
        Level $level,
201
        int $cp,
202
        int $attackIV,
203
        int $defenseIV,
204
        int $staminaIV
205
    ) {
206
        $attackFactor = $pokemon->getBaseAttack() + $attackIV;
207
        $defenseFactor = pow($pokemon->getBaseDefense() + $defenseIV, 0.5);
208
        $staminaFactor = pow($pokemon->getBaseStamina() + $staminaIV, 0.5);
209
        $scalarFactor = pow($level->getCpScalar(), 2);
210
211
        return $cp == floor($attackFactor * $defenseFactor * $staminaFactor * $scalarFactor / 10);
212
    }
213
214
    /**
215
     * @param Pokemon $pokemon
216
     * @param Level $level
217
     * @param int $hp
218
     * @param int $staminaIV
219
     * @return bool
220
     */
221
    private function testHP(
222
        Pokemon $pokemon,
223
        Level $level,
224
        int $hp,
225
        int $staminaIV
226
    ) {
227
        return $hp == (int) floor(($pokemon->getBaseStamina() + $staminaIV) * $level->getCpScalar());
228
    }
229
230
    /**
231
     * Return the range of stats given by the coach
232
     * @param int $maxStat
233
     * @return array
234
     */
235
    private function getMaxRange(int $maxStat)
236
    {
237
        switch ($maxStat) {
238
            case 1:
239
                return range(0, 7);
240
            case 2:
241
                return range(8, 12);
242
            case 3:
243
                return range(13, 14);
244
            case 4:
245
                return [15];
246
        };
247
        return range(0, 15);
248
    }
249
250
    /**
251
     * Return the range of stats non cited by the coach
252
     * @param int $maxStat
253
     * @return array
254
     */
255
    private function getLowerRange(int $maxStat)
256
    {
257
        switch ($maxStat) {
258
            case 1:
259
                return range(0, 6);
260
            case 2:
261
                return range(0, 11);
262
            case 3:
263
                return range(0, 13);
264
            case 4:
265
                return range(0, 14);
266
        };
267
        return range(0, 15);
268
    }
269
270
    /**
271
     * Get the threshold of the global evaluation given by the coach
272
     * @param $global
273
     * @return int
274
     */
275
    private function getMaxGlobalEvaluation($global)
276
    {
277
        switch ($global) {
278
            case 1:
279
                // 0-22
280
                return 22;
281
            case 2:
282
                // 23-29
283
                return 29;
284
            case 3:
285
                // 30-36
286
                return 36;
287
        }
288
        // 37-45
289
        return 45;
290
    }
291
292
    /**
293
     * Get attack_range
294
     *
295
     * @return array
296
     */
297
    public function getAttackRange(): array
298
    {
299
        return $this->attack_range;
300
    }
301
302
    /**
303
     * Get defense_range
304
     *
305
     * @return array
306
     */
307
    public function getDefenseRange(): array
308
    {
309
        return $this->defense_range;
310
    }
311
312
    /**
313
     * Get stamina_range
314
     *
315
     * @return array
316
     */
317
    public function getStaminaRange(): array
318
    {
319
        return $this->stamina_range;
320
    }
321
322
    /**
323
     * Get potentialLevels
324
     *
325
     * @return Collection
326
     */
327
    public function getPotentialLevels(): Collection
328
    {
329
        return $this->potentialLevels;
330
    }
331
332
    /**
333
     * Get potentialStamina
334
     *
335
     * @return Collection
336
     */
337
    public function getPotentialStamina(): Collection
338
    {
339
        return $this->potentialStamina;
340
    }
341
342
    /**
343
     * Get potentialCombinaisons
344
     *
345
     * @return Collection
346
     */
347
    public function getPotentialCombinaisons(): Collection
348
    {
349
        return $this->potentialCombinaisons;
350
    }
351
}
352