use of soc.game.SOCShip in project JSettlers2 by jdmonin.
the class SOCDisplaylessPlayerClient method handlePUTPIECE.
/**
* handle the "put piece" message
*<P>
* This method is public static for access by
* {@code SOCRobotBrain.handlePUTPIECE_updateGameData(SOCPutPiece)}.
* @param mes the message
* @param ga Message's game from {@link SOCPutPiece#getGame()}; if {@code null}, message is ignored
*/
public static void handlePUTPIECE(final SOCPutPiece mes, SOCGame ga) {
if (ga != null) {
final int pieceType = mes.getPieceType();
final int coord = mes.getCoordinates();
final SOCPlayer pl = (pieceType != SOCPlayingPiece.VILLAGE) ? ga.getPlayer(mes.getPlayerNumber()) : null;
switch(pieceType) {
case SOCPlayingPiece.ROAD:
ga.putPiece(new SOCRoad(pl, coord, null));
break;
case SOCPlayingPiece.SETTLEMENT:
ga.putPiece(new SOCSettlement(pl, coord, null));
break;
case SOCPlayingPiece.CITY:
ga.putPiece(new SOCCity(pl, coord, null));
break;
case SOCPlayingPiece.SHIP:
ga.putPiece(new SOCShip(pl, coord, null));
break;
case SOCPlayingPiece.FORTRESS:
ga.putPiece(new SOCFortress(pl, coord, ga.getBoard()));
break;
case SOCPlayingPiece.VILLAGE:
ga.putPiece(new SOCVillage(coord, ga.getBoard()));
break;
default:
System.err.println("Displayless.handlePUTPIECE: game " + ga.getName() + ": Unknown pieceType " + pieceType);
}
}
}
use of soc.game.SOCShip in project JSettlers2 by jdmonin.
the class SOCGameMessageHandler method handleMOVEPIECE.
/**
* Handle the client's "move piece request" message.
* Currently, ships are the only pieces that can be moved.
*/
private void handleMOVEPIECE(SOCGame ga, Connection c, final SOCMovePiece mes) {
final String gaName = ga.getName();
boolean denyRequest = false;
final int fromEdge = mes.getFromCoord(), toEdge = mes.getToCoord();
if ((mes.getPieceType() != SOCPlayingPiece.SHIP) || !handler.checkTurn(c, ga)) {
denyRequest = true;
} else {
final int pn = ga.getCurrentPlayerNumber();
SOCShip moveShip = ga.canMoveShip(pn, fromEdge, toEdge);
if (moveShip == null) {
denyRequest = true;
} else {
final int gstate = ga.getGameState();
ga.moveShip(moveShip, toEdge);
srv.messageToGame(gaName, new SOCMovePiece(gaName, pn, SOCPlayingPiece.SHIP, fromEdge, toEdge));
if (!ga.pendingMessagesOut.isEmpty())
handler.sendGamePendingMessages(ga, true);
if (ga.getGameState() == SOCGame.WAITING_FOR_PICK_GOLD_RESOURCE) {
// If ship placement reveals a gold hex in _SC_FOG,
// the player gets to pick a free resource.
handler.sendGameState(ga, false, false);
handler.sendGameState_sendGoldPickAnnounceText(ga, gaName, c, null);
} else if (gstate != ga.getGameState()) {
// announce new state (such as PLACING_INV_ITEM in _SC_FTRI),
// or if state is now SOCGame.OVER, announce end of game
handler.sendGameState(ga, false, false);
}
}
}
if (denyRequest) {
D.ebugPrintln("ILLEGAL MOVEPIECE: 0x" + Integer.toHexString(fromEdge) + " -> 0x" + Integer.toHexString(toEdge) + ": player " + c.getData());
// "You can't move that ship now."
srv.messageToPlayerKeyed(c, gaName, "reply.movepiece.cannot.now.ship");
srv.messageToPlayer(c, new SOCCancelBuildRequest(gaName, SOCPlayingPiece.SHIP));
}
}
use of soc.game.SOCShip in project JSettlers2 by jdmonin.
the class SOCPlayerTracker method updateLRPotential.
/**
* update the potential LR value of a possible road or ship
* by placing dummy roads/ships and calculating LR (longest road).
* If <tt>level</tt> > 0, add the new roads or ships adjacent
* to <tt>dummy</tt> and recurse.
*
* @param posRoad the possible road or ship
* @param dummy the dummy player
* @param lrLength the current LR length
* @param level how many levels of recursion, or 0 to not recurse
*/
public void updateLRPotential(SOCPossibleRoad posRoad, SOCPlayer dummy, SOCRoad dummyRoad, final int lrLength, final int level) {
// D.ebugPrintln("$$$ updateLRPotential for road at "+Integer.toHexString(posRoad.getCoordinates())+" level="+level);
//
// if we've reached the bottom level of recursion,
// or if there are no more roads to place from this one.
// then calc potential LR value
//
SOCBoard board = game.getBoard();
boolean noMoreExpansion;
if (level <= 0) {
noMoreExpansion = true;
} else {
noMoreExpansion = false;
Enumeration<Integer> adjEdgeEnum = board.getAdjacentEdgesToEdge(dummyRoad.getCoordinates()).elements();
while (adjEdgeEnum.hasMoreElements()) {
final int adjEdge = adjEdgeEnum.nextElement().intValue();
if ((dummyRoad.isRoadNotShip() && dummy.isPotentialRoad(adjEdge)) || ((!dummyRoad.isRoadNotShip()) && dummy.isPotentialShip(adjEdge))) {
noMoreExpansion = false;
break;
}
}
}
if (noMoreExpansion) {
//
// only update the potential LR if it's bigger than the
// current value
//
int newPotentialLRValue = dummy.calcLongestRoad2() - lrLength;
// D.ebugPrintln("$$$ newPotentialLRValue = "+newPotentialLRValue);
if (newPotentialLRValue > posRoad.getLRPotential()) {
posRoad.setLRPotential(newPotentialLRValue);
}
} else {
//
// we need to add new roads/ships adjacent to dummyRoad, and recurse
//
Enumeration<Integer> adjEdgeEnum = board.getAdjacentEdgesToEdge(dummyRoad.getCoordinates()).elements();
while (adjEdgeEnum.hasMoreElements()) {
final int adjEdge = adjEdgeEnum.nextElement().intValue();
if ((dummyRoad.isRoadNotShip() && dummy.isPotentialRoad(adjEdge)) || ((!dummyRoad.isRoadNotShip()) && dummy.isPotentialShip(adjEdge))) {
SOCRoad newDummyRoad;
if (dummyRoad.isRoadNotShip())
newDummyRoad = new SOCRoad(dummy, adjEdge, board);
else
newDummyRoad = new SOCShip(dummy, adjEdge, board);
dummy.putPiece(newDummyRoad, true);
updateLRPotential(posRoad, dummy, newDummyRoad, lrLength, level - 1);
dummy.removePiece(newDummyRoad, null);
}
}
}
}
use of soc.game.SOCShip in project JSettlers2 by jdmonin.
the class SOCPlayerTracker method recalcScenario_SC_PIRI_nextPotentialShip.
/**
* For scenario {@code _SC_PIRI}, get the player's next potential ship towards their Fortress.
* If fortress was already defeated, or they have no boats, returns {@code null}.
*<P>
* This is calculated every time, not cached, because potential-ships list may change often.
* Calls {@link #updateScenario_SC_PIRI_closestShipToFortress(SOCShip, boolean)} if closest ship not known.
*
* @return Next potential ship, or {@code null}
* @since 2.0.00
*/
SOCPossibleShip recalcScenario_SC_PIRI_nextPotentialShip() {
// may be null towards end of game
final SOCFortress fort = player.getFortress();
if (fort == null)
// <--- Early return: already defeated fortress ---
return null;
final int fortR = fort.getCoordinates() >> 8;
if (scen_SC_PIRI_closestShipToFortress == null)
updateScenario_SC_PIRI_closestShipToFortress(null, false);
final SOCShip closest = scen_SC_PIRI_closestShipToFortress;
if (closest == null)
// <--- Early return: no ships ---
return null;
final List<Integer> closestAdjacs = ((SOCBoardLarge) game.getBoard()).getAdjacentEdgesToEdge(closest.getCoordinates());
SOCPossibleShip nextShip = null;
int nextR = -1, nextC = -1;
for (Integer edge : closestAdjacs) {
final SOCPossibleRoad rs = possibleRoads.get(edge);
if ((rs == null) || !(rs instanceof SOCPossibleShip))
continue;
final int shipEdge = rs.getCoordinates();
final int shipR = shipEdge >> 8, shipC = shipEdge & 0xFF;
if ((nextShip == null) || (shipC < nextC) || ((shipC == nextC) && (Math.abs(shipR - fortR) < Math.abs(nextR - fortR)))) {
nextShip = (SOCPossibleShip) rs;
nextR = shipR;
nextC = shipC;
}
}
return nextShip;
}
use of soc.game.SOCShip in project JSettlers2 by jdmonin.
the class SOCPlayerTracker method expandRoadOrShip.
/**
* Expand a possible road or ship, to see what placements it makes possible.
*<UL>
*<LI> Creates {@code dummyRoad}: A copy of {@code targetRoad} owned by {@code dummy}
*<LI> Calls {@link SOCPlayer#putPiece(SOCPlayingPiece, boolean) dummy.putPiece(dummyRoad, true)}
*<LI> Adds to or updates {@link #possibleSettlements} at <tt>targetRoad</tt>'s nodes, if potential
*<LI> If {@code level > 0}: Calls itself recursively to go more levels out from the current pieces,
* adding/updating {@link #possibleRoads} and {@link #possibleSettlements}
*<LI> Calls {@link SOCPlayer#removePiece(SOCPlayingPiece, SOCPlayingPiece) dummy.removePiece(dummyRoad, null)}
*</UL>
*<P>
* <b>Scenario {@code _SC_PIRI}</b>: Ships in this scenario never expand east (never away from the
* pirate fortress). Scenario rules require the route to be as short as possible. Even if another (human)
* player might want to do so, they couldn't interfere with the bot's own route, so we don't track
* that possibility.
*
* @param targetRoad the possible road
* @param player the player who owns the original road
* @param dummy the dummy player used to see what's legal; created by caller copying {@code player}
* @param trackers player trackers
* @param level how many levels (additional pieces) to expand;
* 0 to only check <tt>targetRoad</tt> for potential settlements
* and not expand past it for new roads, ships, or further settlements.
* If {@code level > 0} but {@code dummy} has no more roads or ships
* (depending on {@link SOCPossibleRoad#isRoadNotShip() targetRoad.isRoadNotShip()}),
* acts as if {@code level == 0}.
*/
public void expandRoadOrShip(final SOCPossibleRoad targetRoad, final SOCPlayer player, final SOCPlayer dummy, HashMap<Integer, SOCPlayerTracker> trackers, final int level) {
// D.ebugPrintln("$$$ expandRoad at "+Integer.toHexString(targetRoad.getCoordinates())+" level="+level);
final SOCBoard board = game.getBoard();
final int tgtRoadEdge = targetRoad.getCoordinates();
final boolean isRoadNotShip = targetRoad.isRoadNotShip();
final SOCRoad dummyRoad;
if (isRoadNotShip || ((targetRoad instanceof SOCPossibleShip) && ((SOCPossibleShip) targetRoad).isCoastalRoadAndShip))
dummyRoad = new SOCRoad(dummy, tgtRoadEdge, board);
else
// TODO better handling for coastal roads/ships
dummyRoad = new SOCShip(dummy, tgtRoadEdge, board);
dummy.putPiece(dummyRoad, true);
//
for (Integer adjNode : board.getAdjacentNodesToEdge(tgtRoadEdge)) {
if (dummy.canPlaceSettlement(adjNode.intValue())) {
//
// see if possible settlement is already in the list
//
// D.ebugPrintln("$$$ seeing if "+Integer.toHexString(adjNode.intValue())+" is already in the list");
SOCPossibleSettlement posSet = possibleSettlements.get(adjNode);
if (posSet != null) {
//
if (!(posSet.getNecessaryRoads().isEmpty() || posSet.getNecessaryRoads().contains(targetRoad))) {
//
// add target road to settlement's nr list and this settlement to the road's np list
//
// D.ebugPrintln("$$$ adding road "+Integer.toHexString(targetRoad.getCoordinates())+" to the settlement "+Integer.toHexString(posSet.getCoordinates()));
posSet.addNecessaryRoad(targetRoad);
targetRoad.addNewPossibility(posSet);
//
if ((targetRoad.getNumberOfNecessaryRoads() + 1) < posSet.getNumberOfNecessaryRoads()) {
posSet.setNumberOfNecessaryRoads(targetRoad.getNumberOfNecessaryRoads() + 1);
}
}
} else {
//
// else, add new possible settlement
//
// D.ebugPrintln("$$$ adding new possible settlement at "+Integer.toHexString(adjNode.intValue()));
List<SOCPossibleRoad> nr = new ArrayList<SOCPossibleRoad>();
nr.add(targetRoad);
SOCPossibleSettlement newPosSet = new SOCPossibleSettlement(player, adjNode.intValue(), nr);
newPosSet.setNumberOfNecessaryRoads(targetRoad.getNumberOfNecessaryRoads() + 1);
possibleSettlements.put(adjNode, newPosSet);
targetRoad.addNewPossibility(newPosSet);
updateSettlementConflicts(newPosSet, trackers);
}
}
}
if ((level > 0) && (0 < dummy.getNumPieces(isRoadNotShip ? SOCPlayingPiece.ROAD : SOCPlayingPiece.SHIP))) {
//
// check for new possible roads or ships.
// The above getNumPieces check ignores any possible ship <-> road transition at a coastal settlement.
//
ArrayList<SOCPossibleRoad> newPossibleRoads = new ArrayList<SOCPossibleRoad>();
ArrayList<SOCPossibleRoad> roadsToExpand = new ArrayList<SOCPossibleRoad>();
// ships in _SC_PIRI never expand east
final boolean isShipInSC_PIRI = (!isRoadNotShip) && game.isGameOptionSet(SOCGameOption.K_SC_PIRI);
// D.ebugPrintln("$$$ checking roads adjacent to "+Integer.toHexString(targetRoad.getCoordinates()));
//
// check adjacent edges to road or ship
//
Enumeration<Integer> adjEdgesEnum = board.getAdjacentEdgesToEdge(tgtRoadEdge).elements();
while (adjEdgesEnum.hasMoreElements()) {
Integer adjEdge = adjEdgesEnum.nextElement();
final int edge = adjEdge.intValue();
if (isShipInSC_PIRI) {
final int tgtEdgeCol = tgtRoadEdge & 0xFF, adjEdgeCol = edge & 0xFF;
if (// adjacent goes north/south from eastern node of diagonal target edge
(adjEdgeCol > tgtEdgeCol) || ((adjEdgeCol == tgtEdgeCol) && ((tgtRoadEdge & 0x100) != 0))) // adjacent goes northeast/southeast from vertical target edge (tgtRoadEdge is on odd row)
{
// <--- Ignore this eastern adjacent edge ---
continue;
}
}
// D.ebugPrintln("$$$ edge "+Integer.toHexString(adjEdge.intValue())+" is legal:"+dummy.isPotentialRoad(adjEdge.intValue()));
//
// see if edge is a potential road
// or ship to continue this route
//
boolean edgeIsPotentialRoute = (isRoadNotShip) ? dummy.isPotentialRoad(edge) : dummy.isPotentialShip(edge);
// If true, this edge transitions
// between ships <-> roads, at a
// coastal settlement
boolean edgeRequiresCoastalSettlement = false;
if ((!edgeIsPotentialRoute) && game.hasSeaBoard) {
// Determine if can transition ship <-> road
// at a coastal settlement
final int nodeBetween = ((SOCBoardLarge) board).getNodeBetweenAdjacentEdges(tgtRoadEdge, edge);
if (dummy.canPlaceSettlement(nodeBetween)) {
// check opposite type at transition
edgeIsPotentialRoute = (isRoadNotShip) ? dummy.isPotentialShip(edge) : dummy.isPotentialRoad(edge);
if (edgeIsPotentialRoute)
edgeRequiresCoastalSettlement = true;
}
}
if (edgeIsPotentialRoute) {
// Add 1 to road distance, unless
// it requires a coastal settlement
// (extra effort to build that)
final int incrDistance = edgeRequiresCoastalSettlement ? 3 : 1;
//
// see if possible road is already in the list
//
SOCPossibleRoad pr = possibleRoads.get(adjEdge);
if (pr != null) {
// For now, can't differ along a coastal route.
if (edgeRequiresCoastalSettlement && (isRoadNotShip != pr.isRoadNotShip())) {
// <--- road vs ship mismatch ---
continue;
}
//
// if so, and it needs 1 or more roads other than this one,
//
// D.ebugPrintln("$$$ pr "+Integer.toHexString(pr.getCoordinates())+" already in list");
List<SOCPossibleRoad> nr = pr.getNecessaryRoads();
if (!(nr.isEmpty() || nr.contains(targetRoad))) {
//
// add the target road to its nr list and the new road to the target road's np list
//
// D.ebugPrintln("$$$ adding "+Integer.toHexString(targetRoad.getCoordinates())+" to nr list");
nr.add(targetRoad);
targetRoad.addNewPossibility(pr);
//
if ((targetRoad.getNumberOfNecessaryRoads() + incrDistance) < pr.getNumberOfNecessaryRoads()) {
pr.setNumberOfNecessaryRoads(targetRoad.getNumberOfNecessaryRoads() + incrDistance);
}
}
if (!pr.hasBeenExpanded()) {
roadsToExpand.add(pr);
pr.setExpandedFlag();
}
} else {
//
// else, add new possible road or ship
//
// D.ebugPrintln("$$$ adding new pr at "+Integer.toHexString(adjEdge.intValue()));
ArrayList<SOCPossibleRoad> neededRoads = new ArrayList<SOCPossibleRoad>();
neededRoads.add(targetRoad);
SOCPossibleRoad newPR;
boolean isRoad = isRoadNotShip;
if (edgeRequiresCoastalSettlement)
isRoad = !isRoad;
// use coastal road/ship type (isCoastalRoadAndShip) only if the road/ship
// being expanded is coastal, or if we can require a coastal settlement to
// switch from road-only or ship-only
final boolean isCoastal = dummy.isPotentialRoad(edge) && dummy.isPotentialShip(edge) && (edgeRequiresCoastalSettlement || ((targetRoad instanceof SOCPossibleShip) && ((SOCPossibleShip) targetRoad).isCoastalRoadAndShip));
if (isRoad && !isCoastal) {
newPR = new SOCPossibleRoad(player, edge, neededRoads);
} else {
newPR = new SOCPossibleShip(player, edge, isCoastal, neededRoads);
System.err.println("L1072: " + toString() + ": new PossibleShip(" + isCoastal + ") at 0x" + Integer.toHexString(edge));
}
newPR.setNumberOfNecessaryRoads(targetRoad.getNumberOfNecessaryRoads() + incrDistance);
targetRoad.addNewPossibility(newPR);
newPossibleRoads.add(newPR);
roadsToExpand.add(newPR);
newPR.setExpandedFlag();
}
}
}
//
for (SOCPossibleRoad newPR : newPossibleRoads) {
possibleRoads.put(Integer.valueOf(newPR.getCoordinates()), newPR);
}
//
for (SOCPossibleRoad expandPR : roadsToExpand) {
expandRoadOrShip(expandPR, player, dummy, trackers, level - 1);
}
}
//
// remove the dummy road
//
dummy.removePiece(dummyRoad, null);
}
Aggregations