/**
   * Implements Speed special movement/attack model.
   *
   * @param board
   * @param mtkn
   * @return
   */
  public List<Vector2D> powerMovementSystemSpeed(Board board, MovablePlayerToken mtkn) {
    List<Vector2D> movements = new ArrayList<Vector2D>();
    List<Vector2D> extraMovements = new ArrayList<Vector2D>();
    // Make consecutive movements:
    int x = mtkn.getCol();
    int y = mtkn.getRow();

    movements.add(new Vector2D(y - 1, x));
    movements.add(new Vector2D(y + 1, x));
    movements.add(new Vector2D(y, x - 1));
    movements.add(new Vector2D(y, x + 1));

    movements = validInBoard(movements);
    movements = validInPlayer(board, movements);

    for (int k = 0; k < movements.size(); k++) {
      if (board.getToken(movements.get(k).y, movements.get(k).x).getOwn()
          != this.getTurn().otherSide()) {
        extraMovements.add(new Vector2D(movements.get(k).y - 1, movements.get(k).x));
        extraMovements.add(new Vector2D(movements.get(k).y + 1, movements.get(k).x));
        extraMovements.add(new Vector2D(movements.get(k).y, movements.get(k).x - 1));
        extraMovements.add(new Vector2D(movements.get(k).y, movements.get(k).x + 1));
      }
    }

    extraMovements = validInBoard(extraMovements);
    extraMovements = validInPlayer(board, extraMovements);

    movements.addAll(extraMovements);

    return movements;
  }
  public void moveToken(Board board, MovablePlayerToken src, Vector2D trgloc) {
    // A move happens only between a movablePlayerToken and Grass token:

    // Swap tokens:
    int tmpc = src.getCol();
    int tmpr = src.getRow();
    // Update position of source token:
    this.insertToken2Board(board, src, trgloc.y, trgloc.x);
    // fill the space with grass:
    this.insertToken2Board(board, StrategoBoard.grassToken, tmpr, tmpc);
  }
  /**
   * Implements Range special attack model.
   *
   * @param board
   * @param mtkn
   * @return
   */
  public List<Vector2D> powerMovementSystemRange(Board board, MovablePlayerToken mtkn) {
    List<Vector2D> movements = new ArrayList<Vector2D>();

    int x = mtkn.getCol();
    int y = mtkn.getRow();

    for (int i = -2; i <= 2; i++) {
      for (int j = -2; j <= 2; j++) {
        movements.add(new Vector2D(y + i, x + j));
      }
    }

    movements = validInBoard(movements);
    movements = validInPlayer(board, movements);

    // Because this system implements ranged attack,
    // valid targets are only enemy tokens:
    movements = validForAttack(board, movements);

    return movements;
  }
 /**
  * <b>pre-condition</b>: The Token to exist in Board. Computes valid movement locations for the
  * token in board.
  *
  * @param board
  * @param tkn
  * @return
  */
 public List<Vector2D> tokenSelection(Board board, Token tkn) {
   // List<Vector2D> moveLocations = new ArrayList<Vector2D>();
   this.moveLocations = new ArrayList<Vector2D>();
   // Determine if action is valid (is permitted):
   if (tkn instanceof MovablePlayerToken) {
     // Get available positions for movement/attack
     // based on token class:
     MovablePlayerToken mtkn = (MovablePlayerToken) tkn;
     // Special movement pattern for scouts, based on state of the board:
     if (mtkn instanceof Scout) {
       this.moveLocations = movementSystemScout(board, (Scout) mtkn);
     } else {
       // Get ABSOLUTE board locations:
       this.moveLocations = mtkn.getMovePattern();
       // Vector2D pos = new Vector2D(mtkn.getRow(),mtkn.getCol());
       // Check what locations are valid on the board:
       this.moveLocations = validInBoard(this.moveLocations);
       this.moveLocations = validInPlayer(board, this.moveLocations);
     }
   }
   // else return empty valid move locations:
   return this.moveLocations;
 }
 /**
  * Saves the lost (input) Token and places it back to the board in the first empty position. If no
  * empty position Token is not saved.
  *
  * @param board
  * @param tkn
  * @return
  */
 public boolean saveToken(Board board, MovablePlayerToken tkn) {
   // Check if input Token is indeed killed;
   if (tkn.getCol() >= 0) {
     return false;
   }
   // Move the selected Token into the board (if possible!):
   if (getTurn().side().pname.equals("Fire")) {
     // find the first empty spot:
     for (int k = 0; k < 30; k++) {
       int r = k / 10 + 5;
       int c = k % 10;
       if (board.getToken(r, c) instanceof Grass) {
         this.insertToken2Board(board, tkn, r, c);
         return true;
       }
     }
   }
   return false;
 }
 public void attackToken(
     Board board, MovablePlayerToken src, PlayerToken trg, boolean specialPower) {
   // An attack happens only between PlayerTokens:
   // perform attack method of source token:
   String outcome = "";
   // No need for an extra attack method, just interpret differently the results.
   if (specialPower && (src instanceof SpecialMovablePlayerToken)) {
     SpecialMovablePlayerToken scltkn = (SpecialMovablePlayerToken) src;
     outcome = scltkn.specialAttackTo(trg);
   } else {
     outcome = src.attackTo(trg);
   }
   if (outcome.equals("won")) {
     // Save location:
     int tmpc = trg.getCol();
     int tmpr = trg.getRow();
     // Remove token that lost from the board:
     takeToken(board, trg);
     // move token that won to its place:
     this.moveToken(board, src, new Vector2D(tmpr, tmpc));
   } else if (outcome.equals("lost")) {
     // Remove token that lost from the board:
     takeToken(board, src);
   } else if (outcome.equals("tie")) {
     // remove both tokens from the board:
     takeToken(board, src);
     takeToken(board, trg);
   } else if (outcome.equals("wonNotMove")) {
     // Remove token that lost from the board:
     takeToken(board, trg);
   } else if (outcome.equals("nothing")) {
     // Nothing happens in the board.
   } else if (outcome.equals("convert")) {
     // Target Token is converted to the other side (probably
     // due to cookies)..
     convertToken(board, trg);
   }
 }
  /**
   * Performs an action from source token to the target token. Actions can be: 1. Nothing (action
   * not permitted) 2. Move (valid movement action) 3. Attack (valid attack action)
   *
   * @param src The source token
   * @param trg The target token
   * @return The outcome of the action was successful. False: no action whatsoever.
   */
  public boolean tokenAction(
      Board board,
      Token src,
      Token trg,
      Vector2D trgloc,
      StrategoAppViewer viewer,
      boolean specialPower) {
    // List<Vector2D> moveLocations = new ArrayList<Vector2D>();
    // Determine if action is valid (is permitted):
    // Token action is already validated by the viewer, but the controller ought to check:
    // (in case viewer is not used):
    boolean found = false;
    // Get available positions for movement/attack:
    if (specialPower) {
      this.moveLocations = tokenSpecialSelection(board, src);
    } else {
      this.moveLocations = tokenSelection(board, src);
    }

    for (int i = 0; i < this.moveLocations.size(); i++) {
      if ((trgloc.y == this.moveLocations.get(i).y) && (trgloc.x == this.moveLocations.get(i).x)) {
        found = true;
        break;
      }
    }
    // if no valid movement/token detected: do not execute action:
    if (!found) {
      return false;
    }
    // Now that the movement is permitted:
    // Check what token action to perform:
    if (trg instanceof BackgroundToken) {
      // Grass is the only move-onto background token:
      this.moveToken(board, (MovablePlayerToken) src, trgloc);
    } else {
      // else this is an attack:
      this.attackToken(board, (MovablePlayerToken) src, (PlayerToken) trg, specialPower);
    }

    MovablePlayerToken saviour = null;
    // Check if a token moved in enemy's back row:

    for (int k = 0; k < getTurn().side().tokens.size(); k++) {
      if (getTurn().side().pname == "Fire") {
        if ((getTurn().side().tokens.get(k).getRow() == 0)) {
          saviour = (MovablePlayerToken) getTurn().side().tokens.get(k);
        }
      } else {
        if ((getTurn().side().tokens.get(k).getRow() == 7)) {
          saviour = (MovablePlayerToken) getTurn().side().tokens.get(k);
        }
      }
    }
    // Scouts can not save tokens:
    if (saviour instanceof Scout) {
      saviour = null;
    } else if (getTurn().side().getTotalSaves() > 2) {
      // Can not save more than twice:
      saviour = null;
    } else if ((saviour != null) && saviour.savedToken()) {
      // Can not save more than twice:
      // Get a random Token to save:
      for (int k = 0; k < getTurn().side().tokens.size(); k++) {
        if (getTurn().side().tokens.get(k).getCol() < 0) {
          if (getTurn().side().tokens.get(k) instanceof MovablePlayerToken) {
            if (saveToken(board, (MovablePlayerToken) getTurn().side().tokens.get(k))) {
              break;
            }
          }
        }
      }
    }

    // if player turn completed successfully, check if winning condition:
    getTurn().setWinner(doWeHaveAWinner(board, getTurn()));
    // Else change sides:
    if (getTurn().getWinner() == null) {
      getTurn().flip();
    } else {
      endGame(getTurn());
    }

    return true;
  }