/**
* 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.model;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import net.sf.freecol.common.model.Colony;
import net.sf.freecol.common.model.Europe;
import net.sf.freecol.common.model.Game;
import net.sf.freecol.common.model.Goods;
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.Market;
import net.sf.freecol.common.model.Tile;
import net.sf.freecol.common.model.TileType;
import net.sf.freecol.common.model.Turn;
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.control.InGameController;
import net.sf.freecol.util.test.FreeColTestCase;
import net.sf.freecol.util.test.MockPseudoRandom;
public class ServerPlayerTest extends FreeColTestCase {
private static final GoodsType cottonType
= spec().getGoodsType("model.goods.cotton");
private static final GoodsType foodType
= spec().getPrimaryFoodType();
private static final GoodsType musketsType
= spec().getGoodsType("model.goods.muskets");
private static final GoodsType silverType
= spec().getGoodsType("model.goods.silver");
private static final TileType plains
= spec().getTileType("model.tile.plains");
private static final UnitType colonistType
= spec().getUnitType("model.unit.freeColonist");
private static final UnitType wagonTrainType
= spec().getUnitType("model.unit.wagonTrain");
private static final UnitType caravelType
= spec().getUnitType("model.unit.caravel");
private static final UnitType galleonType
= spec().getUnitType("model.unit.galleon");
private static final UnitType privateerType
= spec().getUnitType("model.unit.privateer");
@Override
public void tearDown() throws Exception {
ServerTestHelper.stopServerGame();
super.tearDown();
}
/**
* If we wait a number of turns after selling, the market should
* recover and finally settle back to the initial levels. Also
* test that selling reduces the price for other players.
*/
public void testMarketRecovery() {
Game game = ServerTestHelper.startServerGame(getTestMap());
InGameController igc = ServerTestHelper.getInGameController();
ServerPlayer french = (ServerPlayer) game.getPlayer("model.nation.french");
ServerPlayer english = (ServerPlayer) game.getPlayer("model.nation.english");
Market frenchMarket = french.getMarket();
Market englishMarket = english.getMarket();
int frenchGold = french.getGold();
int silverPrice = spec().getInitialPrice(silverType);
// Sell lightly in the English market to check that the good
// is now considered "traded".
english.sell(null, silverType, 1, new Random());
assertTrue(englishMarket.hasBeenTraded(silverType));
int englishAmount = englishMarket.getAmountInMarket(silverType);
// Sell heavily in the French market, price should drop.
french.sell(null, silverType, 200, new Random());
assertEquals(frenchGold + silverPrice * 200, french.getGold());
assertTrue(frenchMarket.hasBeenTraded(silverType));
assertTrue(frenchMarket.getSalePrice(silverType, 1) < silverPrice);
// Price might have dropped in the English market too, but
// not as much as for the French.
assertTrue("English silver increases due to French sales",
englishMarket.getAmountInMarket(silverType) > englishAmount);
assertTrue("English silver price might drop due to French sales",
englishMarket.getSalePrice(silverType, 1) <= silverPrice);
assertTrue("English silver price should drop less than French",
englishMarket.getSalePrice(silverType, 1)
>= frenchMarket.getSalePrice(silverType, 1));
// Pretend time is passing.
// Have to advance time as yearly goods removal is initially low.
game.setTurn(new Turn(200));
List<Integer> setValues = new ArrayList<Integer>();
setValues.add(20);
MockPseudoRandom mockRandom = new MockPseudoRandom(setValues, true);
ServerTestHelper.setRandom(mockRandom);
boolean frenchRecovered = false;
boolean englishRecovered = false;
for (int i = 0; i < 100; i++) {
igc.yearlyGoodsAdjust((ServerPlayer) french);
if (frenchMarket.getSalePrice(silverType, 1) >= silverPrice) {
frenchRecovered = true;
}
igc.yearlyGoodsAdjust((ServerPlayer) english);
if (englishMarket.getSalePrice(silverType, 1) >= silverPrice) {
englishRecovered = true;
}
}
// Prices should have recovered.
assertTrue("French silver price should have recovered",
frenchRecovered);
assertTrue("English silver price should have recovered",
englishRecovered);
}
public void testHasExploredTile() {
Map map = getTestMap();
Game game = ServerTestHelper.startServerGame(map);
ServerPlayer dutch = (ServerPlayer) game.getPlayer("model.nation.dutch");
ServerPlayer french = (ServerPlayer) game.getPlayer("model.nation.french");
Tile tile1 = map.getTile(6, 8);
Tile tile2 = map.getTile(8, 6);
assertFalse("Setup error, tile1 should not be explored by dutch player",dutch.hasExplored(tile1));
assertFalse("Setup error, tile1 should not be explored by french player",french.hasExplored(tile1));
assertFalse("Setup error, tile2 should not be explored by dutch player",dutch.hasExplored(tile2));
assertFalse("Setup error, tile2 should not be explored by french player",french.hasExplored(tile2));
new ServerUnit(game, tile1, dutch, colonistType);
new ServerUnit(game, tile2, french, colonistType);
assertTrue("Tile1 should be explored by dutch player",dutch.hasExplored(tile1));
assertFalse("Tile1 should not be explored by french player",french.hasExplored(tile1));
assertFalse("Tile2 should not be explored by dutch player",dutch.hasExplored(tile2));
assertTrue("Tile2 should be explored by french player",french.hasExplored(tile2));
}
public void testLoadInColony() {
Map map = getTestMap();
Game game = ServerTestHelper.startServerGame(map);
InGameController igc = ServerTestHelper.getInGameController();
Colony colony = getStandardColony();
ServerPlayer dutch = (ServerPlayer) game.getPlayer("model.nation.dutch");
Unit wagonInColony = new ServerUnit(game, colony.getTile(), dutch,
wagonTrainType);
Unit wagonNotInColony = new ServerUnit(game, map.getTile(10, 10), dutch,
wagonTrainType);
Goods cotton = new Goods(game, null, cottonType, 75);
// Check if location null
assertEquals(null, cotton.getTile());
// Check that it does not work if current Location == null
try {
igc.moveGoods(cotton, wagonInColony);
fail();
} catch (IllegalStateException e) {
}
try {
igc.moveGoods(cotton, wagonNotInColony);
fail();
} catch (IllegalStateException e) {
}
// Check wagon to colony
cotton.setLocation(wagonInColony);
igc.moveGoods(cotton, colony);
assertEquals(cotton.getLocation(), colony);
assertEquals(75, colony.getGoodsCount(cottonType));
// Check from colony to wagon train
igc.moveGoods(cotton, wagonInColony);
assertEquals(wagonInColony, cotton.getLocation());
assertEquals(0, colony.getGoodsCount(cottonType));
// Check failure units not co-located
try {
igc.moveGoods(cotton, wagonNotInColony);
fail();
} catch (IllegalStateException e) {
}
// Check failure to non-GoodsContainer (Tile)
try {
igc.moveGoods(cotton, map.getTile(9, 10));
fail();
} catch (IllegalStateException e) {
}
// Check from unit to unit
wagonInColony.setLocation(wagonNotInColony.getTile());
igc.moveGoods(cotton, wagonNotInColony);
assertEquals(wagonNotInColony, cotton.getLocation());
}
public void testLoadInEurope() {
Game game = ServerTestHelper.startServerGame(getTestMap());
InGameController igc = ServerTestHelper.getInGameController();
ServerPlayer dutch = (ServerPlayer) game.getPlayer("model.nation.dutch");
Goods cotton = new Goods(game, null, cottonType, 75);
Europe europe = dutch.getEurope();
Map america = game.getMap();
Unit privateer1 = new ServerUnit(game, europe, dutch, privateerType);
Unit privateer2 = new ServerUnit(game, europe, dutch, privateerType);
// While source in Europe, target in Europe
cotton.setLocation(privateer1);
igc.moveGoods(cotton, privateer2);
assertEquals(privateer2, cotton.getLocation());
// Can not unload directly to Europe
try {
igc.moveGoods(cotton, europe);
fail();
} catch (IllegalStateException e) {
}
// While source moving from America, target in Europe
cotton.setLocation(privateer1);
assertEquals(europe, privateer1.getLocation());
igc.moveTo(dutch, privateer1, america);
try {
igc.moveGoods(cotton, privateer2);
fail();
} catch (IllegalStateException e) {
}
// While source moving to America, target in Europe
cotton.setLocation(privateer1);
igc.moveTo(dutch, privateer1, europe);
try {
igc.moveGoods(cotton, privateer2);
fail();
} catch (IllegalStateException e) {
}
// While source in Europe, target moving to America
privateer1.setLocation(europe);
igc.moveTo(dutch, privateer2, america);
cotton.setLocation(privateer1);
try {
igc.moveGoods(cotton, privateer2);
fail();
} catch (IllegalStateException e) {
}
// While source moving to America, target moving to America
cotton.setLocation(privateer1);
igc.moveTo(dutch, privateer1, america);
try {
igc.moveGoods(cotton, privateer2);
fail();
} catch (IllegalStateException e) {
}
// While source moving from America, target moving to America
cotton.setLocation(privateer1);
igc.moveTo(dutch, privateer1, europe);
try {
igc.moveGoods(cotton, privateer2);
fail();
} catch (IllegalStateException e) {
}
// While source in Europe, target moving from America
privateer1.setLocation(europe);
igc.moveTo(dutch, privateer2, europe);
cotton.setLocation(privateer1);
try {
igc.moveGoods(cotton, privateer2);
fail();
} catch (IllegalStateException e) {
}
// While source moving to America, target moving from America
cotton.setLocation(privateer1);
igc.moveTo(dutch, privateer1, america);
try {
igc.moveGoods(cotton, privateer2);
fail();
} catch (IllegalStateException e) {
}
// While source moving from America, target moving from America
cotton.setLocation(privateer1);
igc.moveTo(dutch, privateer1, europe);
try {
igc.moveGoods(cotton, privateer2);
fail();
} catch (IllegalStateException e) {
}
}
public void testCheckGameOverNoUnits() {
Game game = ServerTestHelper.startServerGame(getTestMap());
ServerPlayer dutch = (ServerPlayer)game.getPlayer("model.nation.dutch");
dutch.setGold(0);
assertEquals("Should not have units", 0, dutch.getUnits().size());
assertEquals("Should be game over due to no carrier", -1,
dutch.checkForDeath());
}
public void testCheckNoGameOverEnoughMoney() {
Game game = ServerTestHelper.startServerGame(getTestMap());
ServerPlayer dutch = (ServerPlayer)game.getPlayer("model.nation.dutch");
dutch.setGold(10000);
assertEquals("Should not be game, enough money", 0,
dutch.checkForDeath());
}
public void testCheckNoGameOverHasColonistInNewWorld() {
Map map = getTestMap();
Game game = ServerTestHelper.startServerGame(map);
ServerPlayer dutch = (ServerPlayer)game.getPlayer("model.nation.dutch");
dutch.setGold(0);
new ServerUnit(game, map.getTile(4, 7), dutch, colonistType);
assertEquals("Should not be game over, has units", 0,
dutch.checkForDeath());
}
public void testCheckGameOver1600Threshold() {
Map map = getTestMap();
Game game = ServerTestHelper.startServerGame(map);
ServerPlayer dutch = (ServerPlayer)game.getPlayer("model.nation.dutch");
dutch.setGold(0);
new ServerUnit(game, dutch.getEurope(), dutch, galleonType);
assertEquals("Should have 1 unit", 1, dutch.getUnits().size());
assertEquals("Should not be game over, not 1600 yet, autorecruit", 1,
dutch.checkForDeath());
new ServerUnit(game, dutch.getEurope(), dutch, colonistType);
assertEquals("Should have 2 units", 2, dutch.getUnits().size());
assertEquals("Should not be game over, not 1600 yet", 0,
dutch.checkForDeath());
game.setTurn(new Turn(1600));
assertEquals("Should be game over, no new world presence >= 1600", -1,
dutch.checkForDeath());
}
public void testCheckGameOverUnitsGoingToEurope() {
Map map = getTestMap(spec().getTileType("model.tile.highSeas"));
Game game = ServerTestHelper.startServerGame(map);
InGameController igc = ServerTestHelper.getInGameController();
ServerPlayer dutch = (ServerPlayer)game.getPlayer("model.nation.dutch");
dutch.setGold(0);
Unit galleon = new ServerUnit(game, map.getTile(6, 8), dutch,
galleonType);
Unit colonist = new ServerUnit(game, galleon, dutch, colonistType);
assertTrue("Colonist should be aboard the galleon",
colonist.getLocation() == galleon);
assertEquals("Galleon should have a colonist onboard",
1, galleon.getUnitCount());
igc.moveTo(dutch, galleon, dutch.getEurope());
assertEquals("Should not be game over, units between new world and europe", 0,
dutch.checkForDeath());
game.setTurn(new Turn(1600));
assertEquals("Should be game over, no new world presence >= 1600", -1,
dutch.checkForDeath());
}
public void testCheckGameOverUnitsGoingToNewWorld() {
Map map = getTestMap();
Game game = ServerTestHelper.startServerGame(map);
InGameController igc = ServerTestHelper.getInGameController();
ServerPlayer dutch = (ServerPlayer)game.getPlayer("model.nation.dutch");
dutch.setGold(0);
Unit galleon = new ServerUnit(game, dutch.getEurope(), dutch,
galleonType);
Unit colonist = new ServerUnit(game, galleon, dutch, colonistType);
assertEquals("Colonist should be aboard the galleon", galleon,
colonist.getLocation());
assertEquals("Galleon should have a colonist onboard", 1,
galleon.getUnitCount());
igc.moveTo(dutch, galleon, map);
assertEquals("Should not be game over, units between new world and europe", 0,
dutch.checkForDeath());
game.setTurn(new Turn(1600));
assertEquals("Should be game over, no new world presence >= 1600", -1,
dutch.checkForDeath());
}
public void testSellingMakesPricesFall() {
Game g = ServerTestHelper.startServerGame(getTestMap());
ServerPlayer p = (ServerPlayer)g.getPlayer("model.nation.dutch");
Market dm = p.getMarket();
int previousGold = p.getGold();
int price = spec().getInitialPrice(silverType);
p.sell(null, silverType, 1000, new Random());
assertEquals(previousGold + price * 1000, p.getGold());
assertTrue(dm.getSalePrice(silverType, 1) < price);
}
public void testBuyingMakesPricesRaise() {
Game game = ServerTestHelper.startServerGame(getTestMap());
ServerPlayer player = (ServerPlayer)game.getPlayer("model.nation.dutch");
Market dm = player.getMarket();
player.modifyGold(1000000);
int price = dm.getCostToBuy(foodType);
player.buy(new GoodsContainer(game, player.getEurope()), foodType,
10000, new Random());
assertEquals(1000000 - 10000 * price, player.getGold());
assertTrue(dm.getBidPrice(foodType, 1) > price);
}
/**
* Helper Method for finding out how much of a good to sell until
* the price drops.
*/
public int sellUntilPriceDrop(Game game, ServerPlayer player,
GoodsType type) {
Random random = new Random();
int result = 0;
Market market = player.getMarket();
int price = market.getSalePrice(type, 1);
if (price == 0)
throw new IllegalArgumentException("Price is already 0 for selling " + type);
while (price == market.getSalePrice(type, 1)){
player.sell(null, type, 10, random);
result++;
}
return result;
}
/*
* Helper method for finding out how much to buy of a good before the prices
* rises.
*/
public int buyUntilPriceRise(Game game, ServerPlayer player,
GoodsType type) {
Game g = ServerTestHelper.startServerGame(getTestMap());
Random random = new Random();
int result = 0;
Market market = player.getMarket();
int price = market.getBidPrice(type, 1);
if (price == 20)
throw new IllegalArgumentException("Price is already 20 for buying " + type);
GoodsContainer container = new GoodsContainer(game, player.getEurope());
while (price == market.getBidPrice(type, 1)) {
player.buy(container, type, 10, random);
result++;
}
return result;
}
/**
* Assert that the dutch nation has more stable prices than the other
* nations
*/
public void testDutchMarket() {
Game game = getStandardGame();
ServerPlayer dutch = (ServerPlayer)game.getPlayer("model.nation.dutch");
ServerPlayer french = (ServerPlayer)game.getPlayer("model.nation.french");
assertEquals("model.nationType.trade", dutch.getNationType().getId());
assertFalse(dutch.getNationType().getModifierSet("model.modifier.tradeBonus").isEmpty());
assertFalse(dutch.getModifierSet("model.modifier.tradeBonus").isEmpty());
{// Test that the dutch can sell more goods until the price drops
int dutchSellAmount = sellUntilPriceDrop(game, dutch, silverType);
Game g2 = getStandardGame();
ServerPlayer french2 = (ServerPlayer)g2.getPlayer("model.nation.french");
int frenchSellAmount = sellUntilPriceDrop(g2, french2, silverType);
assertTrue(dutchSellAmount > frenchSellAmount);
}
{// Test that the dutch can buy more goods until the price rises
dutch.modifyGold(10000);
french.modifyGold(10000);
int dutchBuyAmount = buyUntilPriceRise(getStandardGame(), dutch, musketsType);
int frenchBuyAmount = buyUntilPriceRise(getStandardGame(), french, musketsType);
assertTrue(dutchBuyAmount > frenchBuyAmount);
}
}
}