Completed
Push — master ( cb21fe...1dfedc )
by Jakub
02:59
created

Team::getRandomCharacter()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

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