aboutsummaryrefslogtreecommitdiff
path: root/game/ai
diff options
context:
space:
mode:
authorjacopograndi <jacopo.grandi@outlook.it>2022-01-04 13:35:02 +0100
committerjacopograndi <jacopo.grandi@outlook.it>2022-01-04 13:35:02 +0100
commitbb16c32bde58cba70e4877aa2d3ebd04332eb575 (patch)
treede3d82cca043c26cbaa64837a3b2c18efc6ddb64 /game/ai
parent411d2f6d6a6e5370d33f0f54b2f2de7147a9d977 (diff)
linux compile and imgs
Diffstat (limited to 'game/ai')
-rw-r--r--game/ai/action.cpp150
-rw-r--r--game/ai/action.h102
-rw-r--r--game/ai/engine.h130
-rw-r--r--game/ai/evaluator.h58
-rw-r--r--game/ai/generator.h202
-rw-r--r--game/ai/performer.h96
-rw-r--r--game/ai/tactic.h62
7 files changed, 400 insertions, 400 deletions
diff --git a/game/ai/action.cpp b/game/ai/action.cpp
index 63218ba..d85eb4d 100644
--- a/game/ai/action.cpp
+++ b/game/ai/action.cpp
@@ -1,76 +1,76 @@
-#include "action.h"
-
-bool ai::compare_action(ai::action a, ai::action b) {
- return (a.heuristic < b.heuristic);
-}
-
-std::string ai::action::to_string () {
- if (type == actype::attack) {
- if (abs(x-mx)+abs(y-my) != 0) {
- return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
- + " move " +
- "[" + std::to_string(mx) + ", " + std::to_string(my) + "]"
- + " attack " +
- "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
- } else {
- return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
- + " attack " +
- "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
- }
- }
- if (type == actype::heal) {
- if (abs(x-mx)+abs(y-my) != 0) {
- return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
- + " move " +
- "[" + std::to_string(mx) + ", " + std::to_string(my) + "]"
- + " heal " +
- "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
- } else {
- return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
- + " heal " +
- "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
- }
- }
- if (type == actype::convert) {
- if (abs(x-mx)+abs(y-my) != 0) {
- return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
- + " move " +
- "[" + std::to_string(mx) + ", " + std::to_string(my) + "]"
- + " convert " +
- "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
- } else {
- return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
- + " convert " +
- "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
- }
- }
- if (type == actype::move) {
- return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
- + " move " +
- "[" + std::to_string(mx) + ", " + std::to_string(my) + "]";
- }
- if (type == actype::build) {
- if (abs(x-mx)+abs(y-my) != 0) {
- return "[" + std::to_string(x) + ", " + std::to_string(y)
- + "]" + " move " +
- "[" + std::to_string(mx) + ", " + std::to_string(my)
- + "]" + " build " +
- std::to_string(v);
- } else {
- return "[" + std::to_string(mx) + ", " + std::to_string(my)
- + "]" + " build " +
- std::to_string(v);
- }
- }
- if (type == actype::train) {
- return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" +
- " train " + std::to_string(v);
- }
- if (type == actype::trade) {
- return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" +
- " trade " + std::to_string(v);
- }
- if (type == actype::tech) {
- return "tech " + std::to_string(v);
- }
+#include "action.h"
+
+bool ai::compare_action(ai::action a, ai::action b) {
+ return (a.heuristic < b.heuristic);
+}
+
+std::string ai::action::to_string () {
+ if (type == actype::attack) {
+ if (abs(x-mx)+abs(y-my) != 0) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " move " +
+ "[" + std::to_string(mx) + ", " + std::to_string(my) + "]"
+ + " attack " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ } else {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " attack " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ }
+ }
+ if (type == actype::heal) {
+ if (abs(x-mx)+abs(y-my) != 0) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " move " +
+ "[" + std::to_string(mx) + ", " + std::to_string(my) + "]"
+ + " heal " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ } else {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " heal " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ }
+ }
+ if (type == actype::convert) {
+ if (abs(x-mx)+abs(y-my) != 0) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " move " +
+ "[" + std::to_string(mx) + ", " + std::to_string(my) + "]"
+ + " convert " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ } else {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " convert " +
+ "[" + std::to_string(tx) + ", " + std::to_string(ty) + "]";
+ }
+ }
+ if (type == actype::move) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"
+ + " move " +
+ "[" + std::to_string(mx) + ", " + std::to_string(my) + "]";
+ }
+ if (type == actype::build) {
+ if (abs(x-mx)+abs(y-my) != 0) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y)
+ + "]" + " move " +
+ "[" + std::to_string(mx) + ", " + std::to_string(my)
+ + "]" + " build " +
+ std::to_string(v);
+ } else {
+ return "[" + std::to_string(mx) + ", " + std::to_string(my)
+ + "]" + " build " +
+ std::to_string(v);
+ }
+ }
+ if (type == actype::train) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" +
+ " train " + std::to_string(v);
+ }
+ if (type == actype::trade) {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]" +
+ " trade " + std::to_string(v);
+ }
+ if (type == actype::tech) {
+ return "tech " + std::to_string(v);
+ }
} \ No newline at end of file
diff --git a/game/ai/action.h b/game/ai/action.h
index 12da451..6b631ca 100644
--- a/game/ai/action.h
+++ b/game/ai/action.h
@@ -1,52 +1,52 @@
-#ifndef ACTION_H
-#define ACTION_H
-
-#include <string>
-#include <vector>
-
-namespace ai {
-
-enum actype {
- attack, heal, convert, build, train, trade, move, tech
-};
-
-class action {
- public:
- action (actype type, int v) :
- type(type), v(v) {}
- action (actype type, int x, int y, int v) :
- type(type), x(x), y(y), v(v) {}
- action (actype type, int x, int y, int mx, int my) :
- type(type), x(x), y(y), mx(mx), my(my) {}
- action (actype type, int x, int y, int mx, int my, int v) :
- type(type), x(x), y(y), mx(mx), my(my), v(v) {}
- action (actype type, int x, int y, int mx, int my, int tx, int ty) :
- type(type), x(x), y(y), mx(mx), my(my), tx(tx), ty(ty) {}
- action (actype type, int x, int y, int mx, int my, int tx, int ty, int v) :
- type(type), x(x), y(y), mx(mx), my(my), tx(tx), ty(ty), v(v) {}
-
- action (const action& rhs) {
- type = rhs.type; x = rhs.x; y = rhs.y; mx = rhs.mx; my = rhs.my;
- tx = rhs.tx; ty = rhs.ty; v = rhs.v;
- }
- action& operator=(const action& rhs) {
- type = rhs.type; x = rhs.x; y = rhs.y; mx = rhs.mx; my = rhs.my;
- tx = rhs.tx; ty = rhs.ty; v = rhs.v;
- }
-
- actype type;
- int x, y; // start
- int mx, my; // moved
- int tx, ty; // target
- int v; // value (id of trainee, building or f/g trade, or tech id)
-
- float heuristic { 0 };
-
- std::string to_string ();
-};
-
-bool compare_action(action a, action b);
-
-}
-
+#ifndef ACTION_H
+#define ACTION_H
+
+#include <string>
+#include <vector>
+
+namespace ai {
+
+enum actype {
+ attack, heal, convert, build, train, trade, move, tech
+};
+
+class action {
+ public:
+ action (actype type, int v) :
+ type(type), v(v) {}
+ action (actype type, int x, int y, int v) :
+ type(type), x(x), y(y), v(v) {}
+ action (actype type, int x, int y, int mx, int my) :
+ type(type), x(x), y(y), mx(mx), my(my) {}
+ action (actype type, int x, int y, int mx, int my, int v) :
+ type(type), x(x), y(y), mx(mx), my(my), v(v) {}
+ action (actype type, int x, int y, int mx, int my, int tx, int ty) :
+ type(type), x(x), y(y), mx(mx), my(my), tx(tx), ty(ty) {}
+ action (actype type, int x, int y, int mx, int my, int tx, int ty, int v) :
+ type(type), x(x), y(y), mx(mx), my(my), tx(tx), ty(ty), v(v) {}
+
+ action (const action& rhs) {
+ type = rhs.type; x = rhs.x; y = rhs.y; mx = rhs.mx; my = rhs.my;
+ tx = rhs.tx; ty = rhs.ty; v = rhs.v;
+ }
+ action& operator=(const action& rhs) {
+ type = rhs.type; x = rhs.x; y = rhs.y; mx = rhs.mx; my = rhs.my;
+ tx = rhs.tx; ty = rhs.ty; v = rhs.v;
+ }
+
+ actype type;
+ int x, y; // start
+ int mx, my; // moved
+ int tx, ty; // target
+ int v; // value (id of trainee, building or f/g trade, or tech id)
+
+ float heuristic { 0 };
+
+ std::string to_string ();
+};
+
+bool compare_action(action a, action b);
+
+}
+
#endif \ No newline at end of file
diff --git a/game/ai/engine.h b/game/ai/engine.h
index d3755e1..584cb11 100644
--- a/game/ai/engine.h
+++ b/game/ai/engine.h
@@ -1,66 +1,66 @@
-#ifndef ENGINE_H
-#define ENGINE_H
-
-#include <iostream>
-
-#include <string>
-#include <vector>
-#include <limits>
-#include <cmath>
-
-#include "../ground.h"
-#include "../gst.h"
-
-#include "action.h"
-#include "tactic.h"
-#include "generator.h"
-#include "evaluator.h"
-#include "performer.h"
-
-namespace ai {
-
-class engine {
- public:
- engine (Gst &gst) : init(gst) {}
- Gst &init;
-
- tactic get_best () {
- tactic t { search(init, 4) };
- std::cout << t.to_string();
- return t;
- }
-
- tactic search (Gst &gst, int depth) {
- generator gen { gst };
- std::vector<tactic> tactics = gen.tactics();
- tactic best; best.eval = std::numeric_limits<float>::lowest();
- for (tactic t : tactics) {
- performer perf { gst };
- Gst next { perf.apply(t) };
- t.eval = negamax(next, depth, gst.turn);
- std::cout << "depth " << depth << " eval " << t.eval << "\n";
- if (t.eval > best.eval) best = t;
- }
- return best;
- }
-
- float negamax (Gst gst, int depth, int player) {
- //for (int i=0; i<3-depth; i++) std::cout << " "; std::cout << depth << "\n";
- if (depth == 0) {
- evaluator eval { gst };
- return eval.eval(player);
- }
- float value = std::numeric_limits<float>::lowest();
- generator gen { gst };
- auto tactics = gen.tactics();
- for (tactic t : tactics) {
- performer perf { gst };
- Gst next { perf.apply(t) };
- value = fmax(value, negamax(next, depth-1, -player));
- }
- return -value;
- }
-};
-
-}
+#ifndef ENGINE_H
+#define ENGINE_H
+
+#include <iostream>
+
+#include <string>
+#include <vector>
+#include <limits>
+#include <cmath>
+
+#include "../ground.h"
+#include "../gst.h"
+
+#include "action.h"
+#include "tactic.h"
+#include "generator.h"
+#include "evaluator.h"
+#include "performer.h"
+
+namespace ai {
+
+class engine {
+ public:
+ engine (Gst &gst) : init(gst) {}
+ Gst &init;
+
+ tactic get_best () {
+ tactic t { search(init, 4) };
+ std::cout << t.to_string();
+ return t;
+ }
+
+ tactic search (Gst &gst, int depth) {
+ generator gen { gst };
+ std::vector<tactic> tactics = gen.tactics();
+ tactic best; best.eval = std::numeric_limits<float>::lowest();
+ for (tactic t : tactics) {
+ performer perf { gst };
+ Gst next { perf.apply(t) };
+ t.eval = negamax(next, depth, gst.turn);
+ std::cout << "depth " << depth << " eval " << t.eval << "\n";
+ if (t.eval > best.eval) best = t;
+ }
+ return best;
+ }
+
+ float negamax (Gst gst, int depth, int player) {
+ //for (int i=0; i<3-depth; i++) std::cout << " "; std::cout << depth << "\n";
+ if (depth == 0) {
+ evaluator eval { gst };
+ return eval.eval(player);
+ }
+ float value = std::numeric_limits<float>::lowest();
+ generator gen { gst };
+ auto tactics = gen.tactics();
+ for (tactic t : tactics) {
+ performer perf { gst };
+ Gst next { perf.apply(t) };
+ value = fmax(value, negamax(next, depth-1, -player));
+ }
+ return -value;
+ }
+};
+
+}
#endif \ No newline at end of file
diff --git a/game/ai/evaluator.h b/game/ai/evaluator.h
index 75684de..b288076 100644
--- a/game/ai/evaluator.h
+++ b/game/ai/evaluator.h
@@ -1,30 +1,30 @@
-#ifndef EVALUATOR_H
-#define EVALUATOR_H
-
-#include <iostream>
-
-#include <string>
-#include <vector>
-
-#include "../ground.h"
-#include "../gst.h"
-
-namespace ai {
-
-class evaluator {
- public:
- evaluator (Gst gst) : gst(gst) {}
- Gst gst;
-
- float eval (int player) {
- float val = 0;
- for (Entity &ent : gst.entities) {
- int own = (int)(ent.owner != player)*2-1;
- val += own*(ent.info->cost[0] + ent.info->cost[1])*(ent.hp/100.0f);
- }
- return val;
- }
-};
-
-}
+#ifndef EVALUATOR_H
+#define EVALUATOR_H
+
+#include <iostream>
+
+#include <string>
+#include <vector>
+
+#include "../ground.h"
+#include "../gst.h"
+
+namespace ai {
+
+class evaluator {
+ public:
+ evaluator (Gst gst) : gst(gst) {}
+ Gst gst;
+
+ float eval (int player) {
+ float val = 0;
+ for (Entity &ent : gst.entities) {
+ int own = (int)(ent.owner != player)*2-1;
+ val += own*(ent.info->cost[0] + ent.info->cost[1])*(ent.hp/100.0f);
+ }
+ return val;
+ }
+};
+
+}
#endif \ No newline at end of file
diff --git a/game/ai/generator.h b/game/ai/generator.h
index c6cb288..39bde4f 100644
--- a/game/ai/generator.h
+++ b/game/ai/generator.h
@@ -1,102 +1,102 @@
-#ifndef GENERATOR_H
-#define GENERATOR_H
-
-#include <iostream>
-
-#include <string>
-#include <vector>
-
-#include "../ground.h"
-#include "../gst.h"
-#include "action.h"
-#include "tactic.h"
-#include "performer.h"
-
-namespace ai {
-
-const int maxiter = 100000;
-
-
-class generator {
- public:
- generator (Gst &gst) : init(gst) {}
- Gst &init;
-
- std::vector<action> valid_actions (Gst &gst) {
- Ground &gr = gst.inv->ground;
- std::vector<action> acts;
- for (Entity &ent : gst.entities) {
- if (ent.done) continue;
- if (ent.owner != gst.turn) continue;
-
- std::vector<action> ent_acts;
-
- std::vector<int> moves = gr.move_area(gst, ent);
- for (auto move : moves) {
- int mx = move%gr.sizex, my = move/gr.sizex;
- action act { actype::move, ent.x, ent.y, mx, my };
-
- performer perf { gst };
- Gst next { gst };
- next = perf.act(next, act);
- Entity &matk = next.get_at(mx, my);
- std::vector<int> atks = gr.attack_targets(next, matk);
- for (auto atk : atks) {
- int tx = atk%gr.sizex, ty = atk/gr.sizex;
- action act_atk { actype::attack, ent.x, ent.y,
- mx, my, tx, ty };
- Entity &mdef = next.get_at(tx, ty);
-
- BattleResult res = gst.battle_res(matk, mdef);
- float heur = (mdef.hp-res.def_hp);
- heur *= (mdef.info->cost[0] + mdef.info->cost[1]);
- act_atk.heuristic = heur;
- ent_acts.push_back(act_atk);
- }
-
- int dist = 999999;
- int pos = gst.get_nearest_enemy(ent, dist);
- float heur = 1.0f/dist;
- act.heuristic = heur;
- ent_acts.push_back(act);
- }
- std::sort(ent_acts.begin(), ent_acts.end(), compare_action);
- for (int i=0; i<3 && i<ent_acts.size(); i++) {
- acts.push_back(ent_acts[i]);
- }
- }
- std::sort(acts.begin(), acts.end(), compare_action);
- return acts;
- }
-
- tactic valid_tactic (int &n) {
- tactic t;
- Gst gst { init };
- for (int i=0; i<ai::maxiter; i++) {
- std::vector<action> acts { valid_actions(gst) };
- if (acts.size() == 0) break;
- performer perf { gst };
- int j = n % (acts.size());
- n /= acts.size();
- action &act = acts[j];
- gst = perf.act(gst, act);
- t.acts.push_back(act);
- //std::cout << act.to_string() << std::endl;
- }
- return t;
- }
-
- std::vector<tactic> tactics () {
- std::vector<tactic> ts;
- for (int i=0; i<3; i++) {
- int n = i;
- tactic t = valid_tactic(n);
- if (n > 0) break;
- ts.push_back(t);
- }
- return ts;
- }
-};
-
-}
+#ifndef GENERATOR_H
+#define GENERATOR_H
+
+#include <iostream>
+
+#include <string>
+#include <vector>
+
+#include "../ground.h"
+#include "../gst.h"
+#include "action.h"
+#include "tactic.h"
+#include "performer.h"
+
+namespace ai {
+
+const int maxiter = 100000;
+
+
+class generator {
+ public:
+ generator (Gst &gst) : init(gst) {}
+ Gst &init;
+
+ std::vector<action> valid_actions (Gst &gst) {
+ Ground &gr = gst.inv->ground;
+ std::vector<action> acts;
+ for (Entity &ent : gst.entities) {
+ if (ent.done) continue;
+ if (ent.owner != gst.turn) continue;
+
+ std::vector<action> ent_acts;
+
+ std::vector<int> moves = gr.move_area(gst, ent);
+ for (auto move : moves) {
+ int mx = move%gr.sizex, my = move/gr.sizex;
+ action act { actype::move, ent.x, ent.y, mx, my };
+
+ performer perf { gst };
+ Gst next { gst };
+ next = perf.act(next, act);
+ Entity &matk = next.get_at(mx, my);
+ std::vector<int> atks = gr.attack_targets(next, matk);
+ for (auto atk : atks) {
+ int tx = atk%gr.sizex, ty = atk/gr.sizex;
+ action act_atk { actype::attack, ent.x, ent.y,
+ mx, my, tx, ty };
+ Entity &mdef = next.get_at(tx, ty);
+
+ BattleResult res = gst.battle_res(matk, mdef);
+ float heur = (mdef.hp-res.def_hp);
+ heur *= (mdef.info->cost[0] + mdef.info->cost[1]);
+ act_atk.heuristic = heur;
+ ent_acts.push_back(act_atk);
+ }
+
+ int dist = 999999;
+ int pos = gst.get_nearest_enemy(ent, dist);
+ float heur = 1.0f/dist;
+ act.heuristic = heur;
+ ent_acts.push_back(act);
+ }
+ std::sort(ent_acts.begin(), ent_acts.end(), compare_action);
+ for (int i=0; i<3 && i<ent_acts.size(); i++) {
+ acts.push_back(ent_acts[i]);
+ }
+ }
+ std::sort(acts.begin(), acts.end(), compare_action);
+ return acts;
+ }
+
+ tactic valid_tactic (int &n) {
+ tactic t;
+ Gst gst { init };
+ for (int i=0; i<ai::maxiter; i++) {
+ std::vector<action> acts { valid_actions(gst) };
+ if (acts.size() == 0) break;
+ performer perf { gst };
+ int j = n % (acts.size());
+ n /= acts.size();
+ action &act = acts[j];
+ gst = perf.act(gst, act);
+ t.acts.push_back(act);
+ //std::cout << act.to_string() << std::endl;
+ }
+ return t;
+ }
+
+ std::vector<tactic> tactics () {
+ std::vector<tactic> ts;
+ for (int i=0; i<3; i++) {
+ int n = i;
+ tactic t = valid_tactic(n);
+ if (n > 0) break;
+ ts.push_back(t);
+ }
+ return ts;
+ }
+};
+
+}
#endif \ No newline at end of file
diff --git a/game/ai/performer.h b/game/ai/performer.h
index 472773b..17be028 100644
--- a/game/ai/performer.h
+++ b/game/ai/performer.h
@@ -1,49 +1,49 @@
-#ifndef PERFORMER_H
-#define PERFORMER_H
-
-#include <iostream>
-
-#include <string>
-#include <vector>
-
-#include "../ground.h"
-#include "../gst.h"
-#include "action.h"
-#include "tactic.h"
-
-namespace ai {
-
-class performer {
- public:
- performer (Gst &gst) : init(gst) {}
- Gst &init;
-
- Gst apply (tactic t) {
- Gst next { init };
- for (action a : t.acts) {
- next = act(next, a);
- }
- next.end_day();
- return next;
- }
-
- Gst& act (Gst &gst, action a) {
- if (a.type == actype::move) {
- Entity &ent = gst.get_at(a.x, a.y);
- ent.x = a.mx; ent.y = a.my;
- ent.moved = 1; ent.done = true;
- }
- if (a.type == actype::attack) {
- Entity &ent = gst.get_at(a.x, a.y);
- ent.x = a.mx; ent.y = a.my;
- ent.moved = 1;
- Entity &def = gst.get_at(a.tx, a.ty);
- gst.battle(ent, def);
- ent.done = true;
- }
- return gst;
- }
-};
-
-}
+#ifndef PERFORMER_H
+#define PERFORMER_H
+
+#include <iostream>
+
+#include <string>
+#include <vector>
+
+#include "../ground.h"
+#include "../gst.h"
+#include "action.h"
+#include "tactic.h"
+
+namespace ai {
+
+class performer {
+ public:
+ performer (Gst &gst) : init(gst) {}
+ Gst &init;
+
+ Gst apply (tactic t) {
+ Gst next { init };
+ for (action a : t.acts) {
+ next = act(next, a);
+ }
+ next.end_day();
+ return next;
+ }
+
+ Gst& act (Gst &gst, action a) {
+ if (a.type == actype::move) {
+ Entity &ent = gst.get_at(a.x, a.y);
+ ent.x = a.mx; ent.y = a.my;
+ ent.moved = 1; ent.done = true;
+ }
+ if (a.type == actype::attack) {
+ Entity &ent = gst.get_at(a.x, a.y);
+ ent.x = a.mx; ent.y = a.my;
+ ent.moved = 1;
+ Entity &def = gst.get_at(a.tx, a.ty);
+ gst.battle(ent, def);
+ ent.done = true;
+ }
+ return gst;
+ }
+};
+
+}
#endif \ No newline at end of file
diff --git a/game/ai/tactic.h b/game/ai/tactic.h
index 7eefef9..ec2e382 100644
--- a/game/ai/tactic.h
+++ b/game/ai/tactic.h
@@ -1,32 +1,32 @@
-#ifndef TACTIC_H
-#define TACTIC_H
-
-#include <string>
-#include <vector>
-
-#include "action.h"
-
-namespace ai {
-
-class tactic {
- public:
- tactic () { }
-
- std::vector<action> acts;
- float eval = 0;
-
- // copy constructor
- tactic (const tactic& rhs) { acts = rhs.acts; eval = rhs.eval; }
- tactic& operator=(const tactic& rhs) { acts = rhs.acts; eval = rhs.eval; }
-
- std::string to_string () {
- std::string str = "tactic eval= " + std::to_string(eval) + "\n";
- for (action act : acts) {
- str += act.to_string() + "\n";
- }
- return str;
- }
-};
-
-}
+#ifndef TACTIC_H
+#define TACTIC_H
+
+#include <string>
+#include <vector>
+
+#include "action.h"
+
+namespace ai {
+
+class tactic {
+ public:
+ tactic () { }
+
+ std::vector<action> acts;
+ float eval = 0;
+
+ // copy constructor
+ tactic (const tactic& rhs) { acts = rhs.acts; eval = rhs.eval; }
+ tactic& operator=(const tactic& rhs) { acts = rhs.acts; eval = rhs.eval; }
+
+ std::string to_string () {
+ std::string str = "tactic eval= " + std::to_string(eval) + "\n";
+ for (action act : acts) {
+ str += act.to_string() + "\n";
+ }
+ return str;
+ }
+};
+
+}
#endif \ No newline at end of file