Browse files

ai: add respecting war and replanning if unable to perform an action

  • Loading branch information...
1 parent b574a77 commit 6779e62793ba339b33b05e2feab54e9a44650fed @anttisalonen committed Dec 4, 2010
Showing with 194 additions and 51 deletions.
  1. +95 −9 src/ai.cpp
  2. +17 −0 src/ai.h
  3. +11 −5 src/astar.cpp
  4. +2 −0 src/astar.h
  5. +51 −32 src/civ.cpp
  6. +11 −3 src/civ.h
  7. +7 −2 src/map-astar.cpp
View
104 src/ai.cpp
@@ -26,6 +26,16 @@ bool primitive_orders::finished()
return finished_flag;
}
+bool primitive_orders::replan()
+{
+ return false;
+}
+
+void primitive_orders::clear()
+{
+ finished_flag = true;
+}
+
action orders_composite::get_action()
{
if(finished())
@@ -58,18 +68,35 @@ void orders_composite::add_orders(orders* o)
ord.push_back(o);
}
+bool orders_composite::replan()
+{
+ if(ord.empty())
+ return false;
+ return ord.front()->replan();
+}
+
+void orders_composite::clear()
+{
+ ord.clear();
+}
+
goto_orders::goto_orders(const map& m_, const fog_of_war& fog_, unit* u_, int x_, int y_)
: tgtx(x_),
tgty(y_),
m(m_),
fog(fog_),
u(u_)
{
- path = map_astar(m, fog, *u, coord(u->xpos, u->ypos), coord(tgtx, tgty));
+ get_new_path();
if(!path.empty())
path.pop_front();
}
+void goto_orders::get_new_path()
+{
+ path = map_astar(m, fog, *u, coord(u->xpos, u->ypos), coord(tgtx, tgty));
+}
+
action goto_orders::get_action()
{
if(finished())
@@ -95,6 +122,17 @@ int goto_orders::path_length()
return path.size();
}
+bool goto_orders::replan()
+{
+ get_new_path();
+ return !path.empty();
+}
+
+void goto_orders::clear()
+{
+ path.clear();
+}
+
explore_orders::explore_orders(const map& m_, const fog_of_war& fog_, unit* u_,
bool autocontinue_)
: goto_orders(m_, fog_, u_, u_->xpos, u_->ypos),
@@ -150,9 +188,21 @@ void explore_orders::drop_action()
get_new_path();
}
+bool explore_orders::replan()
+{
+ get_new_path();
+ return !path.empty();
+}
+
+void explore_orders::clear()
+{
+ path.clear();
+}
+
wait_orders::wait_orders(unit* u_, unsigned int rounds)
: u(u_),
- rounds_to_go(rounds)
+ rounds_to_go(rounds),
+ total_rounds(rounds)
{
}
@@ -174,6 +224,17 @@ bool wait_orders::finished()
return rounds_to_go == 0;
}
+bool wait_orders::replan()
+{
+ rounds_to_go = total_rounds;
+ return true;
+}
+
+void wait_orders::clear()
+{
+ rounds_to_go = 0;
+}
+
attack_orders::attack_orders(const map& m_, const fog_of_war& fog_, unit* u_, int x_, int y_)
: goto_orders(m_, fog_, u_, x_, y_),
att_x(-1),
@@ -234,6 +295,16 @@ bool attack_orders::finished()
return false;
}
+bool attack_orders::replan()
+{
+ return goto_orders::replan();
+}
+
+void attack_orders::clear()
+{
+ goto_orders::clear();
+}
+
ai_tunable_parameters::ai_tunable_parameters()
: max_defense_prio(1000),
defense_units_prio_coeff(400),
@@ -347,6 +418,13 @@ bool ai::play()
int success = r.perform_action(myciv->civ_id, a, &m);
if(!success) {
printf("AI error: could not perform action.\n");
+ oit->second->replan();
+ action a = oit->second->get_action();
+ success = r.perform_action(myciv->civ_id, a, &m);
+ if(!success) {
+ printf("AI error: still could not perform action.\n");
+ oit->second->clear();
+ }
}
else {
oit->second->drop_action();
@@ -494,24 +572,32 @@ void ai::find_best_city_pos(const unit* u, int* tgtx, int* tgty) const
class city_picker {
private:
- unsigned int civ_id;
+ const civilization* myciv;
const map& m;
bool my_city;
public:
- city_picker(const map& m_, unsigned int civ_id_, bool my_city_) :
- civ_id(civ_id_), m(m_), my_city(my_city_) { }
+ city_picker(const map& m_, const civilization* myciv_, bool my_city_) :
+ myciv(myciv_), m(m_), my_city(my_city_) { }
bool operator()(const coord& co) {
city* c = m.city_on_spot(co.x, co.y);
- if(!c)
+ if(!c) {
return false;
- else
- return (c->civ_id != civ_id) ^ my_city;
+ }
+ else {
+ if(my_city) {
+ return c->civ_id == myciv->civ_id;
+ }
+ else {
+ return c->civ_id != myciv->civ_id &&
+ myciv->get_relationship_to_civ(c->civ_id) == relationship_war;
+ }
+ }
}
};
city* ai::find_nearest_city(const unit* u, bool own) const
{
- city_picker picker(m, myciv->civ_id, own);
+ city_picker picker(m, myciv, own);
std::list<coord> path_to_city = map_path_to_nearest(m,
myciv->fog,
*u,
View
17 src/ai.h
@@ -11,6 +11,8 @@ class orders {
virtual action get_action() = 0;
virtual void drop_action() = 0;
virtual bool finished() = 0;
+ virtual bool replan() = 0;
+ virtual void clear() = 0;
};
class primitive_orders : public orders {
@@ -19,6 +21,8 @@ class primitive_orders : public orders {
action get_action();
void drop_action();
bool finished();
+ bool replan();
+ void clear();
private:
action a;
bool finished_flag;
@@ -30,6 +34,8 @@ class orders_composite : public orders {
void drop_action();
bool finished();
void add_orders(orders* o);
+ bool replan();
+ void clear();
private:
std::list<orders*> ord;
};
@@ -41,6 +47,8 @@ class goto_orders : public orders {
virtual action get_action();
virtual void drop_action();
virtual bool finished();
+ virtual bool replan();
+ void clear();
int path_length();
protected:
int tgtx;
@@ -49,13 +57,17 @@ class goto_orders : public orders {
const fog_of_war& fog;
unit* u;
std::list<coord> path;
+ private:
+ void get_new_path();
};
class explore_orders : public goto_orders {
public:
explore_orders(const map& m_, const fog_of_war& fog_, unit* u_,
bool autocontinue_);
void drop_action();
+ bool replan();
+ void clear();
private:
void get_new_path();
bool autocontinue;
@@ -67,9 +79,12 @@ class wait_orders : public orders {
action get_action();
void drop_action();
bool finished();
+ bool replan();
+ void clear();
private:
unit* u;
unsigned int rounds_to_go;
+ unsigned int total_rounds;
};
class attack_orders : public goto_orders {
@@ -78,6 +93,8 @@ class attack_orders : public goto_orders {
action get_action();
void drop_action();
bool finished();
+ bool replan();
+ void clear();
private:
void check_for_enemies();
int att_x;
View
16 src/astar.cpp
@@ -89,14 +89,20 @@ std::list<coord> astar(graphfunc g, costfunc c, heurfunc h,
}
path.reverse();
#ifdef DEBUG_ASTAR
- printf("Found path: ");
+ print_path(stderr, path);
+#endif
+ return path;
+}
+
+void print_path(FILE* fp, const std::list<coord>& path)
+{
+ fprintf(fp, "Found path: ");
for(std::list<coord>::const_iterator it = path.begin();
it != path.end();
++it) {
- printf("(%d, %d) ", it->x, it->y);
+ fprintf(fp, "(%d, %d) ", it->x, it->y);
}
- printf("\n");
-#endif
- return path;
+ fprintf(fp, "\n");
}
+
View
2 src/astar.h
@@ -15,4 +15,6 @@ typedef boost::function<bool(const coord& a)> goaltestfunc;
std::list<coord> astar(graphfunc g, costfunc c, heurfunc h,
goaltestfunc gtfunc, const coord& start);
+void print_path(FILE* fp, const std::list<coord>& path);
+
#endif
View
83 src/civ.cpp
@@ -335,6 +335,14 @@ bool map::has_city_of(const coord& co, unsigned int civ_id) const
return false;
}
+int map::city_owner_on_spot(int x, int y) const
+{
+ city* c = city_on_spot(x, y);
+ if(!c)
+ return -1;
+ return c->civ_id;
+}
+
city::city(std::string name, int x, int y, unsigned int civid)
: cityname(name),
xpos(x),
@@ -398,9 +406,9 @@ civilization::civilization(std::string name, unsigned int civid,
alloc_science(5),
research_goal_id(0),
ai(ai_),
- relationships(civid + 1, 0)
+ relationships(civid + 1, relationship_unknown)
{
- relationships[civid] = 1;
+ relationships[civid] = relationship_peace;
if(m)
fog = fog_of_war(m->size_x(), m->size_y());
}
@@ -614,29 +622,29 @@ void civilization::remove_city(city* c)
delete c;
}
-int civilization::get_relationship_to_civ(unsigned int civid) const
+relationship civilization::get_relationship_to_civ(unsigned int civid) const
{
if(civid == civ_id)
- return 1;
+ return relationship_peace;
if(relationships.size() <= civid)
- return 0;
+ return relationship_unknown;
return relationships[civid];
}
-void civilization::set_relationship_to_civ(unsigned int civid, int val)
+void civilization::set_relationship_to_civ(unsigned int civid, relationship val)
{
if(civid == civ_id)
return;
if(relationships.size() <= civid) {
- relationships.resize(civid + 1, 0);
+ relationships.resize(civid + 1, relationship_unknown);
}
relationships[civid] = val;
}
bool civilization::discover(unsigned int civid)
{
- if(civid != civ_id && get_relationship_to_civ(civid) == 0) {
- set_relationship_to_civ(civid, 1);
+ if(civid != civ_id && get_relationship_to_civ(civid) == relationship_unknown) {
+ set_relationship_to_civ(civid, relationship_peace);
add_message(discovered_civ(civid));
return 1;
}
@@ -646,21 +654,21 @@ bool civilization::discover(unsigned int civid)
void civilization::undiscover(unsigned int civid)
{
if(civid != civ_id) {
- set_relationship_to_civ(civid, 0);
+ set_relationship_to_civ(civid, relationship_unknown);
}
}
void civilization::set_war(unsigned int civid)
{
if(civid != civ_id) {
- set_relationship_to_civ(civid, 2);
+ set_relationship_to_civ(civid, relationship_war);
}
}
void civilization::set_peace(unsigned int civid)
{
if(civid != civ_id) {
- set_relationship_to_civ(civid, 1);
+ set_relationship_to_civ(civid, relationship_peace);
}
}
@@ -854,27 +862,32 @@ bool round::try_move_unit(unit* u, int chx, int chy, map* m)
// attack square?
int def_id = m->get_spot_owner(tgtxpos, tgtypos);
if(def_id >= 0 && def_id != u->civ_id) {
- const std::list<unit*>& units = m->units_on_spot(tgtxpos, tgtypos);
- if(units.size() != 0) {
- unit* defender = units.front();
- if(!can_attack(*u, *defender)) {
- return false;
- }
- combat(u, defender);
- if(u->strength == 0) {
- // lost combat
- (*current_civ)->remove_unit(u);
- return true;
+ if(in_war(u->civ_id, def_id)) {
+ const std::list<unit*>& units = m->units_on_spot(tgtxpos, tgtypos);
+ if(units.size() != 0) {
+ unit* defender = units.front();
+ if(!can_attack(*u, *defender)) {
+ return false;
+ }
+ combat(u, defender);
+ if(u->strength == 0) {
+ // lost combat
+ (*current_civ)->remove_unit(u);
+ return true;
+ }
+ else if(defender->strength == 0) {
+ // won combat
+ (*civs[def_id]).remove_unit(defender);
+ }
}
- else if(defender->strength == 0) {
- // won combat
- (*civs[def_id]).remove_unit(defender);
+ if(m->units_on_spot(tgtxpos, tgtypos).size() == 0) {
+ // check if a city was conquered
+ check_city_conquer(m, tgtxpos, tgtypos);
+ check_civ_elimination(def_id);
}
}
- if(m->units_on_spot(tgtxpos, tgtypos).size() == 0) {
- // check if a city was conquered
- check_city_conquer(m, tgtxpos, tgtypos);
- check_civ_elimination(def_id);
+ else {
+ return false;
}
}
@@ -888,9 +901,10 @@ bool round::try_move_unit(unit* u, int chx, int chy, map* m)
++it) {
civs[*it]->discover((*current_civ)->civ_id);
}
- if(def_id >= 0 && def_id != u->civ_id) {
+ int city_owner = m->city_owner_on_spot(tgtxpos, tgtypos);
+ if(city_owner >= 0 && city_owner != u->civ_id) {
check_city_conquer(m, tgtxpos, tgtypos);
- check_civ_elimination(def_id);
+ check_civ_elimination(city_owner);
}
return true;
}
@@ -922,3 +936,8 @@ void round::peace_between(unsigned int civ1, unsigned int civ2)
civs[civ2]->set_peace(civ1);
}
+bool round::in_war(unsigned int civ1, unsigned int civ2) const
+{
+ return civs[civ1]->get_relationship_to_civ(civ2) == relationship_war;
+}
+
View
14 src/civ.h
@@ -134,6 +134,7 @@ class map {
int get_spot_owner(int x, int y) const;
const std::list<unit*>& units_on_spot(int x, int y) const;
city* city_on_spot(int x, int y) const;
+ int city_owner_on_spot(int x, int y) const;
bool has_city_of(const coord& co, unsigned int civ_id) const;
void add_city(city* c, int x, int y);
void remove_city(const city* c);
@@ -166,6 +167,12 @@ struct msg {
} msg_data;
};
+enum relationship {
+ relationship_unknown,
+ relationship_peace,
+ relationship_war,
+};
+
class civilization {
public:
civilization(std::string name, unsigned int civid, const color& c_, map* m_, bool ai_);
@@ -181,8 +188,8 @@ class civilization {
city* add_city(std::string name, int x, int y);
void remove_city(city* c);
void add_message(const msg& m);
- int get_relationship_to_civ(unsigned int civid) const;
- void set_relationship_to_civ(unsigned int civid, int val);
+ relationship get_relationship_to_civ(unsigned int civid) const;
+ void set_relationship_to_civ(unsigned int civid, relationship val);
bool discover(unsigned int civid);
void undiscover(unsigned int civid);
void set_war(unsigned int civid);
@@ -208,7 +215,7 @@ class civilization {
std::set<unsigned int> researched_advances;
bool ai;
private:
- std::vector<int> relationships;
+ std::vector<relationship> relationships;
};
enum action_type {
@@ -262,6 +269,7 @@ class round
const unit_configuration_map uconfmap;
const advance_map amap;
const city_improv_map cimap;
+ bool in_war(unsigned int civ1, unsigned int civ2) const;
private:
bool next_civ();
void refill_moves();
View
9 src/map-astar.cpp
@@ -8,8 +8,13 @@
void check_insert(std::set<coord>& s, const map& m, const fog_of_war& fog, const unit& u, int x, int y)
{
if(x >= 0 && y >= 0 && x < m.size_x() && y < m.size_y()) {
- if(terrain_allowed(m, u, x, y) && fog.get_value(x, y)) {
- s.insert(coord(x, y));
+ if(terrain_allowed(m, u, x, y)) {
+ int fogval = fog.get_value(x, y);
+ if(fogval) { // known terrain
+ if(fogval == 1 || m.free_spot(u.civ_id, x, y)) { // terrain visible and no enemy on it
+ s.insert(coord(x, y));
+ }
+ }
}
}
}

0 comments on commit 6779e62

Please sign in to comment.