Skip to content
Browse files

MaskToString method. Upd AI algorithm

  • Loading branch information...
1 parent e19cda3 commit 418503c7a90376b8a4586bc3662fa0c1a584d575 @Ignotus committed Sep 5, 2012
View
46 dottable.cpp
@@ -81,36 +81,36 @@ namespace KDots
return *next;
}
}
+ }
- bool isInPolygon (Polygon_ptr polygon, const Point& point)
- {
- // k - a count of points in the same line with "point" object
- // i - crosses count
- int i = 0, shift;
+ bool DotTable::isInPolygon (Polygon_ptr polygon, const Point& point)
+ {
+ // k - a count of points in the same line with "point" object
+ // i - crosses count
+ int i = 0, shift;
- Polygon::const_iterator itr = polygon->begin (), itrEnd = polygon->end ();
- while (itr != itrEnd)
+ Polygon::const_iterator itr = polygon->begin (), itrEnd = polygon->end ();
+ while (itr != itrEnd)
+ {
+ if (itr->y () != point.y ())
{
- if (itr->y () != point.y ())
- {
- ++itr;
- continue;
- }
-
- if (itr->x () == point.x ())
- return true;
-
- const Point& prevPoint = getPrevPoint (polygon, itr);
- const Point& nextPoint = getNextPoint (polygon, shift, itr);
-
- if (itr->x () < point.x () && prevPoint.y () != nextPoint.y () && shift == 1)
- ++i;
-
++itr;
+ continue;
}
+
+ if (itr->x () == point.x ())
+ return true;
+
+ const Point& prevPoint = getPrevPoint (polygon, itr);
+ const Point& nextPoint = getNextPoint (polygon, shift, itr);
- return i % 2;
+ if (itr->x () < point.x () && prevPoint.y () != nextPoint.y () && shift == 1)
+ ++i;
+
+ ++itr;
}
+
+ return i % 2;
}
void DotTable::pushPoint (const Point& point)
View
5 dottable.hpp
@@ -44,6 +44,9 @@ namespace KDots
std::vector<Polygon_ptr> m_polygons;
public:
DotTable (const GameConfig& config, QObject *parent = 0);
+
+ static bool isInPolygon (Polygon_ptr polygon, const Point& point);
+
virtual ~DotTable () {}
GameConfig gameConfig () const;
@@ -75,4 +78,4 @@ namespace KDots
};
}
-#endif
+#endif
View
45 plugins/simpleai/prioritymap.hpp
@@ -27,6 +27,7 @@
#define KDOTS_PLUGINS_SIMPLEAI_PRIORITY_HPP
#include <list>
#include <vector>
+#include <KDebug>
#include <constants.hpp>
#include <point.hpp>
@@ -66,6 +67,50 @@ namespace KDots
{
}
+ QString toString() const
+ {
+ QString res;
+ for (std::size_t j = 0; j < m_map.size (); ++j)
+ {
+ res += "\n{ ";
+ for (std::size_t i = 0; i < m_map.front ().size (); ++i)
+ {
+ switch (m_map[j][i])
+ {
+ case EM: //Empty
+ res += "EM ";
+ break;
+ case NM: // Does not matter
+ res += "NM ";
+ break;
+ case FI: //First
+ res += "FI ";
+ break;
+ case SE: //Second
+ res += "SE ";
+ break;
+ case PF: // Possibly first
+ res += "PF ";
+ break;
+ case PS: // Possibly second
+ res += "PS ";
+ break;
+ case CU: // Current
+ res += "CU ";
+ break;
+ default:
+ kDebug () << "WTF?";
+ }
+ }
+ res += "}";
+
+ }
+
+ res += "\n";
+
+ return res;
+ }
+
bool operator== (const MapData& other) const;
bool operator!= (const MapData& other) const;
};
View
264 plugins/simpleai/rival.cpp
@@ -38,6 +38,7 @@
#include <dottable.hpp>
#include <stepqueue.hpp>
#include <constants.hpp>
+#include <polygonfinder.hpp>
#include <graph.hpp>
#include "prioritymap.hpp"
@@ -62,7 +63,7 @@ namespace KDots
void Rival::setDifficulty (int diff)
{
- m_iterations = diff + 2;
+ m_iterations = diff;
}
Rival::~Rival()
@@ -77,76 +78,98 @@ namespace KDots
return m_table->stepQueue ()->getCurrentOwner () == m_table->stepQueue ()->firstOwner ();
}
- namespace
+ bool Rival::hasMask (const Point& point, const MapData& mask)
{
- bool hasMask (const Graph& graph, const Point& point, const MapData& mask)
+ const Graph& graph = m_table->graph ();
+ const Owner currentOwner = m_table->stepQueue ()->getCurrentOwner ();
+ const Owner otherOwner = StepQueue::other (currentOwner);
+
+ const MapType& map = mask.m_map;
+ const Point& currentPoint = mask.m_current;
+
+ for (std::size_t j = 0, height = map.size (), i,
+ width = map.front ().size (); j < height; ++j)
{
- const Owner currentOwner = graph[point].owner ();
- const Owner otherOwner = StepQueue::other (currentOwner);
- const MapType& map = mask.m_map;
- const Point& currentPoint = mask.m_current;
-
- for (std::size_t j = 0, height = map.size (), i,
- width = map.front ().size (); j < height; ++j)
+ for (i = 0; i < width; ++i)
{
- for (i = 0; i < width; ++i)
- {
- const Point newPoint (currentPoint.x () - i + point.x (),
- currentPoint.y () - j + point.y ());
+ const Point newPoint (currentPoint.x () - i + point.x (),
+ currentPoint.y () - j + point.y ());
+
+ if (!graph.isValid (newPoint))
+ return false;
+
+ const MapElement el = map[j][i];
+ const GraphPoint& graphPoint = graph[newPoint];
+ const Owner own = graphPoint.owner ();
+ const bool captured = graphPoint.isCaptured ();
- if (!graph.isValid (newPoint))
+ if (captured)
+ return false;
+
+ switch (el)
+ {
+ case EM: //Empty
+ if (own != NONE)
return false;
-
- const MapElement el = map[j][i];
- const GraphPoint& graphPoint = graph[newPoint];
- const Owner own = graphPoint.owner ();
- const bool captured = graphPoint.isCaptured ();
- switch (el)
- {
- case EM: //Empty
- if (own != NONE || captured)
- return false;
- break;
- case FI: //First
- if (own != otherOwner || captured)
- return false;
- break;
- case SE: //Second
- if (own != currentOwner || captured)
- return false;
- break;
- case PF: // Possibly first
- if (own == currentOwner || captured)
- return false;
- break;
- case PS: // Possibly second
- if (own == otherOwner || captured)
- return false;
- default:
- break;
- }
+ break;
+ case FI: //First
+ if (own != otherOwner)
+ return false;
+ break;
+ case SE: //Second
+ if (own != currentOwner)
+ return false;
+ break;
+ case PF: // Possibly first
+ if (own == currentOwner)
+ return false;
+ break;
+ case PS: // Possibly second
+ if (own == otherOwner)
+ return false;
+ break;
+ case NM: case CU:
+ break;
+ default:
+ kDebug () << "WTF";
+ break;
}
}
-
- return true;
}
- float calcImportance(const Graph& graph, const Point& point)
- {
+ return true;
+ }
+
+ float Rival::calcImportance(const Point& point)
+ {
float priority = -0.5;
-
- for (const MapData& table : PriorityMap::instance ().priorityMap ())
+
+ int id = 0;
+ for (const MapData& table : PriorityMap::instance ().priorityMap ())
+ {
+ if (!hasMask (point, table))
{
- if (!hasMask (graph, point, table))
- continue;
-
+ ++id;
+ continue;
+ }
+// else
+// {
+// kDebug () << "Found mask #" << id << "\n"
+// << table.toString ()
+// << "in the point {" << point.x () << ", " << point.y () << "}";
+// }
+
if (table.m_priority > priority)
priority = table.m_priority;
- }
- return priority;
+ ++id;
}
+ return priority;
+ }
+
+ namespace
+ {
bool isEmptyAround (const Graph& graph, const Point& point)
{
for (int i = 0; i < DIRECTION_COUNT; ++i)
@@ -161,25 +184,36 @@ namespace KDots
return true;
}
+
+ bool minSize (const Point& lastPoint, const std::vector<Point> points)
+ {
+ int distance = 10000;
+ int id = 0;
+ int index = 0;
+ for (const Point& point : points)
+ {
+ const int sqrDistance = Point::sqrLength (point, lastPoint);
+ if (sqrDistance < distance)
+ {
+ distance = sqrDistance;
+ index = id;
+ }
+
+ ++id;
+ }
+
+ return index;
+ };
}
- void Rival::nextStep (const Point& point)
+ void Rival::calcRange (int& min_x, int& min_y, int& max_x, int& max_y)
{
- if (isAllow ())
- return;
-
- const Graph& gr = m_table->graph ();
-
- std::vector<Point> points;
- float max_priority = -0.5 * m_iterations;
-
- int min_x = point.x () - 1, min_y = point.y () - 1;
- int max_x = point.x () + 1, max_y = point.y () + 1;
- for (int j = 0, max_j = gr.height (), max_i = gr.width (), i; j < max_j; ++j)
+ const Graph& graph = m_table->graph ();
+ for (int j = 0, max_j = graph.height (), max_i = graph.width (), i; j < max_j; ++j)
{
for (i = 0; i < max_i; ++i)
{
- const GraphPoint& point = gr[i][j];
+ const GraphPoint& point = graph[Point (i, j)];
if (point.owner () != NONE)
{
if (i - 1 < min_x)
@@ -194,92 +228,120 @@ namespace KDots
}
}
}
+ }
+
+ bool Rival::hasCaptured (const Point& point, Owner current)
+ {
+ const Graph& graph = m_table->graph ();
+ auto steps = m_table->stepQueue ();
+ PolygonFinder findPolygon (graph, current);
+
+ //O(n)
+ const PolyList& polyList = findPolygon (point);
+
+ const Owner otherOwner = StepQueue::other (current);
+
+ const auto& otherOwnerPoints = steps->getPoints (otherOwner);
+ for (const Point& p : otherOwnerPoints)
+ {
+ const GraphPoint& gpoint = graph[p];
+ if (gpoint.isCaptured ())
+ continue;
+
+ for (const Polygon_ptr& polygon : polyList)
+ {
+ if (DotTable::isInPolygon (polygon, p)
+ && gpoint.owner () == otherOwner)
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void Rival::nextStep (const Point& point)
+ {
+ if (isAllow ())
+ return;
+
+ int min_x = point.x () - 1, min_y = point.y () - 1;
+ int max_x = point.x () + 1, max_y = point.y () + 1;
+ calcRange (min_x, min_y, max_x, max_y);
m_pointStack.clear ();
- for (Graph::const_iterator itr = gr.begin (), itrEnd = gr.end ();
+ std::vector<Point> points;
+ float max_priority = -0.5 * m_iterations;
+ const Graph& graph = m_table->graph ();
+ for (Graph::const_iterator itr = graph.begin (), itrEnd = graph.end ();
itr != itrEnd; ++itr)
{
if (itr->owner () != NONE || itr->isCaptured ())
continue;
const Point& newPoint = itr.point ();
- if (isEmptyAround (gr, newPoint))
+ if (isEmptyAround (graph, newPoint))
continue;
- if (newPoint.x () < min_x || newPoint.x () > max_x
- || newPoint.y () < min_y || newPoint.y () > max_y)
+ if (!(newPoint >= Point (min_x, min_y)
+ && newPoint <= Point (max_x, max_y)))
continue;
float imp = 0;
-
calcImportanceTree (imp, newPoint, 1);
if (imp == max_priority)
points.push_back (newPoint);
else if (imp > max_priority)
{
max_priority = imp;
+ kDebug () << "Max priority is changed to" << max_priority;
points.clear ();
points.push_back (newPoint);
}
}
- auto minSize = [&points] (const Point& lastPoint) {
- int distance = 10000;
- int id = 0;
- int index = 0;
- for (const Point& point : points)
- {
- const int sqrDistance = Point::sqrLength (point, lastPoint);
- if (sqrDistance < distance)
- {
- distance = sqrDistance;
- index = id;
- }
-
- ++id;
- }
-
- return index;
- };
-
if (!points.empty ())
{
- const int index = minSize (point);
- m_table->pushPoint (points[index]);
+ //const int index = minSize (point, points);
+ srand (std::time (NULL));
+ m_table->pushPoint (points[rand () % points.size ()]);
}
}
void Rival::calcImportanceTree (float& importance, const Point& point, int iteration)
{
- const Graph& gr = m_table->graph ();
-
- importance += calcImportance (gr, point);
+ const Owner current = m_table->stepQueue ()->getCurrentOwner ();
+ if (hasCaptured (point, current))
+ importance += 0.9;
+ else
+ importance += calcImportance (point);
+
m_pointStack.push_back (point);
if (iteration == m_iterations) // Need configure this feature
return;
float max_imp = -m_iterations;
int i = 0;
+ const Graph& graph = m_table->graph ();
for (; i < DIRECTION_COUNT; ++i)
{
const Point newPoint (point.x () + GRAPH_DX[i], point.y () + GRAPH_DY[i]);
- if (!gr.isValid (newPoint))
+ if (!graph.isValid (newPoint))
continue;
- const GraphPoint& newGrPoint = gr[newPoint];
+ const GraphPoint& newGrPoint = graph[newPoint];
if (!newGrPoint.isCaptured () && newGrPoint.owner () == NONE
&& std::find (m_pointStack.begin (), m_pointStack.end (), newPoint) == m_pointStack.end ())
{
float imp = 0;
calcImportanceTree (imp, newPoint, iteration + 1);
- if (max_imp == -m_iterations || imp < max_imp)
- max_imp = imp;
+ if (max_imp == -m_iterations || imp < max_imp)
+ max_imp = imp;
}
}
View
7 plugins/simpleai/rival.hpp
@@ -33,6 +33,8 @@ namespace KDots
{
namespace simpleai
{
+ struct MapData;
+
class Rival : public KDots::IRival
{
Q_OBJECT
@@ -53,7 +55,12 @@ namespace KDots
void setDotTable (DotTable *table);
private:
+ bool hasMask (const Point& point, const MapData& mask);
+ float calcImportance(const Point& point);
void calcImportanceTree (float& importance, const Point& point, int iteration);
+ void calcRange (int& min_x, int& min_y, int& max_x, int& max_y);
+ bool hasCaptured (const Point& point, Owner current);
+
signals:
void createDotTable (const GameConfig& config);
void needDestroy ();
View
3 plugins/simpleai/tests/prioritymaptest/prioritymaptest.hpp
@@ -68,7 +68,6 @@ private slots:
for (const MapData& data : dataList)
{
++k;
- qDebug () << Q_FUNC_INFO << __LINE__ << k;
QVERIFY (data.m_map[data.m_current.y ()][ data.m_current.x ()] == MapElement::CU);
}
@@ -118,6 +117,8 @@ private slots:
0.1
};
+ qDebug () << answer.toString ();
+
QVERIFY (rotated == answer);
const MapData& rotated_1 = PriorityMap::rotate (TEST_DATA_1);
View
10 point.hpp
@@ -85,10 +85,20 @@ namespace KDots
return m_x < other.m_x && m_y < other.m_y;
}
+ bool operator<= (const Point& other) const
+ {
+ return m_x <= other.m_x && m_y <= other.m_y;
+ }
+
bool operator> (const Point& other) const
{
return m_y > other.m_y && m_x > other.m_x;
}
+
+ bool operator>= (const Point& other) const
+ {
+ return m_y >= other.m_y && m_x >= other.m_x;
+ }
bool operator== (const Point& a) const
{
View
6 polygonfinder.cpp
@@ -32,7 +32,7 @@
namespace KDots
{
- PolygonFinder::PolygonFinder (Graph& graph, Owner owner)
+ PolygonFinder::PolygonFinder (const Graph& graph, Owner owner)
: m_graph (graph)
, m_current (owner)
, m_stepMap (graph.width (), std::vector<bool> (graph.height (), false))
@@ -73,6 +73,7 @@ namespace KDots
const PolyList& PolygonFinder::operator() (const Point& point)
{
+ m_first = point;
findPolygons (point);
const int max = maxSize (m_polygons);
@@ -109,7 +110,8 @@ namespace KDots
const GraphPoint& graphPoint = m_graph[newPoint];
- if (graphPoint.isCaptured () || graphPoint.owner () != m_current)
+ if (newPoint != m_first
+ && (graphPoint.isCaptured () || graphPoint.owner () != m_current))
continue;
findPolygons (newPoint);
View
7 polygonfinder.hpp
@@ -34,15 +34,16 @@ namespace KDots
{
struct Graph;
- class PolygonFinder
+ class KDOTS_EXPORT PolygonFinder
{
- Graph& m_graph;
+ const Graph& m_graph;
Owner m_current;
PolygonContainer m_cache;
std::vector<std::vector<bool>> m_stepMap;
PolyList m_polygons;
+ Point m_first;
public:
- PolygonFinder (Graph& graph, Owner owner);
+ PolygonFinder (const Graph& graph, Owner owner);
// O(n)
const PolyList& operator() (const Point& point);
private:

0 comments on commit 418503c

Please sign in to comment.
Something went wrong with that request. Please try again.