コード例 #1
0
ファイル: HybridMover.java プロジェクト: jalman/armada
  private boolean moveToPath() throws GameActionException {
    if (dstar == null) {
      dstar = new DStar(outPath, distances, currentLocation);
    }

    if (!dstar.arrived(currentLocation)) {
      dstar.compute(7000);
    }

    if (!RC.isActive()) return true;

    Direction dir = Direction.NORTH, best = null;
    int min = Integer.MAX_VALUE;
    for (int i = 0; i < 8; i++) {

      int d = RC.canMove(dir) ? dstar.getDistance(currentLocation.add(dir)) : Integer.MAX_VALUE;
      if (d < min) {
        min = d;
        best = dir;
      }
      dir = dir.rotateRight();
    }

    if (best != null && move(best)) {
      RC.setIndicatorString(1, "Moving to outPath");
      return true;
    } else {
      return false;
    }
  }
コード例 #2
0
ファイル: SoldierBehavior.java プロジェクト: jalman/armada
  private MapLocation findRichSquare() {
    double maxCows = currentCowsHere + 50 * COW_GROWTH[curX][curY] + 300; // favor staying here
    double curCows;

    MapLocation best = currentLocation;
    for (MapLocation current :
        MapLocation.getAllMapLocationsWithinRadiusSq(
            currentLocation, RobotType.SOLDIER.sensorRadiusSquared)) {
      try {
        if (RC.senseTerrainTile(current) == TerrainTile.OFF_MAP) continue;

        curCows = RC.senseCowsAtLocation(current) + 50 * COW_GROWTH[current.x][current.y];
        if (curCows > maxCows && RC.senseObjectAtLocation(current) == null) {
          best = current;
          maxCows = curCows;
        }
      } catch (GameActionException e) {
        e.printStackTrace();
      }
    }

    RC.setIndicatorString(1, "max nearby cows: " + maxCows + " at " + best);
    if (maxCows > 1000) {
      return best;
    }

    return null;
  }
コード例 #3
0
ファイル: HybridMover.java プロジェクト: jalman/armada
 private boolean move(Direction dir) throws GameActionException {
   if (!RC.isActive() || !RC.canMove(dir)) return false;
   switch (movementType) {
     case SNEAK:
       RC.sneak(dir);
       break;
     case RUN:
       RC.move(dir);
       break;
   }
   return true;
 }
コード例 #4
0
ファイル: NoiseTowerBehavior.java プロジェクト: jalman/armada
  /** Called every round. */
  @Override
  public void run() throws GameActionException {
    while (!RC.isActive()) {
      RC.yield();
    }
    Robot[] robots = Utils.RC.senseNearbyGameObjects(Robot.class, 35, ENEMY_TEAM);
    Utils.RC.setIndicatorString(1, "" + robots.length);
    for (int i = 0; i < robots.length; ++i) {
      messagingSystem.writeAttackMessage(Utils.RC.senseRobotInfo(robots[i]).location);
      messagingSystem.writeMicroMessage(Utils.RC.senseRobotInfo(robots[i]).location, 1);
    }

    makeSomeNoise();
  }
コード例 #5
0
ファイル: NoiseTowerBehavior.java プロジェクト: jalman/armada
 public static boolean pathbetween(MapLocation a, MapLocation b) {
   while (!a.equals(b)) {
     a = a.add(a.directionTo(b));
     if (RC.senseTerrainTile(a) == TerrainTile.VOID) return false;
   }
   return true;
 }
コード例 #6
0
ファイル: HybridMover.java プロジェクト: jalman/armada
  private void computeOutPath() throws GameActionException {
    Pair<Direction, Integer> pathingInfo = messagingSystem.readPathingInfo(dest);
    if (pathingInfo.first == null) {
      outPath = null;
      return;
    }
    RC.setIndicatorString(1, "Computing outPath");

    outPath = new LocSet();
    distances = new int[MAP_SIZE];
    MapLocation loc = dest;
    int d = pathingInfo.second;
    while (!loc.equals(DIJKSTRA_CENTER)) {
      pathingInfo = messagingSystem.readPathingInfo(loc);
      distances[outPath.size] = d - pathingInfo.second;
      outPath.insert(loc);
      loc = loc.subtract(pathingInfo.first);
    }

    int[] diffs = new int[outPath.size - 1];
    for (int i = diffs.length; --i > 0; ) {
      diffs[i] = distances[i + 1] - distances[i];
    }

    // heuristic to prefer further away points on the path (which may be closer to us)
    for (int i = 1; i < outPath.size; i++) {
      distances[i] = distances[i - 1] + Math.max(1, diffs[i - 1] * 100 / (100 + 10 * i));
    }
  }
コード例 #7
0
ファイル: BFSNoiseTower.java プロジェクト: jalman/armada
 public void earlyNearbyCows() throws GameActionException {
   target = null;
   double numCows = -1.0;
   for (int x = -8; x <= 8; x++) {
     for (int y = -8; y <= 8; y++) {
       MapLocation lookat = currentLocation.add(x, y);
       if (lookat.distanceSquaredTo(ALLY_PASTR_COUNT > 0 ? ALLY_PASTR_LOCS[0] : currentLocation)
               <= 5
           || !RC.canSenseSquare(lookat)) continue;
       double t = RC.senseCowsAtLocation(lookat);
       if (t > numCows) {
         numCows = t;
         target = lookat;
       }
     }
   }
   System.out.println("target" + target + "  numcows " + numCows);
 }
コード例 #8
0
ファイル: HybridMover.java プロジェクト: jalman/armada
  public void move(MovementType movementType) throws GameActionException {
    if (currentLocation.equals(dest)) return;

    this.movementType = movementType;

    // try computing the outpath if it isn't set
    if (outPath == null) {
      computeOutPath();
    }

    if (outPath != null) {
      if (!moveToPath()) {
        simpleMove(dest);
        RC.setIndicatorString(1, "dstar failed, simpleMove to dest");
      }
    } else {
      simpleMove(dest);
      RC.setIndicatorString(1, "no outPath, simpleMove to dest");
    }
  }
コード例 #9
0
ファイル: HybridMover.java プロジェクト: jalman/armada
  private void simpleMove(MapLocation loc) throws GameActionException {
    if (!loc.equals(simpleTarget)) {
      simpleTarget = loc;
      simple.recompute(loc);
    }

    Direction dir = simple.getNextDir();
    if (RC.canMove(dir)) {
      move(dir);
    }
  }
コード例 #10
0
ファイル: NoiseTowerBehavior.java プロジェクト: jalman/armada
  public static void makeSomeNoise() throws GameActionException { // assumes RC is active

    incrementAB();

    if (b < pathat[a] - 1
        && b > 1
        && paths[a][b] != null
        && paths[a][b + 1] != null
        && paths[a][b - 1] != null) {
      if (paths[a][b].directionTo(paths[a][b + 1]) == paths[a][b - 1].directionTo(paths[a][b])) {
        b--;
      }
    }

    if (paths[a][b] != null) {
      if (RC.canAttackSquare(paths[a][b].add(directions[a]))) {
        RC.attackSquare(paths[a][b].add(directions[a]));
      } else {
        makeSomeNoise();
      }
    }
  }
コード例 #11
0
ファイル: Mover.java プロジェクト: jalman/armada
  /**
   * Try to move.
   *
   * @param sneak:
   * @return
   */
  public void execute(int sneak) {
    // int bc = Clock.getBytecodesLeft();
    // RC.setIndicatorString(1, "my x = " + Integer.toString(RC.getLocation().x) + ", my y = " +
    // Integer.toString(RC.getLocation().y)
    // + "x = " + Integer.toString(dest.x) + ", y = " + Integer.toString(dest.y));
    // RC.setIndicatorString(2, Clock.getRoundNum() + " | dest = " + dest + ", navtype = " +
    // navType);

    if (arrived()) return;

    if (RC.isActive()) {
      Direction d;
      d = navAlg.getNextDir();
      if (d != null && d != Direction.NONE && d != Direction.OMNI) {
        if (RC.canMove(d)) {
          try {
            switch (sneak) {
              case SNEAK:
                // RC.setIndicatorString(2, dest.x + ", " + dest.y + ": sneak");
                RC.sneak(d);
                break;
              case RUN:
                // RC.setIndicatorString(2, dest.x + ", " + dest.y + ": run");
                RC.move(d);
                break;
              case PUSH_HOME:
                // RC.setIndicatorString(2, dest.x + ", " + dest.y + ": push_home");
                Direction awayFromHome = currentLocation.directionTo(ALLY_HQ).opposite();
                if (d == awayFromHome
                    || d == awayFromHome.rotateLeft()
                    || d == awayFromHome.rotateRight()) {
                  RC.sneak(d);
                } else {
                  RC.move(d);
                }
                break;
              default:
                break;
            }
          } catch (GameActionException e) {
            e.printStackTrace();
          }
        } else if (currentLocation.distanceSquaredTo(dest) <= 2) {
          setTarget(currentLocation);
        }
      }
    }
    // System.out.println("Bytecodes used by Mover.execute() = " +
    // Integer.toString(bc-Clock.getBytecodesLeft()));
  }
コード例 #12
0
ファイル: BFSNoiseTower.java プロジェクト: jalman/armada
  public BFSNoiseTower() throws GameActionException {
    System.out.println("start " + Clock.getBytecodeNum());

    queue[0] = currentLocation;
    dir[17][17] = Direction.OMNI;

    for (int i = 7; i >= 0; i--) {
      Direction d = directions[i];
      MapLocation loc = currentLocation.add(d);
      TerrainTile there = RC.senseTerrainTile(loc);
      if (!there.isTraversableAtHeight(RobotLevel.ON_GROUND)) continue;
      int x = loc.x - currentLocation.x;
      int y = loc.y - currentLocation.y;
      dir[x + 17][y + 17] = d.opposite();
      queue[at] = loc;
      at++;
    }

    for (int s = 1; s < at; s++) {
      if (s % 30 == 0 && RC.isActive()) {
        if (target == null
            || target.distanceSquaredTo(ALLY_PASTR_COUNT > 0 ? ALLY_PASTR_LOCS[0] : currentLocation)
                <= 5) {
          earlyNearbyCows();
        }
        MapLocation realTarget = target.add(currentLocation.directionTo(target), 3);

        if (RC.canAttackSquare(realTarget)) RC.attackSquare(realTarget);

        target = target.add(target.directionTo(currentLocation));
      }

      Direction initD =
          dir[queue[s].x - currentLocation.x + 17][queue[s].y - currentLocation.y + 17];
      Direction aD;
      Direction bD;
      if (initD.isDiagonal()) {
        aD = initD.rotateLeft().rotateLeft();
        bD = initD.rotateRight();
      } else {
        aD = initD.rotateLeft().rotateLeft().rotateLeft();
        bD = initD.rotateRight().rotateRight();
      }
      for (Direction d = aD; d != bD; d = d.rotateLeft()) {
        MapLocation loc = queue[s].add(d);
        TerrainTile there = RC.senseTerrainTile(loc);
        if (!there.isTraversableAtHeight(RobotLevel.ON_GROUND)) continue;
        int x = loc.x - currentLocation.x;
        int y = loc.y - currentLocation.y;
        if (x * x + y * y > 200) continue;

        if (dir[x + 17][y + 17] == null) {
          dir[x + 17][y + 17] = d.opposite();
          queue[at] = loc;
          at++;
        }
      }
    }

    System.out.println("end " + Clock.getBytecodeNum());
    System.out.println("at " + at);
  }
コード例 #13
0
ファイル: DStar.java プロジェクト: jalman/armada
  public boolean compute(int bytecodes) {
    // cache variables
    int d, w, e, x, y;
    int[] weight;
    MapLocation next, nbr;
    Direction dir;
    final BucketQueue<MapLocation> queue = this.queue;
    final int[][] distance = this.distance;
    final Direction[][] from = this.from;

    // int iters = 0;
    // int bc = Clock.getBytecodeNum();

    while (queue.size > 0) {
      // iters++;
      if (Clock.getBytecodeNum() >= bytecodes - 600) {
        break;
      }

      // RC.setIndicatorString(0, Integer.toString(min));
      // ALERT: queue.min is valid only after a call to deleteMin()!
      next = queue.deleteMin();

      x = next.x;
      y = next.y;
      d = distance[x][y];

      // check if we have already visited this node
      if (!visited[x][y]) {
        visited[x][y] = true;
        /*
         * if (broadcast) {
         * try {
         * messagingSystem.writePathingDirection(next, from[x][y]);
         * } catch (GameActionException ex) {
         * ex.printStackTrace();
         * }
         * }
         */

        weight = WEIGHT[RC.senseTerrainTile(next).ordinal()];

        dir = from[x][y];
        int i;
        if (dir == Direction.NONE) {
          dir = Direction.NORTH;
          i = 8;
        } else if (dir.isDiagonal()) {
          dir = dir.rotateLeft().rotateLeft();
          i = 5;
        } else {
          dir = dir.rotateLeft();
          i = 3;
        }

        for (; --i >= 0; dir = dir.rotateRight()) {
          nbr = next.add(dir);
          if (RC.senseTerrainTile(nbr).isTraversableAtHeight(RobotLevel.ON_GROUND)) {
            w = d + weight[dir.ordinal()];
            e = w + heuristic(next, dest);

            x = nbr.x;
            y = nbr.y;

            if (from[x][y] == null) {
              queue.insert(e, nbr);
              // if (RC.getRobot().getID() == 118)
              // System.out.println("inserted " + nbr + ": " + w + " " + e);
              distance[x][y] = w;
              // estimate[x][y] = e;
              from[x][y] = dir;
            } else {
              if (w < distance[x][y]) {
                queue.insert(e, nbr);
                distance[x][y] = w;
                // estimate[x][y] = e;
                from[x][y] = dir;
                visited[x][y] = false;
              }
            }
          }
        }
      }
    }

    // bc = Clock.getBytecodeNum() - bc;
    // RC.setIndicatorString(2, "average DStar bytecodes: " + (iters > 0 ? bc / iters : bc));

    return arrived(dest);
  }
コード例 #14
0
ファイル: SoldierBehavior.java プロジェクト: jalman/armada
  @Override
  public void run() throws GameActionException {
    if (luge()) { // luge = micro
      // set mode to ATTACK or something
      return;
      // send message?
    } else if (mode != Mode.ENGAGE
        && mode != Mode.ACQUIRE_TARGET
        && mode != Mode.BIRTH_DECIDE_MODE
        && mode != Mode.FIND_PASTR_LOC
        && mode != Mode.BUILD_PASTR) {
      if (ENEMY_MILK - ALLY_MILK > 50000 || ENEMY_PASTR_COUNT > ALLY_PASTR_COUNT) {
        changeMode(Mode.ACQUIRE_TARGET);
      } else {
        // try to build pastures if late in game
        // probably deprecated (doesn't happen)
        if (currentRound > 1800 && ENEMY_PASTR_COUNT > ALLY_PASTR_COUNT && !panicPastrBuilding) {
          if (currentCowsHere < 150) {
            panicPastrBuilding = true;
            dest = ALLY_HQ.subtract(ALLY_HQ.directionTo(ENEMY_HQ));
            mover.setTarget(dest);
            sneakToBuildingLoc = 1;
            changeMode(Mode.FIND_PASTR_LOC);
          } else if (currentCowsHere < 400) {
            panicPastrBuilding = true;
            mover.setTarget(ALLY_HQ);
            changeMode(Mode.RETURN_HOME);
          }
        } else if (!initialSweep) {
          // stand on rich squares
          MapLocation loc = findRichSquare();
          if (loc != null) {
            mover.setTarget(loc);
            changeMode(Mode.STAND_RICH_LOC);
          }
        }
      }
    }

    switch (mode) {
      case BIRTH_DECIDE_MODE:
        int robotNum = RC.senseRobotCount();
        if (ENEMY_PASTR_COUNT > ALLY_PASTR_COUNT + 1
            || (robotNum + currentRound / 100 > 22 && ENEMY_PASTR_COUNT > ALLY_PASTR_COUNT)) {
          roleIndex = ALLY_PASTR_COUNT % 4;
          role = Role.PASTR;
          changeMode(Mode.FIND_PASTR_LOC);
          dest =
              new MapLocation(
                  (ALLY_HQ.x + roleLocList[roleIndex].x) / 2,
                  (ALLY_HQ.y + roleLocList[roleIndex].y) / 2);
        } else {
          roleIndex = robotNum % 4;
          role = roleList[roleIndex];

          changeMode(Mode.SWEEP_OUT);
          dest = roleLocList[roleIndex];

          initialSweep = true;
        }
        mover.setTarget(dest);
        mover.move();
        break;
      case GOING_TO_MIDDLE:
        if (mover.arrived()) {
          decideNextMode();
        } else {
          mover.movePushHome();
        }
        break;
      case SWEEP_OUT:
        if (mover.arrived()) {
          dest =
              new MapLocation(
                  (2 * ALLY_HQ.x + roleLocList[roleIndex].x) / 3,
                  (2 * ALLY_HQ.y + roleLocList[roleIndex].y) / 3);
          mover.setTarget(dest);
          changeMode(Mode.RETURN_HOME);
        } else {
          mover.movePushHome();
        }
        break;
      case RETURN_HOME:
        if (mover.arrived()) {
          dest = roleLocList[roleIndex];
          mover.setTarget(dest);
          changeMode(Mode.SWEEP_OUT);

          initialSweep = false;
        } else {
          mover.movePushHome();
        }
        break;
      case STAND_RICH_LOC:
        if (!mover.arrived()) {
          mover.sneak();
        } else {
          RC.setIndicatorString(1, "cows here: " + currentCowsHere);
          if (currentCowsHere < 500) {
            mover.setTarget(roleLocList[roleIndex]);
            changeMode(Mode.SWEEP_OUT);
          }
        }
        break;
      case FIND_PASTR_LOC:
        if (mover.arrived()) {
          changeMode(Mode.BUILD_PASTR);
        } else {
          mover.execute(sneakToBuildingLoc);
        }
        break;
      case BUILD_PASTR:
        if (!RC.isConstructing() && RC.isActive()) {
          RC.construct(RobotType.PASTR);
        }

        if (RC.getConstructingRounds() == 0) {
          buildingFinished = true;
        }
        break;
      case ACQUIRE_TARGET:
        int mindistance = 10000000;
        MapLocation pastrTarget = null;
        for (MapLocation pastrLoc : ENEMY_PASTR_LOCS) {
          int d = currentLocation.distanceSquaredTo(pastrLoc);
          if (d < mindistance) {
            mindistance = d;
            pastrTarget = pastrLoc;
          }
        }

        if (pastrTarget == null) {
          mover.setTarget(ALLY_HQ);
          changeMode(Mode.RETURN_HOME);
        } else {
          mover.setTarget(pastrTarget);
          changeMode(Mode.ENGAGE);
          mover.move();
        }
        break;
      case ENGAGE:
        if (mover.arrived()) {
          changeMode(Mode.RETURN_HOME);
        } else {
          mover.move();
        }
        break;
      default:
        break;
    }
  }
コード例 #15
0
ファイル: NoiseTowerBehavior.java プロジェクト: jalman/armada
  public NoiseTowerBehavior() {
    for (int i = 7; i >= 0; i--) {
      int lastdir = (i + 4) % 8;
      int at = 1;
      paths[i][0] = currentLocation;
      int lastcow = 0;
      for (int j = 1; j < 30; j++) {
        if (i < 7 && RC.isActive()) {
          try {
            makeSomeNoise();
          } catch (GameActionException e1) {
            e1.printStackTrace();
          }
        }

        int k = lastdir + 2;
        k %= 8;
        int bestscore = -1;
        MapLocation bestplace = currentLocation;
        while (k != (lastdir + 6) % 8) {

          int score = Math.abs(i - k);
          if (score < 4) score = 8 - score;
          score *= score * score;
          MapLocation here = paths[i][j - 1].add(directions[k]);
          double cows;
          try {
            cows = Utils.COW_GROWTH[here.x][here.y];
            if (cows > 0) lastcow = j;
            score =
                (here.add(directions[k])).distanceSquaredTo(currentLocation) > 300
                        || RC.senseTerrainTile(here) == TerrainTile.VOID
                    ? -10
                    : cows == 0.0 ? 30 : score + (int) (cows) * 0 + 30;
          } catch (Exception e) {
            score = -2;
          }

          if (score > bestscore) {
            bestscore = score;
            bestplace = here;
          }

          k++;
          if (k == 8) k = 0;
        }
        if (!bestplace.equals(currentLocation)) {
          paths[i][j] = bestplace;
        } else {
          break;
        }
      }
      pathat[i] = lastcow;
      while (paths[i][pathat[i]] == null && pathat[i] > 0) pathat[i]--;
      if (lastcow < 29) lastcow++;
    }

    skip[0] = false;

    double[] d = new double[8];
    int[] dist = new int[8];
    MapLocation[] toconsider = new MapLocation[8];

    for (int i = 7; i >= 0; i--) {
      if (pathat[i] == 0) {
        d[i] = 0;
        dist[i] = 0;
      } else {
        toconsider[i] = paths[i][pathat[i] - 1];
        d[i] = Math.atan2(toconsider[i].y - curY, toconsider[i].x - curX);
        dist[i] = currentLocation.distanceSquaredTo(toconsider[i]);
      }
    }
    for (int i = 7; i >= 0; i--) {
      if (dist[i] == 0) skip[i] = true;
      else {
        for (int j = i - 1; j >= 0; j--) {
          if (i == j || dist[j] == 0) continue;
          if (Math.abs(d[i] - d[j]) < 0.4 && pathbetween(toconsider[i], toconsider[j])) {
            if (dist[i] < dist[j]) skip[i] = true;
            else skip[j] = true;
          }
        }
      }
    }
  }
コード例 #16
0
ファイル: Dijkstra.java プロジェクト: jalman/armada
  /**
   * Compute until either bytecodes have run out or we find a destination.
   *
   * @param end Hash-map of destination.
   * @param bytecodes The bytecode limit.
   * @param broadcast Whether to broadcast the results (used by the HQ).
   * @return Whether we found a destination.
   */
  public boolean compute(boolean[][] end, int bytecodes, boolean broadcast) {
    // cache variables
    int min, w, x, y;
    int[] weight;
    MapLocation next, nbr, prev, p;
    Direction dir;
    final BucketQueue<MapLocation> queue = this.queue;
    final int[][] distance = this.distance;
    final Direction[][] from = this.from;
    // final MapLocation[][] parent = this.parent;
    final boolean[][] unsafe = getUnsafe();

    // int iters = 0;
    // int bc = Clock.getBytecodeNum();

    while (queue.size > 0) {
      // iters++;
      if (Clock.getBytecodeNum() >= bytecodes - 500) {
        break;
      }

      // RC.setIndicatorString(0, Integer.toString(min));
      // ALERT: queue.min is valid only after a call to deleteMin()!
      next = queue.deleteMin();
      min = queue.min;

      x = next.x;
      y = next.y;

      // check if we have already visited this node
      if (min == distance[x][y]) {
        if (unsafe[x][y]) min += 100;

        dir = from[x][y];

        /*
         * if (dir != null) {
         * prev = next.subtract(dir);
         * p = parent[prev.x][prev.y];
         * if (min <= distance[p.x][p.y] + PARENT_DIST) {
         * parent[x][y] = p;
         * } else {
         * parent[x][y] = prev;
         * }
         * }
         */

        if (broadcast) {
          try {
            messagingSystem.writePathingInfo(next, dir, min, null /* parent[x][y] */);
          } catch (GameActionException e) {
            // e.printStackTrace();
          }
        }

        // if (end[x][y]) {
        // reached = next;
        // break;
        // }

        weight = WEIGHT[RC.senseTerrainTile(next).ordinal()];

        int i;
        if (dir == null) {
          dir = Direction.NORTH;
          i = 8;
        } else if (dir.isDiagonal()) {
          dir = dir.rotateLeft().rotateLeft();
          i = 5;
        } else {
          dir = dir.rotateLeft();
          i = 3;
        }

        for (; --i >= 0; dir = dir.rotateRight()) {
          nbr = next.add(dir);
          if (RC.senseTerrainTile(nbr).isTraversableAtHeight(RobotLevel.ON_GROUND)) {
            w = min + weight[dir.ordinal()];

            x = nbr.x;
            y = nbr.y;

            if (from[x][y] == null) {
              queue.insert_fast(w, nbr);
              // System.out.println("inserted " + nbr + " with distance " + w + " from " + dir);
              distance[x][y] = w;
              from[x][y] = dir;
            } else {
              if (w < distance[x][y]) {
                queue.insert_fast(w, nbr);
                distance[x][y] = w;
                from[x][y] = dir;
              }
            }
          }
        }
      }
    }

    // bc = Clock.getBytecodeNum() - bc;
    // RC.setIndicatorString(2, "average Dijkstra bytecodes: " + bc / iters);

    return reached != null;
  }
コード例 #17
0
ファイル: SoldierBehavior.java プロジェクト: jalman/armada
 private void changeMode(Mode m) {
   RC.setIndicatorString(0, currentRound + ": " + m.toString() + " " + role.toString());
   mode = m;
 }