Completed
Push — master ( 29e2cf...033bf5 )
by Jakub
02:40
created

Team::getLowestHpCharacter()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 16
ccs 11
cts 11
cp 1
rs 9.2222
c 0
b 0
f 0
nc 7
nop 1
cc 6
crap 6
1
<?php
2
declare(strict_types=1);
3
4
namespace HeroesofAbenez\Combat;
5
6
use Nexendrie\Utils\Collection;
7
use Nexendrie\Utils\Numbers;
8
9
/**
10
 * Structure for a team in combat
11
 * 
12
 * @author Jakub Konečný
13
 * @property-read string $name
14
 * @property-read Character[] $aliveMembers
15
 * @property-read Character[] $usableMembers
16
 * @property int $maxRowSize
17
 * @property-read int|null $rowToAttack
18
 */
19 1
final class Team extends Collection {
20
  protected const LOWEST_HP_THRESHOLD = 0.5;
21
22
  /** @var string */
23
  protected $class = Character::class;
24
  /** @var string Name of the team */
25
  protected $name;
26
  /** @var int */
27
  protected $maxRowSize = 5;
28
  
29 1
  use \Nette\SmartObject;
30
  
31
  public function __construct(string $name) {
32 1
    parent::__construct();
33 1
    $this->name = $name;
34 1
  }
35
  
36
  public function getName(): string {
37 1
    return $this->name;
38
  }
39
  
40
  public function getMaxRowSize(): int {
41 1
    return $this->maxRowSize;
42
  }
43
  
44
  public function setMaxRowSize(int $maxRowSize): void {
45 1
    $this->maxRowSize = Numbers::range($maxRowSize, 1, PHP_INT_MAX);
46 1
  }
47
  
48
  /**
49
   * Get alive members from the team
50
   * 
51
   * @return Character[]
52
   */
53
  public function getAliveMembers(): array {
54 1
    return $this->getItems(["hitpoints>" => 0,]);
55
  }
56
  
57
  /**
58
   * Get members which can perform an action
59
   * 
60
   * @return Character[]
61
   */
62
  public function getUsableMembers(): array {
63 1
    return $this->getItems([
64 1
      "stunned" => false, "hitpoints>" => 0,
65
    ]);
66
  }
67
  
68
  /**
69
   * Check whether the team has at least 1 alive member
70
   */
71
  public function hasAliveMembers(): bool {
72 1
    return count($this->getAliveMembers()) > 0;
73
  }
74
  
75
  /**"hitpoints>" => 0
76
   * Set character's position in team
77
   *
78
   * @param string|int $id
79
   * @throws \OutOfBoundsException
80
   * @throws InvalidCharacterPositionException
81
   */
82
  public function setCharacterPosition($id, int $row, int $column): void {
83 1
    if(!$this->hasItems(["id" => $id])) {
84 1
      throw new \OutOfBoundsException("Character $id is not in the team");
85 1
    } elseif(count($this->getItems(["positionRow" => $row])) >= $this->maxRowSize) {
86 1
      throw new InvalidCharacterPositionException("Row $row is full.", InvalidCharacterPositionException::ROW_FULL);
87 1
    } elseif($this->hasItems(["positionRow" => $row, "positionColumn" => $column])) {
88 1
      throw new InvalidCharacterPositionException("Row $row column $column is occupied.", InvalidCharacterPositionException::POSITION_OCCUPIED);
0 ignored issues
show
introduced by
Line exceeds 120 characters; contains 144 characters
Loading history...
89
    }
90 1
    $character = $this->getItems(["id" => $id])[0];
91 1
    $character->positionRow = $row;
92 1
    $character->positionColumn = $column;
93 1
  }
94
  
95
  public function getRandomCharacter(): ?Character {
96 1
    $characters = $this->aliveMembers;
97 1
    if(count($characters) === 0) {
98 1
      return null;
99 1
    } elseif(count($characters) === 1) {
100 1
      return $characters[0];
101
    }
102 1
    $roll = rand(0, count($characters) - 1);
103 1
    return $characters[$roll];
104
  }
105
  
106
  public function getLowestHpCharacter(float $threshold = self::LOWEST_HP_THRESHOLD): ?Character {
107 1
    $lowestHp = PHP_INT_MAX;
108 1
    $lowestIndex = PHP_INT_MIN;
109 1
    if(count($this->aliveMembers) === 0) {
110 1
      return null;
111
    }
112 1
    foreach($this->aliveMembers as $index => $member) {
113 1
      if($member->hitpoints <= $member->maxHitpoints * $threshold AND $member->hitpoints < $lowestHp) {
114 1
        $lowestHp = $member->hitpoints;
115 1
        $lowestIndex = $index;
116
      }
117
    }
118 1
    if($lowestIndex === PHP_INT_MIN) {
119 1
      return null;
120
    }
121 1
    return $this->aliveMembers[$lowestIndex];
122
  }
123
  
124
  public function getRowToAttack(): ?int {
125 1
    if(count($this->aliveMembers) === 0) {
126 1
      return null;
127
    }
128 1
    for($i = 1; $i <= PHP_INT_MAX; $i++) {
129 1
      if($this->hasItems(["positionRow" => $i, "hitpoints>" => 0,])) {
130 1
        return $i;
131
      }
132
    }
133
  }
134
}
135
?>