Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Failed Conditions
Push — live ( 5fc72e...903a76 )
by Dan
07:31 queued 02:29
created

SmrGalaxy::clearCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 1
b 0
f 1
1
<?php declare(strict_types=1);
2
class SmrGalaxy {
3
4
	protected static array $CACHE_GALAXIES = [];
5
	protected static array $CACHE_GAME_GALAXIES = [];
6
7
	public const TYPE_RACIAL = 'Racial';
8
	public const TYPE_NEUTRAL = 'Neutral';
9
	public const TYPE_PLANET = 'Planet';
10
	public const TYPES = [self::TYPE_RACIAL, self::TYPE_NEUTRAL, self::TYPE_PLANET];
11
12
	protected Smr\Database $db;
13
	protected string $SQL;
14
15
	protected int $gameID;
16
	protected int $galaxyID;
17
	protected string $name;
18
	protected int $width;
19
	protected int $height;
20
	protected string $galaxyType;
21
	protected int $maxForceTime;
22
23
	protected int $startSector;
24
25
	protected bool $hasChanged = false;
26
	protected bool $isNew = false;
27
28
	public static function clearCache(): void {
29
		self::$CACHE_GALAXIES = [];
30
		self::$CACHE_GAME_GALAXIES = [];
31
	}
32
33
	public static function getGameGalaxies(int $gameID, bool $forceUpdate = false): array {
34
		if ($forceUpdate || !isset(self::$CACHE_GAME_GALAXIES[$gameID])) {
35
			$db = Smr\Database::getInstance();
36
			$dbResult = $db->read('SELECT * FROM game_galaxy WHERE game_id = ' . $db->escapeNumber($gameID) . ' ORDER BY galaxy_id ASC');
37
			$galaxies = [];
38
			foreach ($dbResult->records() as $dbRecord) {
39
				$galaxyID = $dbRecord->getInt('galaxy_id');
40
				$galaxies[$galaxyID] = self::getGalaxy($gameID, $galaxyID, $forceUpdate, $dbRecord);
41
			}
42
			self::$CACHE_GAME_GALAXIES[$gameID] = $galaxies;
43
		}
44
		return self::$CACHE_GAME_GALAXIES[$gameID];
45
	}
46
47
	public static function getGalaxy(int $gameID, int $galaxyID, bool $forceUpdate = false, Smr\DatabaseRecord $dbRecord = null): self {
48
		if ($forceUpdate || !isset(self::$CACHE_GALAXIES[$gameID][$galaxyID])) {
49
			$g = new self($gameID, $galaxyID, false, $dbRecord);
50
			self::$CACHE_GALAXIES[$gameID][$galaxyID] = $g;
51
		}
52
		return self::$CACHE_GALAXIES[$gameID][$galaxyID];
53
	}
54
55
	public static function saveGalaxies(): void {
56
		foreach (self::$CACHE_GALAXIES as $gameGalaxies) {
57
			foreach ($gameGalaxies as $galaxy) {
58
				$galaxy->save();
59
			}
60
		}
61
	}
62
63
	public static function createGalaxy(int $gameID, int $galaxyID): self {
64
		if (!isset(self::$CACHE_GALAXIES[$gameID][$galaxyID])) {
65
			$g = new self($gameID, $galaxyID, true);
66
			self::$CACHE_GALAXIES[$gameID][$galaxyID] = $g;
67
		}
68
		return self::$CACHE_GALAXIES[$gameID][$galaxyID];
69
	}
70
71
	protected function __construct(int $gameID, int $galaxyID, bool $create = false, Smr\DatabaseRecord $dbRecord = null) {
72
		$this->db = Smr\Database::getInstance();
73
		$this->SQL = 'game_id = ' . $this->db->escapeNumber($gameID) . '
74
		              AND galaxy_id = ' . $this->db->escapeNumber($galaxyID);
75
76
		if ($dbRecord === null) {
77
			$dbResult = $this->db->read('SELECT * FROM game_galaxy WHERE ' . $this->SQL);
78
			if ($dbResult->hasRecord()) {
79
				$dbRecord = $dbResult->record();
80
			}
81
		}
82
		$this->isNew = $dbRecord === null;
83
84
		$this->gameID = $gameID;
85
		$this->galaxyID = $galaxyID;
86
		if (!$this->isNew) {
87
			$this->name = $dbRecord->getField('galaxy_name');
88
			$this->width = $dbRecord->getInt('width');
89
			$this->height = $dbRecord->getInt('height');
90
			$this->galaxyType = $dbRecord->getField('galaxy_type');
91
			$this->maxForceTime = $dbRecord->getInt('max_force_time');
92
		} elseif ($create === false) {
93
			throw new Smr\Exceptions\GalaxyNotFound('No such galaxy: ' . $gameID . '-' . $galaxyID);
94
		}
95
	}
96
97
	public function save(): void {
98
		if ($this->isNew) {
99
			$this->db->insert('game_galaxy', [
100
				'game_id' => $this->db->escapeNumber($this->getGameID()),
101
				'galaxy_id' => $this->db->escapeNumber($this->getGalaxyID()),
102
				'galaxy_name' => $this->db->escapeString($this->getName()),
103
				'width' => $this->db->escapeNumber($this->getWidth()),
104
				'height' => $this->db->escapeNumber($this->getHeight()),
105
				'galaxy_type' => $this->db->escapeString($this->getGalaxyType()),
106
				'max_force_time' => $this->db->escapeNumber($this->getMaxForceTime()),
107
			]);
108
		} elseif ($this->hasChanged) {
109
			$this->db->write('UPDATE game_galaxy SET galaxy_name = ' . $this->db->escapeString($this->getName()) .
110
										', width = ' . $this->db->escapeNumber($this->getWidth()) .
111
										', height = ' . $this->db->escapeNumber($this->getHeight()) .
112
										', galaxy_type = ' . $this->db->escapeString($this->getGalaxyType()) .
113
										', max_force_time = ' . $this->db->escapeNumber($this->getMaxForceTime()) .
114
									' WHERE ' . $this->SQL);
115
		}
116
		$this->isNew = false;
117
		$this->hasChanged = false;
118
	}
119
120
	public function getGameID(): int {
121
		return $this->gameID;
122
	}
123
124
	public function getGalaxyID(): int {
125
		return $this->galaxyID;
126
	}
127
128
	public function getGalaxyMapHREF(): string {
129
		return 'map_galaxy.php?galaxy_id=' . $this->getGalaxyID();
130
	}
131
132
	/**
133
	 * Returns the galaxy name.
134
	 * Use getDisplayName for an HTML-safe version.
135
	 */
136
	public function getName(): string {
137
		return $this->name;
138
	}
139
140
	/**
141
	 * Returns the galaxy name, suitable for HTML display.
142
	 */
143
	public function getDisplayName(): string {
144
		return htmlentities($this->name);
145
	}
146
147
	public function setName(string $name): void {
148
		if (!$this->isNew && $this->name === $name) {
149
			return;
150
		}
151
		$this->name = $name;
152
		$this->hasChanged = true;
153
	}
154
155
	public function getWidth(): int {
156
		return $this->width;
157
	}
158
159
	public function setWidth(int $width): void {
160
		if (!$this->isNew && $this->width === $width) {
161
			return;
162
		}
163
		$this->width = $width;
164
		$this->hasChanged = true;
165
	}
166
167
	public function getHeight(): int {
168
		return $this->height;
169
	}
170
171
	public function setHeight(int $height): void {
172
		if (!$this->isNew && $this->height === $height) {
173
			return;
174
		}
175
		$this->height = $height;
176
		$this->hasChanged = true;
177
	}
178
179
	public function getStartSector(): int {
180
		if (!isset($this->startSector)) {
181
			$this->startSector = 1;
182
			if ($this->galaxyID != 1) {
183
				$galaxies = self::getGameGalaxies($this->gameID);
184
				for ($i = 1; $i < $this->galaxyID; $i++) {
185
					$this->startSector += $galaxies[$i]->getSize();
186
				}
187
			}
188
		}
189
		return $this->startSector;
190
	}
191
192
	public function getEndSector(): int {
193
		return $this->getStartSector() + $this->getSize() - 1;
194
	}
195
196
	public function getSize(): int {
197
		return $this->getHeight() * $this->getWidth();
198
	}
199
200
	public function getSectors(): array {
201
		return SmrSector::getGalaxySectors($this->getGameID(), $this->getGalaxyID());
202
	}
203
204
	public function getPorts(): array {
205
		return SmrPort::getGalaxyPorts($this->getGameID(), $this->getGalaxyID());
206
	}
207
208
	public function getLocations(): array {
209
		return SmrLocation::getGalaxyLocations($this->getGameID(), $this->getGalaxyID());
210
	}
211
212
	public function getPlanets(): array {
213
		return SmrPlanet::getGalaxyPlanets($this->getGameID(), $this->getGalaxyID());
214
	}
215
216
	public function getForces(): array {
217
		return SmrForce::getGalaxyForces($this->getGameID(), $this->getGalaxyID());
218
	}
219
220
	public function getPlayers(): array {
221
		return SmrPlayer::getGalaxyPlayers($this->getGameID(), $this->getGalaxyID());
222
	}
223
224
	/**
225
	 * Returns a 2D array of sectors in the galaxy.
226
	 * If $centerSectorID is specified, it will be in the center of the array.
227
	 * If $dist is also specified, only include sectors $dist away from center.
228
	 *
229
	 * NOTE: This routine queries sectors inefficiently. You may want to
230
	 * construct the cache efficiently before calling this.
231
	 */
232
	public function getMapSectors(int $centerSectorID = null, int $dist = null): array {
233
		if ($centerSectorID === null) {
234
			$topLeft = SmrSector::getSector($this->getGameID(), $this->getStartSector());
235
		} else {
236
			$topLeft = SmrSector::getSector($this->getGameID(), $centerSectorID);
237
			// go left then up
238
			$halfWidth = floor($this->width / 2);
239
			for ($i = 0; ($dist === null || $i < $dist) && $i < $halfWidth; $i++) {
240
				$topLeft = $topLeft->getNeighbourSector('Left');
241
			}
242
			$halfHeight = floor($this->height / 2);
243
			for ($i = 0; ($dist === null || $i < $dist) && $i < $halfHeight; $i++) {
244
				$topLeft = $topLeft->getNeighbourSector('Up');
245
			}
246
		}
247
248
		$mapSectors = [];
249
		for ($i = 0; ($dist === null || $i < 2 * $dist + 1) && $i < $this->height; $i++) {
250
			$mapSectors[$i] = [];
251
			// get left most sector for this row
252
			$rowLeft = $i == 0 ? $topLeft : $rowLeft->getNeighbourSector('Down');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $rowLeft does not seem to be defined for all execution paths leading up to this point.
Loading history...
253
254
			// iterate through the columns
255
			for ($j = 0; ($dist === null || $j < 2 * $dist + 1) && $j < $this->width; $j++) {
256
				$nextSec = $j == 0 ? $rowLeft : $nextSec->getNeighbourSector('Right');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $nextSec does not seem to be defined for all execution paths leading up to this point.
Loading history...
257
				$mapSectors[$i][$j] = $nextSec;
258
			}
259
		}
260
		return $mapSectors;
261
	}
262
263
	public function getGalaxyType(): string {
264
		return $this->galaxyType;
265
	}
266
267
	public function setGalaxyType(string $galaxyType): void {
268
		if (!$this->isNew && $this->galaxyType === $galaxyType) {
269
			return;
270
		}
271
		$this->galaxyType = $galaxyType;
272
		$this->hasChanged = true;
273
	}
274
275
	public function getMaxForceTime(): int {
276
		return $this->maxForceTime;
277
	}
278
279
	public function setMaxForceTime(int $maxForceTime): void {
280
		if (!$this->isNew && $this->maxForceTime === $maxForceTime) {
281
			return;
282
		}
283
		$this->maxForceTime = $maxForceTime;
284
		$this->hasChanged = true;
285
	}
286
287
	public function generateSectors(): void {
288
		$sectorID = $this->getStartSector();
289
		$galSize = $this->getSize();
290
		for ($i = 0; $i < $galSize; $i++) {
291
			$sector = SmrSector::createSector($this->gameID, $sectorID);
292
			$sector->setGalaxyID($this->getGalaxyID());
293
			$sector->update(); //Have to save sectors after creating them
294
			$sectorID++;
295
		}
296
		$this->setConnectivity(100);
297
	}
298
299
	/**
300
	 * Randomly set the connections between all galaxy sectors.
301
	 * $connectivity = (average) percent of connections to enable.
302
	 */
303
	public function setConnectivity(float $connectivity): bool {
304
		// Only set down/right, otherwise we double-hit every link
305
		$linkDirs = ['Down', 'Right'];
306
307
		$problem = true;
308
		$problemTimes = 0;
309
		while ($problem) {
310
			$problem = false;
311
312
			foreach ($this->getSectors() as $galSector) {
313
				foreach ($linkDirs as $linkDir) {
314
					if (rand(1, 100) <= $connectivity) {
315
						$galSector->enableLink($linkDir);
316
					} else {
317
						$galSector->disableLink($linkDir);
318
					}
319
				}
320
			}
321
322
			// Try again if any sector has 0 connections (except 1-sector gals)
323
			if ($this->getSize() > 1) {
324
				foreach ($this->getSectors() as $galSector) {
325
					if ($galSector->getNumberOfConnections() == 0) {
326
						$problem = true;
327
						break;
328
					}
329
				}
330
			}
331
332
			if ($problem && $problemTimes++ > 350) {
333
				$connectivity = 100;
334
			}
335
		}
336
		return $problemTimes <= 350;
337
	}
338
339
	/**
340
	 * Returns the sector connectivity of the galaxy as a percent.
341
	 */
342
	public function getConnectivity(): float {
343
		$totalLinks = 0;
344
		foreach ($this->getSectors() as $galSector) {
345
			$totalLinks += $galSector->getNumberOfLinks();
346
		}
347
		// There are 4 possible links per sector
348
		$connectivity = 100 * $totalLinks / (4 * $this->getSize());
349
		return $connectivity;
350
	}
351
352
	/**
353
	 * Check if the galaxy contains a specific sector.
354
	 */
355
	public function contains(int|SmrSector $sectorID): bool {
356
		if ($sectorID instanceof SmrSector) {
357
			return $sectorID->getGalaxyID() == $this->getGalaxyID();
358
		}
359
		return $sectorID >= $this->getStartSector() && $sectorID <= $this->getEndSector();
360
	}
361
362
	public static function getGalaxyContaining(int $gameID, int $sectorID): self {
363
		return SmrSector::getSector($gameID, $sectorID)->getGalaxy();
364
	}
365
366
	public function equals(SmrGalaxy $otherGalaxy): bool {
367
		return $otherGalaxy->getGalaxyID() == $this->getGalaxyID() && $otherGalaxy->getGameID() == $this->getGameID();
368
	}
369
370
}
371