16      if(&potential_ally==&origin)
 
   26           if(potential_ally.
occupant_data!=NULL && origin.occupant_data!=NULL &&
 
   36      const int x_length = x_right - x_left + 1;
 
   37      const int y_height = y_down - y_up + 1;
 
   39      vector<vector<GridCell> > to_return(x_length,vector<GridCell>(y_height));
 
   40      for(
int i=x_left; i<=x_right; i++)
 
   41           for(
int j=y_up; j<=y_down; j++)
 
   43                GridCell& sanitized = to_return[i-x_left][j-y_up];
 
   44                sanitized = worldGrid[i][j];
 
   66 RoboSim::RoboSim(
int initial_robots_per_combatant, 
int skill_points, 
int length, 
int width, 
int obstacles) :
 
   70      for(
int i=0; i<length; i++)
 
   71           for(
int j=0; j<width; j++)
 
   81           for(
int i=0; i<initial_robots_per_combatant; i++)
 
   86                     x_pos = rand()%length;
 
   92                worldGrid[x_pos][y_pos].occupant_data = &data;
 
   96                vector<uint8_t> creation_message(64);
 
  110      for(
int i=0; i<obstacles; i++)
 
  115                x_pos = rand()%length;
 
  116                y_pos = rand()%width;
 
  152                for(
int i=0; 
true; i++)
 
  194      if(power > actingRobot.status.power || power > actingRobot.specs.attack || power < 1)
 
  195           throw RoboSimExecutionException(
"attempted melee attack with illegal power level",actingRobot.player,*actingRobot.assoc_cell);
 
  198      if(!isAdjacent(adjacent_cell))
 
  199           throw RoboSimExecutionException(
"attempted to melee attack nonadjacent cell",actingRobot.player,*actingRobot.assoc_cell);
 
  203      if(adjacent_cell.
x_coord > rsim.worldGrid.size() || adjacent_cell.
y_coord > rsim.worldGrid[0].size() ||
 
  205           throw RoboSimExecutionException(
"passed invalid cell coordinates to meleeAttack()",actingRobot.player,*actingRobot.assoc_cell,adjacent_cell);
 
  214           throw RoboSimExecutionException(
"attempted to attack empty cell",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  216           throw RoboSimExecutionException(
"attempted to attack blocked tile",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  222           throw RoboSimExecutionException(
"attempted to attack energy capsule",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  224           throw RoboSimExecutionException(
"ERROR in RoboSim.RoboAPIImplementor.meleeAttack().  This is probably not the student's fault.  Contact Patrick Simmons about this message.  (Not the Doobie Brother...)");
 
  229      actingRobot.status.charge-=power;
 
  230      actingRobot.status.power-=power;
 
  233      int raw_attack = actingRobot.specs.attack;
 
  240      int attack = raw_attack + power;
 
  243      return processAttack(attack,cell_to_attack,power);
 
  251      if(power > actingRobot.status.power || power > actingRobot.specs.attack || power < 1)
 
  252           throw RoboSimExecutionException(
"attempted ranged attack with illegal power level",actingRobot.player,*actingRobot.assoc_cell);
 
  256      if(nonadjacent_cell.
x_coord > rsim.worldGrid.size() || nonadjacent_cell.
y_coord > rsim.worldGrid[0].size() ||
 
  258           throw RoboSimExecutionException(
"passed invalid cell coordinates to rangedAttack()",actingRobot.player,*actingRobot.assoc_cell,nonadjacent_cell);
 
  261      if(isAdjacent(nonadjacent_cell))
 
  269      if(!shortest_path.size()) 
 
  270           throw RoboSimExecutionException(
"attempted to range attack cell with no clear path",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  271      else if(shortest_path.size()>actingRobot.specs.defense) 
 
  272           throw RoboSimExecutionException(
"attempted to range attack cell more than (defense) tiles away",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  278           throw RoboSimExecutionException(
"attempted to attack empty cell",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  280           throw RoboSimExecutionException(
"attempted to attack blocked tile",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  286           throw RoboSimExecutionException(
"attempted to attack energy capsule",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  288           throw RoboSimExecutionException(
"ERROR in RoboSim.RoboAPIImplementor.rangedAttack().  This is probably not the student's fault.  Contact Patrick Simmons about this message.  (Not the Doobie Brother...)");
 
  293      actingRobot.status.charge-=power;
 
  294      actingRobot.status.power-=power;
 
  297      int raw_attack = actingRobot.specs.attack/2;
 
  300      int attack = raw_attack + power;
 
  303      return processAttack(attack,cell_to_attack,power);
 
  312           throw RoboSimExecutionException(
"passed invalid cell coordinates to capsuleAttack()",actingRobot.player,*actingRobot.assoc_cell,cell);
 
  318      auto capsule_it = find(actingRobot.status.capsules.begin(),actingRobot.status.capsules.end(),power_of_capsule);
 
  320      if(capsule_it==actingRobot.status.capsules.end())
 
  321           throw RoboSimExecutionException(
string(
"passed invalid power to capsuleAttack(): doesn't have capsule of power ")+to_string(power_of_capsule),actingRobot.player,*actingRobot.assoc_cell);
 
  324      if(actingRobot.specs.attack + actingRobot.specs.defense < power_of_capsule)
 
  325           throw RoboSimExecutionException(
"attempted to use capsule of greater power than attack+defense",actingRobot.player,*actingRobot.assoc_cell);
 
  330      if(!shortest_path.size())
 
  333      if(shortest_path.size() > power_of_capsule + actingRobot.specs.defense)
 
  340           throw RoboSimExecutionException(
"attempted to attack empty cell",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  342           throw RoboSimExecutionException(
"attempted to attack blocked tile",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  348           throw RoboSimExecutionException(
"attempted to attack energy capsule",actingRobot.player,*actingRobot.assoc_cell,cell_to_attack);
 
  350           throw RoboSimExecutionException(
"ERROR in RoboSim.RoboAPIImplementor.capsuleAttack().  This is probably not the student's fault.  Contact Patrick Simmons about this message.  (Not the Doobie Brother...)");
 
  356      actingRobot.status.capsules.erase(capsule_it);
 
  359      return processAttack(actingRobot.specs.attack + power_of_capsule,cell_to_attack,(
int)(ceil(0.1 * power_of_capsule * actingRobot.specs.attack)));
 
  367      int x_coord = actingRobot.assoc_cell->x_coord;
 
  368      const int actor_x = x_coord;
 
  369      int y_coord = actingRobot.assoc_cell->y_coord;
 
  370      const int actor_y = y_coord;
 
  388      if(x_coord < 0 || x_coord > rsim.worldGrid.size() || y_coord < 0 || y_coord > rsim.worldGrid[0].size())
 
  392      if(rsim.worldGrid[x_coord][y_coord].contents!=
EMPTY && rsim.worldGrid[x_coord][y_coord].contents!=
FORT)
 
  393           throw RoboSimExecutionException(
"attempted to move onto illegal cell",actingRobot.player,*actingRobot.assoc_cell,rsim.worldGrid[x_coord][y_coord]);
 
  396      if(rsim.worldGrid[x_coord][y_coord].contents==
FORT && rsim.worldGrid[x_coord][y_coord].fort_orientation!=way)
 
  397           throw RoboSimExecutionException(
"attempted to move onto a fort from an illegal direction",actingRobot.player,*actingRobot.assoc_cell,rsim.worldGrid[x_coord][y_coord]);
 
  400      const bool x_left = x_coord<actor_x;
 
  401      const bool y_left = y_coord<actor_y;
 
  404           for(
int i=(x_left ? actor_x-1 : actor_x+1); i!=x_coord; i=(x_left ? i-1 : i+1))
 
  405                if(rsim.worldGrid[i][y_coord].contents!=
EMPTY)
 
  406                     throw RoboSimExecutionException(
"attempted to cross illegal cell",actingRobot.player,*actingRobot.assoc_cell,rsim.worldGrid[i][y_coord]);
 
  410           for(
int i=(y_left ? actor_y-1 : actor_y+1); i!=y_coord; i=(y_left ? i-1 : i+1))
 
  411                if(rsim.worldGrid[x_coord][i].contents!=
EMPTY)
 
  412                     throw RoboSimExecutionException(
"attempted to cross illegal cell",actingRobot.player,*actingRobot.assoc_cell,rsim.worldGrid[x_coord][i]);
 
  416      if(steps > actingRobot.status.power)
 
  417           throw RoboSimExecutionException(
"attempted to move too far (not enough power)",actingRobot.player,*actingRobot.assoc_cell,rsim.worldGrid[x_coord][y_coord]);
 
  420      actingRobot.status.power-=steps;
 
  421      actingRobot.status.charge-=steps;
 
  424      actingRobot.assoc_cell->contents = 
EMPTY;
 
  425      actingRobot.assoc_cell->occupant_data = NULL;
 
  426      actingRobot.assoc_cell = &rsim.worldGrid[x_coord][y_coord];
 
  427      actingRobot.assoc_cell->contents = 
SELF;
 
  428      actingRobot.assoc_cell->occupant_data = &actingRobot;
 
  436      if(adjacent_cell.
x_coord > rsim.worldGrid.size() || adjacent_cell.
y_coord > rsim.worldGrid[0].size() || adjacent_cell.
x_coord < 0 || adjacent_cell.
y_coord < 0)
 
  437           throw RoboSimExecutionException(
"passed invalid cell coordinates to pick_up_capsule()",actingRobot.player,*actingRobot.assoc_cell,adjacent_cell);
 
  443      if(!isAdjacent(adjacent_cell))
 
  444           throw RoboSimExecutionException(
"attempted to pick up capsule in nonadjacent cell",actingRobot.player,*actingRobot.assoc_cell,gridCell);
 
  447      if(actingRobot.status.power==0)
 
  448           throw RoboSimExecutionException(
"attempted to pick up capsule with no power",actingRobot.player,*actingRobot.assoc_cell,gridCell);
 
  452           throw RoboSimExecutionException(
"attempted to pick up capsule from cell with no capsule",actingRobot.player,*actingRobot.assoc_cell,gridCell);
 
  455      if(actingRobot.status.capsules.size()+1>actingRobot.specs.attack+actingRobot.specs.defense)
 
  456           throw RoboSimExecutionException(
"attempted to pick up too many capsules",actingRobot.player,*actingRobot.assoc_cell,gridCell);
 
  461      actingRobot.status.power--;
 
  464      actingRobot.status.capsules.push_back(gridCell.
capsule_power);
 
  473      if(adjacent_cell.
x_coord > rsim.worldGrid.size() || adjacent_cell.
y_coord > rsim.worldGrid[0].size() || adjacent_cell.
x_coord < 0 || adjacent_cell.
y_coord < 0)
 
  474           throw RoboSimExecutionException(
"passed invalid cell coordinates to pick_up_capsule()",actingRobot.player,*actingRobot.assoc_cell,adjacent_cell);
 
  480      if(!isAdjacent(adjacent_cell))
 
  481           throw RoboSimExecutionException(
"attempted to pick up capsule in nonadjacent cell",actingRobot.player,*actingRobot.assoc_cell,gridCell);
 
  485           throw RoboSimExecutionException(
"attempted to place capsule in nonempty cell",actingRobot.player,*actingRobot.assoc_cell,gridCell);
 
  488      auto it = find(actingRobot.status.capsules.begin(),actingRobot.status.capsules.end(),power_of_capsule);
 
  489      if(it==actingRobot.status.capsules.end())
 
  490           throw RoboSimExecutionException(
string(
"attempted to drop capsule with power ")+to_string(power_of_capsule)+
", having no such capsule",actingRobot.player,*actingRobot.assoc_cell,gridCell);
 
  497      actingRobot.status.capsules.erase(it);
 
  503      if(actingRobot.whatBuilding==
NOTHING)
 
  507      int capsule_power = actingRobot.investedPower/10;
 
  508      switch(actingRobot.whatBuilding)
 
  511           if(actingRobot.investedPower >= 50)
 
  513                actingRobot.invested_assoc_cell->contents = 
WALL;
 
  514                actingRobot.invested_assoc_cell->wallforthealth = 
WALL_HEALTH;
 
  517                actingRobot.invested_assoc_cell->contents = 
EMPTY;
 
  521           if(actingRobot.investedPower >= 75)
 
  523                actingRobot.invested_assoc_cell->contents = 
FORT;
 
  524                actingRobot.invested_assoc_cell->wallforthealth = 
WALL_HEALTH;
 
  527                actingRobot.invested_assoc_cell->contents = 
EMPTY;
 
  533                if(actingRobot.status.capsules.size()+1>actingRobot.specs.attack+actingRobot.specs.defense)
 
  534                     throw RoboSimExecutionException(
"attempted to finish building capsule when already at max capsule capacity",actingRobot.player,*actingRobot.assoc_cell);
 
  535                actingRobot.status.capsules.push_back(capsule_power);
 
  540           int skill_points = actingRobot.investedPower/20;
 
  544                if(creation_message.size()!=0 && creation_message.size()!=64)
 
  545                     throw RoboSimExecutionException(
"passed incorrect sized creation message to setBuildTarget()",actingRobot.player,*actingRobot.assoc_cell,*actingRobot.invested_assoc_cell);
 
  548                if(!creation_message.size())
 
  550                     creation_message.resize(64);
 
  551                     creation_message[1] = rsim.turnOrder.size() % 256;
 
  552                     creation_message[0] = rsim.turnOrder.size() / 256;
 
  556                actingRobot.invested_assoc_cell->contents = 
SELF;
 
  564                     throw RoboSimExecutionException(
"something went wrong calling student's constructor", actingRobot.player,*actingRobot.assoc_cell, *actingRobot.invested_assoc_cell);
 
  566                rsim.turnOrder.emplace_back();
 
  567                RobotData& data = *(rsim.turnOrder.rbegin());
 
  569                data.
assoc_cell = actingRobot.invested_assoc_cell;
 
  571                data.
player = actingRobot.player;
 
  576                actingRobot.invested_assoc_cell->contents = 
EMPTY;
 
  584      if(actingRobot.whatBuilding!=
NOTHING)
 
  585           finalizeBuilding(message);
 
  590      if(location!=NULL && (location->
x_coord > rsim.worldGrid.size() || location->
y_coord > rsim.worldGrid[0].size() || location->
x_coord < 0 || location->
y_coord < 0))
 
  591           throw RoboSimExecutionException(
"passed invalid cell coordinates to setBuildTarget()",actingRobot.player,*actingRobot.assoc_cell,*location);
 
  597      actingRobot.whatBuilding = status;
 
  598      actingRobot.investedPower = 0;                    
 
  599      actingRobot.invested_assoc_cell = gridCell;
 
  605           if(actingRobot.whatBuilding!=
NOTHING && actingRobot.whatBuilding!=
CAPSULE)
 
  606                throw RoboSimExecutionException(
"passed null to setBuildTarget() location with non-null and non-capsule build target",actingRobot.player,*actingRobot.assoc_cell);
 
  612           throw RoboSimExecutionException(
"attempted to target capsule or null building on non-null adjacent cell",actingRobot.player,*actingRobot.assoc_cell,*location);
 
  615      if(!isAdjacent(*location))
 
  616           throw RoboSimExecutionException(
"attempted to set build target to nonadjacent cell",actingRobot.player,*actingRobot.assoc_cell,*gridCell);
 
  620           throw RoboSimExecutionException(
"attempted to set build target to nonempty cell",actingRobot.player,*actingRobot.assoc_cell,*gridCell);
 
RobotData * occupant_data
RoboSim(int initial_robots_per_combatant, int skill_points, int length, int width, int obstacles)
virtual Robot_Specs createRobot(WorldAPI *api, int skill_points, std::vector< std::uint8_t > message)=0
RoboAPIImplementor(RoboSim &rsim_, RobotData &actingRobot_)
#define RBP_CALL_CONSTRUCTOR(x)
AttackResult capsuleAttack(int power_of_capsule, GridCell &cell)
static const int WALL_HEALTH
AttackResult meleeAttack(int power, GridCell &adjacent_cell)
AttackResult rangedAttack(int power, GridCell &nonadjacent_cell)
vector< RobotData > turnOrder
void drop_capsule(GridCell &adjacent_cell, int power_of_capsule)
void move(int steps, Direction way)
static Robot_Specs checkSpecsValid(Robot_Specs proposed, int player, int skill_points)
AttackResult processAttack(int attack, GridCell &cell_to_attack, int power)
bool operator()(const GridCell &potential_ally)
void setBuildTarget(BuildStatus status, GridCell *location)
vector< vector< GridCell > > worldGrid
void pick_up_capsule(GridCell &adjacent_cell)
static std::list< GridCell * > findShortestPath(GridCell &origin, const GridCell &target, std::vector< std::vector< GridCell > > &grid)
vector< vector< GridCell > > getSanitizedSubGrid(int x_left, int y_up, int x_right, int y_down, int player) const 
void finalizeBuilding(vector< uint8_t > creation_message)
GridCell * invested_assoc_cell
bool calculateHit(int attack, int defense)