/**
* Copyright (C) 2002-2012 The FreeCol Team
*
* This file is part of FreeCol.
*
* FreeCol is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* FreeCol is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.freecol.server.ai;
import java.util.ArrayList;
import java.util.List;
import net.sf.freecol.common.model.Building;
import net.sf.freecol.common.model.BuildingType;
import net.sf.freecol.common.model.Colony;
import net.sf.freecol.common.model.ColonyTile;
import net.sf.freecol.common.model.Game;
import net.sf.freecol.common.model.GoodsContainer;
import net.sf.freecol.common.model.GoodsType;
import net.sf.freecol.common.model.Map;
import net.sf.freecol.common.model.Player;
import net.sf.freecol.common.model.Tile;
import net.sf.freecol.common.model.TileImprovementType;
import net.sf.freecol.common.model.TileType;
import net.sf.freecol.common.model.Unit;
import net.sf.freecol.common.model.UnitType;
import net.sf.freecol.server.ServerTestHelper;
import net.sf.freecol.server.model.ServerUnit;
import net.sf.freecol.util.test.FreeColTestCase;
public class ColonyPlanTest extends FreeColTestCase {
private static final BuildingType blacksmithShopType
= spec().getBuildingType("model.building.blacksmithShop");
private static final BuildingType lumberMillType
= spec().getBuildingType("model.building.lumberMill");
private static final BuildingType townHallType
= spec().getBuildingType("model.building.townHall");
private static final GoodsType bellsType
= spec().getGoodsType("model.goods.bells");
private static final GoodsType cottonType
= spec().getGoodsType("model.goods.cotton");
private static final GoodsType clothType
= spec().getGoodsType("model.goods.cloth");
private static final GoodsType foodType
= spec().getPrimaryFoodType();
private static final GoodsType grainType
= spec().getGoodsType("model.goods.grain");
private static final GoodsType sugarType
= spec().getGoodsType("model.goods.sugar");
private static final GoodsType tobaccoType
= spec().getGoodsType("model.goods.tobacco");
private static final GoodsType rumType
= spec().getGoodsType("model.goods.rum");
private static final GoodsType hammersType
= spec().getGoodsType("model.goods.hammers");
private static final GoodsType lumberType
= spec().getGoodsType("model.goods.lumber");
private static final GoodsType oreType
= spec().getGoodsType("model.goods.ore");
private static final GoodsType toolsType
= spec().getGoodsType("model.goods.tools");
private static final TileType forestType
= spec().getTileType("model.tile.coniferForest");
private static final TileType mountainType
= spec().getTileType("model.tile.mountains");
private static final TileType prairieType
= spec().getTileType("model.tile.prairie");
private static final TileType savannahType
= spec().getTileType("model.tile.savannah");
private static final TileImprovementType clearForest
= spec().getTileImprovementType("model.improvement.clearForest");
private static final TileImprovementType fishBonusLand
= spec().getTileImprovementType("model.improvement.fishBonusLand");
private static final TileImprovementType fishBonusRiver
= spec().getTileImprovementType("model.improvement.fishBonusRiver");
private static final TileImprovementType plow
= spec().getTileImprovementType("model.improvement.plow");
private static final TileImprovementType river
= spec().getTileImprovementType("model.improvement.river");
private static final TileImprovementType road
= spec().getTileImprovementType("model.improvement.road");
private static final TileType arctic
= spec().getTileType("model.tile.arctic");
private static final TileType desert
= spec().getTileType("model.tile.desert");
private static final TileType desertForest
= spec().getTileType("model.tile.scrubForest");
private static final TileType grassland
= spec().getTileType("model.tile.grassland");
private static final TileType grasslandForest
= spec().getTileType("model.tile.coniferForest");
private static final TileType highSeas
= spec().getTileType("model.tile.highSeas");
private static final TileType hills
= spec().getTileType("model.tile.hills");
private static final TileType marsh
= spec().getTileType("model.tile.marsh");
private static final TileType marshForest
= spec().getTileType("model.tile.wetlandForest");
private static final TileType mountains
= spec().getTileType("model.tile.mountains");
private static final TileType ocean
= spec().getTileType("model.tile.ocean");
private static final TileType plains
= spec().getTileType("model.tile.plains");
private static final TileType plainsForest
= spec().getTileType("model.tile.mixedForest");
private static final TileType prairie
= spec().getTileType("model.tile.prairie");
private static final TileType prairieForest
= spec().getTileType("model.tile.broadleafForest");
private static final TileType savannah
= spec().getTileType("model.tile.savannah");
private static final TileType savannahForest
= spec().getTileType("model.tile.tropicalForest");
private static final TileType swamp
= spec().getTileType("model.tile.swamp");
private static final TileType swampForest
= spec().getTileType("model.tile.rainForest");
private static final TileType tundra
= spec().getTileType("model.tile.tundra");
private static final TileType tundraForest
= spec().getTileType("model.tile.borealForest");
private static final UnitType farmerType
= spec().getUnitType("model.unit.expertFarmer");
private static final UnitType colonistType
= spec().getUnitType("model.unit.freeColonist");
private static final UnitType servantType
= spec().getUnitType("model.unit.indenturedServant");
private static final UnitType convertType
= spec().getUnitType("model.unit.indianConvert");
private static final UnitType criminalType
= spec().getUnitType("model.unit.pettyCriminal");
private static final UnitType sugarPlanterType
= spec().getUnitType("model.unit.masterSugarPlanter");
@Override
public void tearDown() throws Exception {
ServerTestHelper.stopServerGame();
super.tearDown();
}
/**
* Creates the special map for the tests
* map will have:
* - a colony in (5,8) (built after)
* - a forest in (4,8) for lumber
* - a mountain in (6,8) for ore
*/
private Map buildMap(boolean withBuildRawMat) {
MapBuilder builder = new MapBuilder(getGame());
if(withBuildRawMat){
builder.setTile(4, 8, forestType);
builder.setTile(6, 8, mountainType);
}
return builder.build();
}
/**
* Should a plan produce a type of goods?
*
* @param plan The <code>ColonyPlan</code> to examine.
* @param type The <code>GoodsType</code> to check.
* @return True is there is a work location plan for the required goods
* type in the colony plan.
*/
private boolean shouldProduce(ColonyPlan plan, GoodsType type) {
List<WorkLocationPlan> plans = (type.isFoodType()) ? plan.getFoodPlans()
: plan.getWorkPlans();
for (WorkLocationPlan wlp : plans) {
if (wlp.getGoodsType() == type) return true;
}
return false;
}
public void testReqLumberAndHammersForBuild() {
Map map = buildMap(true);
Game game = ServerTestHelper.startServerGame(map);
AIMain aiMain = ServerTestHelper.getServer().getAIMain();
Colony colony = getStandardColony(4);
ColonyPlan plan = new ColonyPlan(aiMain,colony);
plan.update();
assertEquals("The colony should plan to build the lumber mill",
lumberMillType, plan.getBuildableTypes().get(0));
assertTrue("The colony should plan to produce lumber",
shouldProduce(plan, lumberType));
assertTrue("The colony should plan to produce hammers",
shouldProduce(plan, hammersType));
}
public void testReqOreAndToolsWithEnoughHammersForBuild() {
Map map = buildMap(true);
Game game = ServerTestHelper.startServerGame(map);
AIMain aiMain = ServerTestHelper.getServer().getAIMain();
Colony colony = getStandardColony(4);
// Set colony to have enough hammers. Should still require tools.
ColonyPlan plan = new ColonyPlan(aiMain, colony);
plan.update();
colony.addGoods(hammersType,
blacksmithShopType.getAmountRequiredOf(hammersType));
colony.setCurrentlyBuilding(blacksmithShopType);
plan.refine(blacksmithShopType);
assertTrue("The colony should plan to produce ore",
shouldProduce(plan, oreType));
assertTrue("The colony should plan to produce tools",
shouldProduce(plan, toolsType));
assertFalse("The colony should not produce hammers, has enough",
shouldProduce(plan, hammersType));
}
/**
* This test verifies behavior when the colony has no tiles that
* provide the raw materials for the build, but has them in stock
*/
public void testNoBuildRawMatTiles() {
Map map = buildMap(false);
Game game = ServerTestHelper.startServerGame(map);
AIMain aiMain = ServerTestHelper.getServer().getAIMain();
Colony colony = getStandardColony(4);
// Add enough raw materials for build
colony.addGoods(lumberType, GoodsContainer.CARGO_SIZE);
colony.addGoods(oreType, GoodsContainer.CARGO_SIZE);
ColonyPlan plan = new ColonyPlan(aiMain, colony);
plan.update();
plan.refine(colony.getCurrentlyBuilding());
assertFalse("The colony can not produce lumber, none available",
shouldProduce(plan, lumberType));
assertTrue("The colony should produce hammers, has lumber in stock",
shouldProduce(plan, hammersType));
// Simulate that enough hammers have been gathered, re-plan building
// with a tools requirement.
plan.update();
colony.addGoods(hammersType,
blacksmithShopType.getAmountRequiredOf(hammersType));
colony.setCurrentlyBuilding(blacksmithShopType);
plan.refine(blacksmithShopType);
assertFalse("The colony should not produce hammers, has enough",
shouldProduce(plan, hammersType));
assertFalse("The colony can not produce ore, none available",
shouldProduce(plan, oreType));
assertTrue("The colony should produce tools, has ore in stock",
shouldProduce(plan, toolsType));
}
public void testGetBestWorker() {
Game game = ServerTestHelper.startServerGame(getTestMap(savannahType));
AIMain aiMain = ServerTestHelper.getServer().getAIMain();
Colony colony = getStandardColony();
game.setCurrentPlayer(colony.getOwner());
Player dutch = getGame().getPlayer("model.nation.dutch");
List<Unit> units = new ArrayList<Unit>();
Unit servant = new ServerUnit(getGame(), colony.getTile(),
dutch, servantType);
units.add(servant);
Building townHall = colony.getBuilding(townHallType);
ColonyTile colonyTile = null;
for (ColonyTile ct : colony.getColonyTiles()) {
if (!ct.isFull()) {
colonyTile = ct;
break;
}
}
assertNotNull(colonyTile);
assertNull(ColonyPlan.getBestWorker(colonyTile, sugarType, null));
assertNull(ColonyPlan.getBestWorker(colonyTile, sugarType, new ArrayList<Unit>()));
// Should always pick a singleton as long as it is productive.
assertEquals(servant, ColonyPlan.getBestWorker(colonyTile, sugarType, units));
assertEquals(servant, ColonyPlan.getBestWorker(colonyTile, grainType, units));
assertEquals(servant, ColonyPlan.getBestWorker(townHall, bellsType, units));
assertNull(ColonyPlan.getBestWorker(townHall, grainType, units));
// The criminal should be preferred to the servant when their
// productivity is equal because it has lower skill.
Unit criminal = new ServerUnit(getGame(), colony.getTile(), dutch, criminalType);
units.add(criminal);
assertEquals(criminal, ColonyPlan.getBestWorker(colonyTile, sugarType, units));
assertEquals(criminal, ColonyPlan.getBestWorker(colonyTile, grainType, units));
assertEquals(servant, ColonyPlan.getBestWorker(townHall, bellsType, units));
// The colonist will displace the servant in the town hall
// because it is more productive, and elsewhere because it can
// upgrade.
Unit colonist1 = new ServerUnit(getGame(), colony.getTile(), dutch, colonistType);
units.add(colonist1);
assertEquals(colonist1, ColonyPlan.getBestWorker(colonyTile, sugarType, units));
assertEquals(colonist1, ColonyPlan.getBestWorker(colonyTile, grainType, units));
assertEquals(colonist1, ColonyPlan.getBestWorker(townHall, bellsType, units));
// When there is a colonist with relevant experience it will win,
// otherwise it will lose to the inexperienced colonist.
Unit colonist2 = new ServerUnit(getGame(), colony.getTile(), dutch, colonistType);
units.add(colonist2);
colonist2.setWorkType(sugarType);
colonist2.modifyExperience(100);
assertEquals(colonist2, ColonyPlan.getBestWorker(colonyTile, sugarType, units));
assertEquals(colonist1, ColonyPlan.getBestWorker(colonyTile, grainType, units));
assertEquals(colonist1, ColonyPlan.getBestWorker(townHall, bellsType, units));
// colonist1 still has *less* experience to waste. Experience
// now causes a preference when production is zero, but only for
// singletons.
colonist1.setWorkType(lumberType);
colonist1.modifyExperience(80);
assertNull(ColonyPlan.getBestWorker(colonyTile, lumberType, units));
assertEquals(colonist2, ColonyPlan.getBestWorker(colonyTile, sugarType, units));
assertEquals(colonist1, ColonyPlan.getBestWorker(colonyTile, grainType, units));
assertEquals(colonist1, ColonyPlan.getBestWorker(townHall, bellsType, units));
Unit convert = new ServerUnit(getGame(), colony.getTile(), dutch, convertType);
units.add(convert);
assertEquals(convert, ColonyPlan.getBestWorker(colonyTile, sugarType, units));
assertEquals(convert, ColonyPlan.getBestWorker(colonyTile, grainType, units));
units.remove(convert);
// The sugarPlanter will prevail in its expertise, and in the
// town hall because it can not be upgraded.
Unit sugarPlanter = new ServerUnit(getGame(), colony.getTile(), dutch, sugarPlanterType);
units.add(sugarPlanter);
assertEquals(sugarPlanter, ColonyPlan.getBestWorker(colonyTile, sugarType, units));
assertEquals(colonist1, ColonyPlan.getBestWorker(colonyTile, grainType, units));
assertEquals(sugarPlanter, ColonyPlan.getBestWorker(townHall, bellsType, units));
units.remove(sugarPlanter);
// Similarly with the farmer.
Unit farmer = new ServerUnit(getGame(), colony.getTile(), dutch, farmerType);
units.add(farmer);
assertEquals(colonist2, ColonyPlan.getBestWorker(colonyTile, sugarType, units));
assertEquals(farmer, ColonyPlan.getBestWorker(colonyTile, grainType, units));
assertEquals(farmer, ColonyPlan.getBestWorker(townHall, bellsType, units));
// But with both we can not expect to tell who wins the town hall.
units.add(convert);
units.add(sugarPlanter);
assertEquals(sugarPlanter, ColonyPlan.getBestWorker(colonyTile, sugarType, units));
assertEquals(farmer, ColonyPlan.getBestWorker(colonyTile, grainType, units));
}
public void testBestImprovements() throws Exception {
Map map = getTestMap(plains);
Game game = getStandardGame();
game.setMap(map);
Tile tile1 = map.getTile(5, 8);
tile1.setType(savannah);
assertEquals(plow, TileImprovementPlan.getBestTileImprovementType(tile1, grainType));
assertEquals(plow, TileImprovementPlan.getBestTileImprovementType(tile1, sugarType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, tobaccoType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, lumberType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, oreType));
tile1.setType(marsh);
assertEquals(plow, TileImprovementPlan.getBestTileImprovementType(tile1, grainType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, sugarType));
assertEquals(plow, TileImprovementPlan.getBestTileImprovementType(tile1, tobaccoType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, lumberType));
assertEquals(road, TileImprovementPlan.getBestTileImprovementType(tile1, oreType));
tile1.setType(savannahForest);
assertEquals(clearForest, TileImprovementPlan.getBestTileImprovementType(tile1, grainType));
assertEquals(clearForest, TileImprovementPlan.getBestTileImprovementType(tile1, sugarType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, tobaccoType));
assertEquals(road, TileImprovementPlan.getBestTileImprovementType(tile1, lumberType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, oreType));
tile1.setType(hills);
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, grainType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, sugarType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, tobaccoType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, lumberType));
assertEquals(road, TileImprovementPlan.getBestTileImprovementType(tile1, oreType));
tile1.setType(arctic);
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, grainType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, sugarType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, tobaccoType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, lumberType));
assertEquals(null, TileImprovementPlan.getBestTileImprovementType(tile1, oreType));
}
}