/**
   * Test a critter {@code c1} BUD and create a new critter {@code c2} and the new critter has the
   * property as expected
   *
   * @throws IOException
   * @throws SyntaxError
   */
  @Test
  public void testBud() throws IOException, SyntaxError {
    World w = World.loadWorld("txt/BudTest/world.txt", session_id);
    Critter c1 = w.order.get(0);
    Position posC1 = c1.getPosition();
    w.printCoordinatesASCIIMap();
    w.printASCIIMap();

    // Critter c1 bud and create a new critter c2 behind it
    int c1Energy = c1.getMem(IDX.ENERGY);
    c1Energy -= Constant.BUD_COST * c1.getComplexity();
    w.lapse();
    assertTrue(
        "Critter c1 has decrease certain amount of energy", c1.getMem(IDX.ENERGY) == c1Energy);

    // c2 may turn into food if it bud again
    if (w.order.size() == 1) {
      assertTrue(
          "Critter c2 doesn't turn into food as expected",
          w.getElemAtPosition(posC1.getRelativePos(1, DIR.BACK))
              .equals(new Food(Constant.FOOD_PER_SIZE * Constant.INIT_SIZE)));
      return;
    }
    assertTrue("Critter c2 has not been created", w.order.size() == 2);
    Critter c2 = w.order.get(1);
    assertTrue(
        "Critter c2 doesn't wait and gather energy in" + "the round it is created",
        c2.getMem(IDX.ENERGY) == Constant.INITIAL_ENERGY + 1);
    for (int i = 0; i < Constant.MIN_MEMORY; ++i) {
      if (i == IDX.ENERGY || i == IDX.SIZE || i == IDX.POSTURE || i == IDX.TAG) continue;
      assertTrue(
          "Critter c2 doesn't inherient it parent as expected", c1.getMem(i) == c2.getMem(i));
    }
  }
  /**
   * Test a critter {@code c1} TAG another critter {@code c2}
   *
   * @throws IOException
   * @throws SyntaxError
   */
  @Test
  public void testTag() throws IOException, SyntaxError {
    World w = World.loadWorld("txt/TagTest/world.txt", session_id);
    Critter c1 = w.order.get(0);
    Critter c2 = w.order.get(1);
    final int TAGVAL = 23;
    w.printCoordinatesASCIIMap();
    w.printASCIIMap();

    // Critter c1 start to tag Critter c2
    int c1Energy = c1.getMem(IDX.ENERGY);
    int c1Size = c1.getMem(IDX.SIZE);
    c1Energy -= c1Size;
    w.lapse();
    assertTrue("Critter c2 has not been tag", c2.getMem(IDX.TAG) == TAGVAL);
    assertTrue("Critter c1 doesn't lose the energy to tag", c1.getMem(IDX.ENERGY) == c1Energy);

    // Critter c1 still try to tag some critter
    w.lapse();
    c1Size = c1.getMem(IDX.SIZE);
    c1Energy -= c1Size;
    assertTrue(
        "Critter still lose energy although there is " + "no critter for it to tag",
        c1.getMem(IDX.ENERGY) == c1Energy);
  }
  /**
   * Test a critter {@code c1} ATTACK another critter {@code c2}
   *
   * @throws IOException
   * @throws SyntaxError
   */
  @Test
  public void testAttack() throws IOException, SyntaxError {
    World w = World.loadWorld("txt/AttackTest/world.txt", session_id);
    Critter c1 = w.order.get(0);
    Critter c2 = w.order.get(1);
    Position posC2 = c2.getPosition();
    w.printCoordinatesASCIIMap();
    w.printASCIIMap();

    // Critter c1 start to attack Critter c2
    int c1Energy = c1.getMem(IDX.ENERGY);
    int c2Energy = c2.getMem(IDX.ENERGY);
    int c1Size = c1.getMem(IDX.SIZE);
    int c2Size = c2.getMem(IDX.SIZE);
    c1Energy -= c1Size * Constant.ATTACK_COST;
    int da =
        (int)
            (Constant.BASE_DAMAGE
                * c1Size
                * game.utils.Formula.logistic(
                    Constant.DAMAGE_INC
                        * (c1Size * c1.getMem(IDX.OFFENSE) - c2Size * c2.getMem(IDX.DEFENSE))));
    c2Energy -= da;
    c2Energy += c2Size * Constant.SOLAR_FLUX;
    w.lapse();

    assertTrue("Critter c2 doesn't lose energy as expected", c2.getMem(IDX.ENERGY) == c2Energy);
    assertTrue("Critter c1 doesn't lose the energy to attack", c1.getMem(IDX.ENERGY) == c1Energy);

    // c1 keep attack c2, but c2 is still alive
    w.lapse();
    c2Energy -= da;
    c2Energy += c2Size * Constant.SOLAR_FLUX;
    assertTrue("Critter c2 doesn't lose energy as expected", c2.getMem(IDX.ENERGY) == c2Energy);
    System.out.println(c2);

    w.lapse();
    c2Energy -= da;
    c2Energy += c2Size * Constant.SOLAR_FLUX;
    assertTrue("Critter c2 doesn't lose energy as expected", c2.getMem(IDX.ENERGY) == c2Energy);

    w.lapse();
    c2Energy -= da;
    c2Energy += c2Size * Constant.SOLAR_FLUX;
    assertTrue("Critter c2 doesn't lose energy as expected", c2.getMem(IDX.ENERGY) == c2Energy);

    w.lapse();
    c2Energy -= da;
    c2Energy += c2Size * Constant.SOLAR_FLUX;
    assertTrue("Critter c2 doesn't lose energy as expected", c2.getMem(IDX.ENERGY) == c2Energy);

    // c2 is killed
    w.lapse();
    assertTrue(
        "c2 has not been turn into food",
        w.getElemAtPosition(posC2).equals(new Food(c2Size * Constant.FOOD_PER_SIZE)));
    assertTrue(
        "c2 has not been removed from the list", w.order.size() == 1 && w.order.get(0).equals(c1));
  }
  /**
   * Test single critter walking a spiral
   *
   * @throws SyntaxError
   * @throws IOException
   */
  @Test
  public void testSpiralMove() throws IOException, SyntaxError {
    World w = World.loadWorld("txt/SpiralMoveTest/world.txt", session_id);
    Critter c = w.order.get(0);
    w.printCoordinatesASCIIMap();
    w.printASCIIMap();

    for (int i = 0; i < 100; ++i) {
      w.lapse();
      w.printASCIIMap();
      System.out.println("Critter energy: " + c.getMem(IDX.ENERGY));
    }
  }