Fix limit evaluation for player settlement lists, BR#2873.

This commit is contained in:
Mike Pope 2015-07-25 12:23:32 +09:30
parent 8609f0908b
commit fe0fe8cfeb
4 changed files with 83 additions and 105 deletions

View File

@ -29,6 +29,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -265,6 +266,31 @@ public abstract class FreeColObject
lb.add("]");
}
/**
* Invoke a method for this object.
*
* @param methodName The name of the method.
* @param returnClass The class of the return value.
* @param defaultValue The default value.
* @return The result of invoking the method, or the default value
* on failure.
*/
protected <T> T invokeMethod(String methodName, Class<T> returnClass,
T defaultValue) {
if (methodName != null && returnClass != null) {
try {
Method method = getClass().getMethod(methodName);
if (method != null) {
return returnClass.cast(method.invoke(this));
}
} catch (Exception e) {
logger.log(Level.WARNING, "Invoke failed: " + methodName, e);
}
}
return defaultValue;
}
// Property change support
public void addPropertyChangeListener(PropertyChangeListener listener) {

View File

@ -19,8 +19,6 @@
package net.sf.freecol.common.model;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
@ -167,15 +165,9 @@ public class Operand extends Scope {
* @return The operand value or null if inapplicable.
*/
public Integer getValue(Game game) {
if (value == null) {
if (scopeLevel == ScopeLevel.GAME){
return calculateGameValue(game);
} else {
return null;
}
} else {
return value;
}
return (value != null) ? value
: (scopeLevel == ScopeLevel.GAME) ? calculateGameValue(game)
: null;
}
/**
@ -185,21 +177,10 @@ public class Operand extends Scope {
* @return The operand value.
*/
private Integer calculateGameValue(Game game) {
final String methodName = getMethodName();
switch (operandType) {
case NONE:
if (getMethodName() != null) {
try {
Method method = game.getClass().getMethod(getMethodName());
if (method != null &&
Integer.class.isAssignableFrom(method.getReturnType())) {
return (Integer) method.invoke(game);
}
} catch (Exception e) {
logger.log(Level.WARNING, "Unable to invoke: "
+ getMethodName(), e);
}
}
return null;
return game.invokeMethod(methodName, Integer.class, 0);
case YEAR:
return game.getTurn().getYear();
case OPTION:
@ -237,47 +218,47 @@ public class Operand extends Scope {
* @return The operand value, or null if inapplicable.
*/
public Integer getValue(Player player) {
if (value == null) {
if (scopeLevel == ScopeLevel.PLAYER) {
List<FreeColObject> list = new LinkedList<>();
switch (operandType) {
case UNITS:
return count(player.getUnits());
case BUILDINGS:
for (Colony colony : player.getColonies()) {
list.addAll(colony.getBuildings());
}
return count(list);
case SETTLEMENTS:
return count(player.getSettlements())
+ player.getSpecification()
.getInteger(GameOptions.SETTLEMENT_LIMIT_MODIFIER);
case FOUNDING_FATHERS:
list.addAll(player.getFathers());
return count(list);
default:
if (getMethodName() != null) {
try {
Method method = player.getClass().getMethod(getMethodName());
if (method != null
&& (int.class.equals(method.getReturnType())
|| Integer.class.equals(method.getReturnType()))) {
return (Integer) method.invoke(player);
}
} catch (Exception e) {
logger.log(Level.WARNING, "Unable to invoke: "
+ getMethodName(), e);
}
}
}
return null;
} else if (scopeLevel == ScopeLevel.GAME) {
return getValue(player.getGame());
} else {
return null;
if (value != null) return value;
switch (scopeLevel) {
case GAME:
return getValue(player.getGame());
case PLAYER: // Real case, handled below
break;
default: // Inapplicable
return null;
}
final Specification spec = player.getSpecification();
final String methodName = getMethodName();
List<FreeColObject> list = new LinkedList<>();
switch (operandType) {
case UNITS:
return count(player.getUnits());
case BUILDINGS:
for (Colony colony : player.getColonies()) {
list.addAll(colony.getBuildings());
}
} else {
return value;
return count(list);
case SETTLEMENTS:
if (methodName == null) {
return count(player.getSettlements())
+ spec.getInteger(GameOptions.SETTLEMENT_LIMIT_MODIFIER);
} else {
final String methodValue = getMethodValue();
int result = 0;
for (Settlement settlement : player.getSettlements()) {
Boolean b = settlement.invokeMethod(methodName,
Boolean.class, Boolean.FALSE);
if (String.valueOf(b).equals(methodValue)) result++;
}
return result;
}
case FOUNDING_FATHERS:
list.addAll(player.getFathers());
return count(list);
default:
return player.invokeMethod(methodName, Integer.class,
(Integer)null);
}
}
@ -301,20 +282,8 @@ public class Operand extends Scope {
list.addAll(colony.getBuildings());
break;
default:
if (getMethodName() != null) {
try {
Method method = colony.getClass().getMethod(getMethodName());
if (method != null &&
Integer.class.isAssignableFrom(method.getReturnType())) {
return (Integer) method.invoke(colony);
}
} catch (Exception e) {
logger.log(Level.WARNING, "Unable to invoke: "
+ getMethodName(), e);
return null;
}
}
return null;
return colony.invokeMethod(getMethodName(), Integer.class,
(Integer)null);
}
return count(list);
} else {

View File

@ -19,8 +19,6 @@
package net.sf.freecol.common.model;
import java.lang.reflect.Method;
import javax.xml.stream.XMLStreamException;
import net.sf.freecol.common.io.FreeColXMLReader;
@ -169,20 +167,10 @@ public class Scope extends FreeColObject {
if (!type.equals(object.getId())) {
return matchNegated;
}
} else if (object instanceof FreeColGameObject) {
try {
Method method = object.getClass().getMethod("getType");
if (method != null
&& FreeColGameObjectType.class.isAssignableFrom(method.getReturnType())) {
FreeColGameObjectType objectType =
(FreeColGameObjectType) method.invoke(object);
if (!type.equals(objectType.getId())) {
return matchNegated;
}
} else {
return matchNegated;
}
} catch (Exception e) {
} else if (object instanceof FreeColObject) {
FreeColGameObjectType fcgot = object.invokeMethod("getType",
FreeColGameObjectType.class, (FreeColGameObjectType)null);
if (fcgot == null || !type.equals(fcgot.getId())) {
return matchNegated;
}
} else {
@ -193,15 +181,8 @@ public class Scope extends FreeColObject {
return matchNegated;
}
if (methodName != null) {
try {
Method method = object.getClass().getMethod(methodName);
if (method != null
&& !String.valueOf(method.invoke(object)).equals(methodValue)) {
return matchNegated;
}
} catch (Exception e) {
return matchNegated;
}
Object ret = object.invokeMethod(methodName, Object.class, null);
if (!String.valueOf(ret).equals(methodValue)) return matchNegated;
}
return !matchNegated;
}

View File

@ -102,11 +102,13 @@ public class LimitTest extends FreeColTestCase {
assertFalse(rebelLimit.evaluate(dutch));
assertNotNull(colonyLimit);
assertEquals(Limit.Operator.GT, colonyLimit.getOperator());
assertEquals(Limit.Operator.GE, colonyLimit.getOperator());
assertEquals(Operand.OperandType.SETTLEMENTS, colonyLimit.getLeftHandSide().getOperandType());
assertEquals(Operand.ScopeLevel.PLAYER, colonyLimit.getLeftHandSide().getScopeLevel());
assertEquals("isConnectedPort", colonyLimit.getLeftHandSide().getMethodName());
assertFalse(colony.isConnectedPort());
assertEquals(Integer.valueOf(0), colonyLimit.getLeftHandSide().getValue(dutch));
assertEquals(Integer.valueOf(0), colonyLimit.getRightHandSide().getValue(dutch));
assertEquals(Integer.valueOf(1), colonyLimit.getRightHandSide().getValue(dutch));
assertFalse(colonyLimit.evaluate(dutch));
assertNotNull(yearLimit);