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

Passed
Push — master ( b86122...fc41d3 )
by Dan
05:09
created

Plotter::findDistanceToX()   F

Complexity

Conditions 23
Paths 312

Size

Total Lines 86
Code Lines 61

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 23
eloc 61
nc 312
nop 8
dl 0
loc 86
rs 1.9333
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 declare(strict_types=1);
2
3
class Plotter {
4
5
	public static function getX($xType, $X, $gameID, $player = null) {
6
		// Special case for Location categories (i.e. Bar, HQ, SafeFed)
7
		if (!is_numeric($X)) {
8
			if ($xType != 'Locations') {
9
				throw new Exception('Non-numeric X only exists for Locations');
10
			}
11
			return $X;
12
		}
13
14
		// In all other cases, X is a numeric ID
15
		$X = (int)$X;
16
17
		// Helper function for plots to trade goods
18
		$getGoodWithTransaction = function(int $goodID) use ($xType, $player) {
19
			$good = Globals::getGood($goodID);
20
			if (isset($player) && !$player->meetsAlignmentRestriction($good['AlignRestriction'])) {
21
				create_error('You do not have the correct alignment to see this good!');
22
			}
23
			$good['TransactionType'] = explode(' ', $xType)[0]; // use 'Buy' or 'Sell'
24
			return $good;
25
		};
26
27
		return match($xType) {
28
			'Technology' => Globals::getHardwareTypes($X),
29
			'Ships' => AbstractSmrShip::getBaseShip($X),
30
			'Weapons' => SmrWeaponType::getWeaponType($X),
31
			'Locations' => SmrLocation::getLocation($X),
32
			'Sell Goods', 'Buy Goods' => $getGoodWithTransaction($X),
33
			'Galaxies' => SmrGalaxy::getGalaxy($gameID, $X), // $X is the galaxyID
34
		};
35
	}
36
37
	/**
38
	 * Returns the shortest path from $sector to $x as a Distance object.
39
	 * The path is guaranteed reversible ($x -> $sector == $sector -> $x), which
40
	 * is not true for findDistanceToX. If $x is not a SmrSector, then this
41
	 * function does 2x the work.
42
	 */
43
	public static function findReversiblePathToX($x, SmrSector $sector, $useFirst, AbstractSmrPlayer $needsToHaveBeenExploredBy = null, AbstractSmrPlayer $player = null) {
44
		if ($x instanceof SmrSector) {
45
46
			// To ensure reversibility, always plot lowest to highest.
47
			$reverse = $sector->getSectorID() > $x->getSectorID();
48
			if ($reverse) {
49
				$start = $x;
50
				$end = $sector;
51
			} else {
52
				$start = $sector;
53
				$end = $x;
54
			}
55
			$path = Plotter::findDistanceToX($end, $start, $useFirst, $needsToHaveBeenExploredBy, $player);
56
			if ($path === false) {
57
				create_error('Unable to plot from ' . $sector->getSectorID() . ' to ' . $x->getSectorID() . '.');
58
			}
59
			// Reverse if we plotted $x -> $sector (since we want $sector -> $x)
60
			if ($reverse) {
61
				$path->reversePath();
62
			}
63
64
		} else {
65
66
			// At this point we don't know what sector $x will be at
67
			$path = Plotter::findDistanceToX($x, $sector, $useFirst, $needsToHaveBeenExploredBy, $player);
68
			if ($path === false) {
69
				create_error('Unable to find what you\'re looking for, it either hasn\'t been added to this game or you haven\'t explored it yet.');
70
			}
71
			// Now that we know where $x is, make sure path is reversible
72
			// (i.e. start sector < end sector)
73
			if ($path->getEndSectorID() < $sector->getSectorID()) {
74
				$path = Plotter::findDistanceToX($sector, $path->getEndSector(), true);
75
				$path->reversePath();
76
			}
77
78
		}
79
		return $path;
80
	}
81
82
	/**
83
	 * Returns the shortest path from $sector to $x as a Distance object.
84
	 * $x can be any type implemented by SmrSector::hasX or the string 'Distance'.
85
	 * The resulting path prefers neighbors in their order in SmrSector->links,
86
	 * (i.e. up, down, left, right).
87
	 */
88
	public static function findDistanceToX($x, SmrSector $sector, $useFirst, AbstractSmrPlayer $needsToHaveBeenExploredBy = null, AbstractSmrPlayer $player = null, $distanceLimit = 10000, $lowLimit = 0, $highLimit = 100000) {
89
		$warpAddIndex = TURNS_WARP_SECTOR_EQUIVALENCE - 1;
90
91
		$checkSector = $sector;
92
		$gameID = $sector->getGameID();
93
		$distances = array();
94
		$sectorsTravelled = 0;
95
		$visitedSectors = array();
96
		$visitedSectors[$checkSector->getSectorID()] = true;
97
		if ($x == 'Distance') {
98
			$distances[0][$checkSector->getSectorID()] = new Distance($gameID, $checkSector->getSectorID());
99
		}
100
101
		$distanceQ = array();
102
		for ($i = 0; $i <= TURNS_WARP_SECTOR_EQUIVALENCE; $i++) {
103
			$distanceQ[] = array();
104
		}
105
		//Warps first as a slight optimisation due to how visitedSectors is set.
106
		if ($checkSector->hasWarp() === true) {
107
			$d = new Distance($gameID, $checkSector->getSectorID());
108
			$d->addWarpToPath($checkSector->getWarp(), $checkSector->getSectorID());
109
			$distanceQ[$warpAddIndex][] = $d;
110
		}
111
		foreach ($checkSector->getLinks() as $nextSector) {
112
			if ($nextSector !== 0) {
113
				$visitedSectors[$nextSector] = true;
114
				$d = new Distance($gameID, $checkSector->getSectorID());
115
				$d->addToPath($nextSector);
116
				$distanceQ[0][] = $d;
117
			}
118
		}
119
		$maybeWarps = 0;
120
		while ($maybeWarps <= TURNS_WARP_SECTOR_EQUIVALENCE) {
121
			$sectorsTravelled++;
122
			if ($sectorsTravelled > $distanceLimit) {
123
				return $distances;
124
			}
125
			if ($x == 'Distance') {
126
				$distances[$sectorsTravelled] = array();
127
			}
128
			$distanceQ[] = array();
129
			if (count($q = array_shift($distanceQ)) === 0) {
130
				$maybeWarps++;
131
				continue;
132
			}
133
			$maybeWarps = 0;
134
			while (($distance = array_shift($q)) !== null) {
135
				$checkSectorID = $distance->getEndSectorID();
136
				$visitedSectors[$checkSectorID] = true; // This is here for warps, because they are delayed visits if we set this before the actual visit we'll get sectors marked as visited long before they are actually visited - causes problems when it's quicker to walk to the warp exit than to warp there.
137
																// We still need to mark walked sectors as visited before we go to each one otherwise we get a huge number of paths being checked twice (up then left, left then up are essentially the same but if we set up-left as visited only when we actually check it then it gets queued up twice - nasty)
138
				if ($checkSectorID >= $lowLimit && $checkSectorID <= $highLimit) {
139
					$checkSector = SmrSector::getSector($gameID, $checkSectorID);
140
					if ($x == 'Distance') {
141
						$distances[$sectorsTravelled][$checkSector->getSectorID()] = $distance;
142
					} elseif (($needsToHaveBeenExploredBy === null || $needsToHaveBeenExploredBy->hasVisitedSector($checkSector->getSectorID())) === true
143
							&& $checkSector->hasX($x, $player) === true) {
144
						if ($useFirst === true) {
145
							return $distance;
146
						}
147
						$distances[$checkSector->getSectorID()] = $distance;
148
					}
149
					//Warps first as a slight optimisation due to how visitedSectors is set.
150
					if ($checkSector->hasWarp() === true) {
151
						if (!isset($visitedSectors[$checkSector->getWarp()])) {
152
							$cloneDistance = clone($distance);
153
							$cloneDistance->addWarpToPath($checkSector->getWarp(), $checkSector->getSectorID());
154
							$distanceQ[$warpAddIndex][] = $cloneDistance;
155
						}
156
					}
157
					foreach ($checkSector->getLinks() as $nextSector) {
158
						if (!isset($visitedSectors[$nextSector])) {
159
							$visitedSectors[$nextSector] = true;
160
161
							$cloneDistance = clone($distance);
162
							$cloneDistance->addToPath($nextSector);
163
							$distanceQ[0][] = $cloneDistance;
164
						}
165
					}
166
				}
167
			}
168
		}
169
		if ($useFirst === true) {
170
			$return = false;
171
			return $return;
172
		}
173
		return $distances;
174
	}
175
176
	public static function calculatePortToPortDistances(array $sectors, $distanceLimit = 10000, $lowLimit = 0, $highLimit = 100000) {
177
		$distances = array();
178
		foreach ($sectors as $sec) {
179
			if ($sec !== null) {
180
				if ($sec->getSectorID() >= $lowLimit && $sec->getSectorID() <= $highLimit) {
181
					if ($sec->hasPort() === true) {
182
						$distances[$sec->getSectorID()] = self::findDistanceToOtherPorts($sec, $distanceLimit, $lowLimit, $highLimit);
183
					}
184
				}
185
			}
186
		}
187
		return $distances;
188
	}
189
190
	public static function findDistanceToOtherPorts(SmrSector $sector, $distanceLimit = 10000, $lowLimit = 0, $highLimit = 100000) {
191
		return self::findDistanceToX('Port', $sector, false, null, null, $distanceLimit, $lowLimit, $highLimit);
192
	}
193
}
194
195