public Boolean canMoveSafely(
      Direction direction, Boolean moveAroundHQ, Boolean moveAroundTowers, Boolean moveAroundUnits)
      throws GameActionException {

    if (direction == null) return false;

    RobotController rc = this.robot.robotController;
    Boolean canMove = rc.canMove(direction);
    if (!canMove) return false;

    // run some initial checks
    MapLocation towerLocation = this.robot.locationController.enemyTowerInRange();
    if (towerLocation != null) moveAroundTowers = false;

    // start checking if we can move

    MapLocation currentLocation = this.robot.locationController.currentLocation();
    MapLocation moveLocation = currentLocation.add(direction);

    if (moveAroundHQ) {

      MapLocation[] towers = this.robot.unitController.enemyTowers();
      if (moveLocation.distanceSquaredTo(this.robot.locationController.enemyHQLocation())
          <= HQ.enemyAttackRadiusSquared(towers.length)) return false;
    }

    if (moveAroundTowers) {

      MapLocation[] towers = this.robot.unitController.enemyTowers();
      for (MapLocation tower : towers) {

        if (moveLocation.distanceSquaredTo(tower) <= Tower.type().attackRadiusSquared) return false;
      }
    }

    if (moveAroundUnits) {

      double buffer = 0;
      if (this.robot.type == Launcher.type()) buffer = 10;

      RobotInfo[] enemies = this.robot.unitController.nearbyEnemies();
      for (RobotInfo enemy : enemies) {

        this.robot.broadcaster.evaluateSeenLaunchersWithType(enemy.type);
        if (!UnitController.isUnitTypeDangerous(enemy.type)) continue;
        if (moveLocation.distanceSquaredTo(enemy.location)
            <= enemy.type.attackRadiusSquared + buffer) return false;
      }
    }

    /*RobotInfo[] enemies = this.robot.unitController.nearbyEnemies();
      for (RobotInfo enemy : enemies) {

      	this.robot.broadcaster.evaluateSeenLaunchersWithType(enemy.type);
    if (!UnitController.isUnitTypeDangerous(enemy.type)) continue;

    if (enemy.type == Launcher.type()) {

          	if (moveLocation.distanceSquaredTo(enemy.location) <= 60) return false;

    } else {

    	if (moveAroundUnits) {

              	if (moveLocation.distanceSquaredTo(enemy.location) <= enemy.type.attackRadiusSquared) return false;

      		}

    }

      }*/

    return true;
  }