@Override
 public void initFeature(Tile tile, Feature feature, Element xml) {
   if (!(feature instanceof Road)) return;
   Road road = (Road) feature;
   if (road.isTunnelEnd()) {
     tunnels.add(road);
   }
 }
 @Override
 public void loadFromSnapshot(Document doc, Element node) {
   NodeList nl = node.getElementsByTagName("tunnel");
   for (int i = 0; i < nl.getLength(); i++) {
     Element el = (Element) nl.item(i);
     Position pos = XmlUtils.extractPosition(el);
     Location loc = Location.valueOf(el.getAttribute("location"));
     Road road = (Road) getBoard().get(pos).getFeature(loc);
     if (!road.isTunnelEnd()) {
       logger.error("Tunnel end does not exist.");
       continue;
     }
     Player player = game.getPlayer(Integer.parseInt(el.getAttribute("player")));
     boolean isB = "yes".equals(el.getAttribute("b"));
     road.setTunnelEnd(getTunnelId(player, isB));
     game.post(new TunnelPiecePlacedEvent(player, pos, loc, isB));
   }
 }
  @Override
  public void prepareActions(List<PlayerAction<?>> actions, Set<FeaturePointer> commonSites) {
    if (isTunnelUsedThisTurn()) return;
    if (getOpenTunnels().isEmpty()) return;

    List<TunnelAction> tunnelActions = new ArrayList<>(2);
    TunnelAction tunnelAction = null;
    if (getTunnelTokens(game.getActivePlayer(), false) > 0) {
      tunnelActions.add(new TunnelAction(false));
    }
    if (getTunnelTokens(game.getActivePlayer(), true) > 0) {
      tunnelActions.add(new TunnelAction(true));
    }
    for (TunnelAction ta : tunnelActions) {
      for (Road tunnelEnd : getOpenTunnels()) {
        ta.add(new FeaturePointer(getTile().getPosition(), tunnelEnd.getLocation()));
      }
    }
    actions.addAll(tunnelActions);
  }
 @Override
 public void saveToSnapshot(Document doc, Element node) {
   for (Road tunnel : tunnels) {
     if (tunnel.getTile().getPosition() != null && tunnel.getTunnelEnd() != Road.OPEN_TUNNEL) {
       Element el = doc.createElement("tunnel");
       node.appendChild(el);
       XmlUtils.injectPosition(el, tunnel.getTile().getPosition());
       el.setAttribute("location", tunnel.getLocation().toString());
       el.setAttribute("player", "" + (tunnel.getTunnelEnd() % 100));
       el.setAttribute("b", tunnel.getTunnelEnd() > 100 ? "yes" : "no");
     }
   }
 }
 public void placeTunnelPiece(Position p, Location loc, boolean isB) {
   Road road = (Road) getBoard().get(p).getFeature(loc);
   if (!road.isTunnelOpen()) {
     throw new IllegalStateException("No open tunnel here.");
   }
   Player player = game.getActivePlayer();
   int connectionId = getTunnelId(player, isB);
   decreaseTunnelTokens(player, isB);
   for (Road r : tunnels) {
     if (r.getTunnelEnd() == connectionId) {
       r.setTunnelEdge(road);
       road.setTunnelEdge(r);
       break;
     }
   }
   road.setTunnelEnd(connectionId);
   placedTunnelCurrentTurn = road;
   game.post(new TunnelPiecePlacedEvent(player, p, loc, isB));
 }