-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbasicaisnake.cpp
More file actions
117 lines (97 loc) · 3.54 KB
/
Copy pathbasicaisnake.cpp
File metadata and controls
117 lines (97 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "basicaisnake.h"
#include <queue>
#include <QDebug>
#include <cassert>
BasicAISnake::BasicAISnake(QObject *parent) : QObject(parent)
{}
void BasicAISnake::processUpdate(std::set<Coordinates> updatedCells)
{
for (const auto & cell : updatedCells)
field[cell.uy()][cell.ux()] = remoteField->get(cell).type;
head = snake()->headPosition();
static const auto bfs_shortest_path
= [this](Coordinates start) -> std::vector<Coordinates> // path
{
using std::vector;
using std::queue;
vector<vector<int>> distance(height, vector<int>(width, INT_MAX));
std::list<Coordinates> finishes;
for (size_t i = 0; i < field.size(); ++i)
for (size_t j = 0; j < field[i].size(); ++j)
if (field[i][j] == CellType::Apple)
finishes.push_back(Coordinates{j, i});
distance[start.uy()][start.ux()] = 0;
queue<Coordinates> toCheck;
toCheck.push(start);
while (!toCheck.empty())
{
auto current = toCheck.front();
auto currentDistance = distance[current.uy()][current.ux()];
toCheck.pop();
for (int i = 0; i < 4; ++i)
{
Direction dir = static_cast<Direction>(i);
Coordinates nxt = current.shift(dir, 1);
if (remoteField->validatePosition(nxt)
&& !remoteField->get(nxt).isSnake()
&& currentDistance + 1 < distance[nxt.uy()][nxt.ux()])
{
distance[nxt.uy()][nxt.ux()] = currentDistance + 1;
toCheck.push(nxt);
}
}
}
Coordinates finish{};
for (const auto & f : finishes)
if (!finish.isValid() || distance[finish.uy()][finish.ux()] > distance[f.uy()][f.ux()])
finish = f;
if (!finish.isValid() || distance[finish.uy()][finish.ux()] == INT_MAX)
return vector<Coordinates>{};
vector<Coordinates> reversedPath;
while (finish != start)
{
if (reversedPath.size() > 100)
{
qDebug() << "Shit!";
}
reversedPath.push_back(finish);
auto currentDistance = distance[finish.uy()][finish.ux()];
for (int i = 0; i < 4; ++i)
{
auto dir = static_cast<Direction>(i);
auto neighbor = finish.shift(dir, 1);
if (remoteField->validatePosition(neighbor)
&& distance[neighbor.uy()][neighbor.ux()] == currentDistance - 1)
{
finish = neighbor;
break;
}
}
assert(true);
}
return reversedPath;
};
auto path = bfs_shortest_path(head);
Direction dir = Direction::North;
if (!path.empty())
{
auto diff = head.diff(path.back());
dir = diff.xdiff != 0 ? diff.xdir : diff.ydir;
}
snake()->setDirection(dir);
}
void BasicAISnake::initGame()
{
remoteField = game()->getField();
height = remoteField->height();
width = remoteField->width();
field.resize(height, std::vector<CellType>(width));
auto filled = remoteField->getNonEmptyCells();
for (const auto & coordinate: filled)
{
auto cell = remoteField->get(coordinate);
field[coordinate.uy()][coordinate.ux()] = cell.type;
}
head = snake()->headPosition();
connect(game(), &Game::updated, this, &BasicAISnake::processUpdate, Qt::QueuedConnection);
}