Skip to content

Commit b262747

Browse files
author
Jasper Geurtz
committed
Fix targetUnit.isCompleted() in Unit.canGather and add unit tests for PR #102 fixes
1 parent 687dc8a commit b262747

10 files changed

Lines changed: 361 additions & 17 deletions

File tree

‎src/main/java/bwapi/BuildingPlacer.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ private static void ReserveAllStructures(final PlacementReserve reserve, final U
243243
reserve.restoreIfInvalid();
244244
}
245245

246-
private static void ReserveExistingAddonPlacement(final PlacementReserve reserve, final TilePosition desiredPosition, final Game game) {
246+
static void ReserveExistingAddonPlacement(final PlacementReserve reserve, final TilePosition desiredPosition, final Game game) {
247247
final TilePosition start = desiredPosition.subtract(new TilePosition(MAX_RANGE, MAX_RANGE).divide(2));
248248
//Exclude addon placement locations
249249
reserve.backup();
@@ -258,7 +258,7 @@ private static void ReserveExistingAddonPlacement(final PlacementReserve reserve
258258
reserve.restoreIfInvalid();
259259
}
260260

261-
private static void ReserveDefault(final PlacementReserve reserve, final UnitType type, final TilePosition desiredPosition, final Game game) {
261+
static void ReserveDefault(final PlacementReserve reserve, final UnitType type, final TilePosition desiredPosition, final Game game) {
262262
reserve.backup();
263263
final PlacementReserve original = reserve;
264264

‎src/main/java/bwapi/Game.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* game state information from Starcraft Broodwar. Game state information includes all units,
1717
* resources, players, forces, bullets, terrain, fog of war, regions, etc.
1818
*/
19-
public final class Game {
19+
public class Game {
2020
private static final int[][] damageRatio = {
2121
// Ind, Sml, Med, Lrg, Non, Unk
2222
{0, 0, 0, 0, 0, 0}, // Independent

‎src/main/java/bwapi/Player.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ public Color getColor() {
544544
* @return character code to use for text in Broodwar.
545545
*/
546546
public Text getTextColor() {
547-
switch (color.id) {
547+
switch (getColor().id) {
548548
case 111: // red
549549
return Text.BrightRed;
550550
case 165: // blue

‎src/main/java/bwapi/Unit.java‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class Unit implements Comparable<Unit> {
4545
private static final Set<Order> gatheringMineralOrders = EnumSet.of(
4646
Harvest1, Harvest2, MoveToMinerals, WaitForMinerals, MiningMinerals, ReturnMinerals, ResetCollision);
4747
private final UnitData unitData;
48-
private final Game game;
48+
Game game;
4949
// static
5050
private final UnitType initialType;
5151
private final int initialResources;
@@ -1311,6 +1311,7 @@ public List<Unit> getUnitsInWeaponRange(final WeaponType weapon, final UnitFilte
13111311
return false;
13121312
}
13131313
// Weapon behavioural checks
1314+
// NOTE: The target flag checks below (after targetsOwn) are inverted, matching an upstream bug in C++ BWAPI's UnitInterface::getUnitsInWeaponRange (BWAPILIB/Source/Unit.cpp).
13141315
final UnitType ut = u.getType();
13151316
if ((weapon.targetsOwn() && !u.getPlayer().equals(getPlayer())) ||
13161317
(!weapon.targetsAir() && !u.isFlying()) ||
@@ -4681,14 +4682,14 @@ public boolean canGather(Unit targetUnit, boolean checkCanTargetUnit, boolean ch
46814682
return false;
46824683
}
46834684

4684-
if (!isCompleted()) {
4685+
if (!targetUnit.isCompleted()) {
46854686
return false;
46864687
}
46874688

46884689
if (!hasPath(targetUnit.getPosition())) {
46894690
return false;
46904691
}
4691-
return !targetUnit.getType().isRefinery() || targetUnit.getPlayer().equals(game.self());
4692+
return !uType.isRefinery() || targetUnit.getPlayer().equals(game.self());
46924693
}
46934694

46944695
public boolean canReturnCargo() {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package bwapi;
2+
3+
import org.junit.Test;
4+
5+
import java.util.Collections;
6+
7+
import static org.junit.Assert.assertEquals;
8+
import static org.mockito.Mockito.mock;
9+
import static org.mockito.Mockito.when;
10+
11+
public class BuildingPlacerTest {
12+
13+
@Test
14+
public void reserveExistingAddonPlacementShouldUseHalfMaxRangeOffset() {
15+
Game game = mock(Game.class);
16+
Player self = mock(Player.class);
17+
when(game.self()).thenReturn(self);
18+
19+
TilePosition desired = new TilePosition(40, 40);
20+
// start should be desired - (64, 64)/2 = (8, 8).
21+
// Factory at (40, 40) has its 2x2 addon at world tiles (44, 41)..(45, 42),
22+
// which corresponds to reserve coordinates (36, 33)..(37, 34).
23+
Unit factory = mock(Unit.class);
24+
when(factory.exists()).thenReturn(true);
25+
when(factory.getType()).thenReturn(UnitType.Terran_Factory);
26+
when(factory.getTilePosition()).thenReturn(new TilePosition(40, 40));
27+
when(self.getUnits()).thenReturn(Collections.singletonList(factory));
28+
29+
BuildingPlacer.PlacementReserve reserve = new BuildingPlacer.PlacementReserve(64);
30+
reserve.setRange(0, 0, 64, 64, (byte) 1);
31+
32+
BuildingPlacer.ReserveExistingAddonPlacement(reserve, desired, game);
33+
34+
assertEquals(0, reserve.getValue(36, 33));
35+
assertEquals(0, reserve.getValue(37, 34));
36+
}
37+
38+
@Test
39+
public void reserveDefaultShouldUsePaddingTwoForFactory() {
40+
Game game = mock(Game.class);
41+
Player self = mock(Player.class);
42+
when(game.self()).thenReturn(self);
43+
44+
TilePosition desired = new TilePosition(40, 40);
45+
Unit factory = mock(Unit.class);
46+
when(factory.exists()).thenReturn(true);
47+
when(factory.getType()).thenReturn(UnitType.Terran_Factory);
48+
when(factory.getTilePosition()).thenReturn(new TilePosition(40, 40));
49+
when(factory.getPosition()).thenReturn(new TilePosition(40, 40).toPosition());
50+
when(self.getUnits()).thenReturn(Collections.singletonList(factory));
51+
52+
BuildingPlacer.PlacementReserve reserve = new BuildingPlacer.PlacementReserve(64);
53+
reserve.setRange(0, 0, 64, 64, (byte) 1);
54+
55+
BuildingPlacer.ReserveDefault(reserve, UnitType.Terran_Supply_Depot, desired, game);
56+
57+
// For a 4x3 Factory at (40, 40) (reserve 32, 32) and a 3x2 Supply Depot:
58+
// padding=1 reserves x in [25, 35), y in [27, 35)
59+
// padding=2 reserves x in [24, 36), y in [26, 36)
60+
assertEquals(0, reserve.getValue(24, 26));
61+
assertEquals(0, reserve.getValue(35, 35));
62+
}
63+
}

‎src/test/java/bwapi/FilterTest.java‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,20 @@ public void testFilterCombinations() {
3939
assertTrue(units.stream().noneMatch(IsMineralField.and(IsRefinery)));
4040
assertTrue(units.stream().noneMatch(IsMineralField.negate()));
4141
}
42+
43+
@Test
44+
public void isTransportShouldMatchDropshipAndExcludeBunker() {
45+
Unit dropship = mock(Unit.class);
46+
when(dropship.getType()).thenReturn(UnitType.Terran_Dropship);
47+
48+
Unit bunker = mock(Unit.class);
49+
when(bunker.getType()).thenReturn(UnitType.Terran_Bunker);
50+
51+
Unit marine = mock(Unit.class);
52+
when(marine.getType()).thenReturn(UnitType.Terran_Marine);
53+
54+
assertTrue(IsTransport.test(dropship));
55+
assertFalse(IsTransport.test(bunker));
56+
assertFalse(IsTransport.test(marine));
57+
}
4258
}

‎src/test/java/bwapi/GameTest.java‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@
1313
import java.util.List;
1414

1515
import static org.assertj.core.api.Assertions.assertThat;
16+
import static org.junit.Assert.assertEquals;
17+
import static org.junit.Assert.assertFalse;
1618
import static org.junit.Assert.assertNull;
1719
import static org.junit.Assert.assertTrue;
1820
import static org.mockito.BDDMockito.given;
21+
import static org.mockito.Mockito.doReturn;
1922
import static org.mockito.Mockito.mock;
23+
import static org.mockito.Mockito.spy;
24+
import static org.mockito.Mockito.when;
2025

2126
@RunWith(Theories.class)
2227
public class GameTest {
@@ -101,4 +106,57 @@ public void ifReplaySelfAndEnemyShouldBeNull() throws IOException {
101106
assertTrue(game.enemies().isEmpty());
102107
assertTrue(game.allies().isEmpty());
103108
}
109+
110+
@Test
111+
public void getUnitsOnTileShouldUseUnitBoundingBoxAndValidateTile() {
112+
Game game = spy(new Game());
113+
doReturn(128 * 32).when(game).mapPixelWidth();
114+
doReturn(128 * 32).when(game).mapPixelHeight();
115+
116+
// Command Center at top-left tile (10, 10) spans pixels [320..447, 320..415] (tiles 10..13, 10..12)
117+
Unit commandCenter = mock(Unit.class);
118+
when(commandCenter.getTilePosition()).thenReturn(new TilePosition(10, 10));
119+
when(commandCenter.getLeft()).thenReturn(320);
120+
when(commandCenter.getTop()).thenReturn(320);
121+
when(commandCenter.getRight()).thenReturn(447);
122+
when(commandCenter.getBottom()).thenReturn(415);
123+
124+
game.setAllUnits(Collections.singletonList(commandCenter));
125+
126+
// Tile (11, 11) is covered by the Command Center even though its top-left tile is (10, 10)
127+
List<Unit> onTile = game.getUnitsOnTile(11, 11);
128+
assertEquals(Collections.singletonList(commandCenter), onTile);
129+
130+
// Invalid tile should return empty list
131+
assertTrue(game.getUnitsOnTile(-1, -1).isEmpty());
132+
}
133+
134+
@Test
135+
public void getUnitsInRadiusShouldUseUnitEdgeDistance() {
136+
Game game = new Game();
137+
138+
// Unit centered at (100, 100) with bounding box [80..120, 80..120]
139+
Unit unit = mock(Unit.class);
140+
Position unitCenter = new Position(100, 100);
141+
Position queryCenter = new Position(150, 100);
142+
when(unit.getPosition()).thenReturn(unitCenter);
143+
when(unit.getLeft()).thenReturn(80);
144+
when(unit.getRight()).thenReturn(120);
145+
when(unit.getTop()).thenReturn(80);
146+
when(unit.getBottom()).thenReturn(120);
147+
when(unit.exists()).thenReturn(true);
148+
when(unit.getDistance(queryCenter)).thenCallRealMethod();
149+
150+
game.setAllUnits(Collections.singletonList(unit));
151+
152+
// Center-to-center distance is 50 (> 35), but edge-to-point distance is 30 (<= 35)
153+
List<Unit> result = game.getUnitsInRadius(queryCenter, 35);
154+
assertEquals(Collections.singletonList(unit), result);
155+
}
156+
157+
@Test
158+
public void setMapWithEmptyStringShouldReturnFalseInsteadOfThrowing() {
159+
Game game = new Game();
160+
assertFalse(game.setMap(""));
161+
}
104162
}

‎src/test/java/bwapi/PlayerTest.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.junit.Test;
44

5+
import static org.junit.Assert.assertEquals;
56
import static org.junit.Assert.assertFalse;
67
import static org.mockito.Mockito.mock;
78
import static org.mockito.Mockito.when;
@@ -18,4 +19,13 @@ public void neutralIsNotEnemy() {
1819

1920
assertFalse(self.isEnemy(neutral));
2021
}
22+
23+
@Test
24+
public void getTextColorShouldReturnDarkGreenForColorGreen() {
25+
Player player = mock(Player.class);
26+
when(player.getColor()).thenReturn(Color.Green); // Color(117)
27+
when(player.getTextColor()).thenCallRealMethod();
28+
29+
assertEquals(Text.DarkGreen, player.getTextColor());
30+
}
2131
}

‎src/test/java/bwapi/PointTest.java‎

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import java.util.TreeSet;
77

88
import static org.junit.Assert.*;
9+
import static org.mockito.Mockito.mock;
10+
import static org.mockito.Mockito.when;
911

1012
public class PointTest {
1113

@@ -52,16 +54,10 @@ public void alternativeConstructorTest() {
5254

5355
@Test
5456
public void isValidChecks() {
55-
Game game = new Game();
56-
game.botClientData().setBuffer(GameBuilder.binToBufferUnchecked(GameBuilder.DEFAULT_BUFFER_PATH));
57-
game.botClientData().gameData().setMapWidth(256);
58-
game.botClientData().gameData().setMapHeight(256);
59-
game.init();
60-
61-
assertEquals(256, game.mapHeight());
62-
assertEquals(256, game.mapWidth());
63-
assertEquals(32 * 256, game.mapPixelHeight());
64-
assertEquals(32 * 256, game.mapPixelWidth());
57+
Game game = mock(Game.class);
58+
when(game.mapPixelWidth()).thenReturn(32 * 256);
59+
when(game.mapPixelHeight()).thenReturn(32 * 256);
60+
6561
assertTrue(new Position(0,0).isValid(game));
6662
assertTrue(new Position(1, 1).isValid(game));
6763

0 commit comments

Comments
 (0)