Skip to content

Commit ca9a01d

Browse files
author
Jasper Geurtz
committed
Fix targetUnit.isCompleted() in Unit.canGather and add unit tests for PR #102 fixes
# Conflicts: # src/test/java/bwapi/GameTest.java
1 parent 8476ce4 commit ca9a01d

10 files changed

Lines changed: 360 additions & 16 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: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ UnitSelf self() {
6868
return self;
6969
}
7070

71+
Unit(final Game game) {
72+
this.unitData = null;
73+
this.game = game;
74+
this.initialType = UnitType.Unknown;
75+
this.initialResources = 0;
76+
this.initialHitPoints = 0;
77+
this.initialPosition = Position.Unknown;
78+
this.initialTilePosition = TilePosition.Unknown;
79+
this.id = -1;
80+
}
7181

7282
Unit(final UnitData unitData, int id, final Game game) {
7383
this.unitData = unitData;
@@ -1311,6 +1321,7 @@ public List<Unit> getUnitsInWeaponRange(final WeaponType weapon, final UnitFilte
13111321
return false;
13121322
}
13131323
// Weapon behavioural checks
1324+
// NOTE: The target flag checks below (after targetsOwn) are inverted, matching an upstream bug in C++ BWAPI's UnitInterface::getUnitsInWeaponRange (BWAPILIB/Source/Unit.cpp).
13141325
final UnitType ut = u.getType();
13151326
if ((weapon.targetsOwn() && !u.getPlayer().equals(getPlayer())) ||
13161327
(!weapon.targetsAir() && !u.isFlying()) ||
@@ -4715,14 +4726,14 @@ public boolean canGather(Unit targetUnit, boolean checkCanTargetUnit, boolean ch
47154726
return false;
47164727
}
47174728

4718-
if (!isCompleted()) {
4729+
if (!targetUnit.isCompleted()) {
47194730
return false;
47204731
}
47214732

47224733
if (!hasPath(targetUnit.getPosition())) {
47234734
return false;
47244735
}
4725-
return !targetUnit.getType().isRefinery() || targetUnit.getPlayer().equals(game.self());
4736+
return !uType.isRefinery() || targetUnit.getPlayer().equals(game.self());
47264737
}
47274738

47284739
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 {
@@ -116,4 +121,57 @@ public void hasPowerOnTile() throws IOException {
116121
// tile (31, 15) is pixel (992, 480), right next to the pylon
117122
assertTrue(game.hasPower(31, 15));
118123
}
124+
125+
@Test
126+
public void getUnitsOnTileShouldUseUnitBoundingBoxAndValidateTile() {
127+
Game game = spy(new Game());
128+
doReturn(128 * 32).when(game).mapPixelWidth();
129+
doReturn(128 * 32).when(game).mapPixelHeight();
130+
131+
// Command Center at top-left tile (10, 10) spans pixels [320..447, 320..415] (tiles 10..13, 10..12)
132+
Unit commandCenter = mock(Unit.class);
133+
when(commandCenter.getTilePosition()).thenReturn(new TilePosition(10, 10));
134+
when(commandCenter.getLeft()).thenReturn(320);
135+
when(commandCenter.getTop()).thenReturn(320);
136+
when(commandCenter.getRight()).thenReturn(447);
137+
when(commandCenter.getBottom()).thenReturn(415);
138+
139+
game.setAllUnits(Collections.singletonList(commandCenter));
140+
141+
// Tile (11, 11) is covered by the Command Center even though its top-left tile is (10, 10)
142+
List<Unit> onTile = game.getUnitsOnTile(11, 11);
143+
assertEquals(Collections.singletonList(commandCenter), onTile);
144+
145+
// Invalid tile should return empty list
146+
assertTrue(game.getUnitsOnTile(-1, -1).isEmpty());
147+
}
148+
149+
@Test
150+
public void getUnitsInRadiusShouldUseUnitEdgeDistance() {
151+
Game game = new Game();
152+
153+
// Unit centered at (100, 100) with bounding box [80..120, 80..120]
154+
Unit unit = mock(Unit.class);
155+
Position unitCenter = new Position(100, 100);
156+
Position queryCenter = new Position(150, 100);
157+
when(unit.getPosition()).thenReturn(unitCenter);
158+
when(unit.getLeft()).thenReturn(80);
159+
when(unit.getRight()).thenReturn(120);
160+
when(unit.getTop()).thenReturn(80);
161+
when(unit.getBottom()).thenReturn(120);
162+
when(unit.exists()).thenReturn(true);
163+
when(unit.getDistance(queryCenter)).thenCallRealMethod();
164+
165+
game.setAllUnits(Collections.singletonList(unit));
166+
167+
// Center-to-center distance is 50 (> 35), but edge-to-point distance is 30 (<= 35)
168+
List<Unit> result = game.getUnitsInRadius(queryCenter, 35);
169+
assertEquals(Collections.singletonList(unit), result);
170+
}
171+
172+
@Test
173+
public void setMapWithEmptyStringShouldReturnFalseInsteadOfThrowing() {
174+
Game game = new Game();
175+
assertFalse(game.setMap(""));
176+
}
119177
}

‎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)