-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBoard.cpp
237 lines (198 loc) · 6.15 KB
/
Board.cpp
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#include "Board.h"
#include <algorithm>
#include <iostream>
#include "DisplayPDCurses.h"
Board::Board() noexcept : width_{ 0 }, heigth_{ 0 }
{
p_display_ = new Quoridor::Display::PDCurses();
}
Board::~Board()
{
}
void Board::add(PawnPosition pawn)
{
try
{
// Find player on board
auto& player = getPawnNonConst(pawn.playerName());
// Existing one : replace it
player = pawn;
}
catch (const std::out_of_range &)
{
// New pawn : Add it
pawnsPosition_.emplace_back(pawn);
// Initialize pawn style on display
if(p_display_) p_display_->pawn(pawnsPosition_.size(), pawn.color(), (pawnsPosition_.size() == 1 ? PawnStyle::cross : PawnStyle::circle));
}
}
void Board::add(const WallPosition & wall)
{
wallsPosition_.emplace_back(wall);
}
void Board::callHandler()
{
if (handler_)
handler_();
}
void Board::add(const Move & move)
{
switch (move.type())
{
case Move::Type::pawn:
add(move.pawn());
callHandler();
break;
case Move::Type::wall:
add(move.wall());
callHandler();
break;
case Move::Type::none:
break;
default:
throw std::out_of_range("Unknown move to add to the board");
}
if (showMoves_)
{
std::cout << "Board status : \n" << *this << std::endl;
display();
}
}
void Board::registerHandler(const handlerCB &&handler)
{
handler_ = std::move(handler);
}
void Board::display()
{
if (p_display_)
{
p_display_->Board();
for (auto& p : pawnsPosition_)
p_display_->pawn(p, (pawnsPosition_[0].playerName() == p.playerName() ? 1 : 2));
for (auto& w : wallsPosition_)
p_display_->wall(w);
// Force to refresh the display
p_display_->refresh();
}
}
PawnPosition& Board::getPawnNonConst(const PlayerName& name)
{
return const_cast<PawnPosition&>(static_cast<const Board&>(*this).getPawn(name));
}
const PawnPosition & Board::getPawn(const PlayerName& name) const
{
// Find player by name in vector
auto player = std::find_if(pawnsPosition_.begin(), pawnsPosition_.end(),
[name](const PawnPosition &p)->bool { return (p.playerName() == name); });
if (player == pawnsPosition_.end())
throw std::out_of_range("Player " + name + " unknown");
return *player;
}
bool Board::existsWall(const WallPosition & wall) const
{
// Find player by name in vector
auto wallFound = std::find(wallsPosition_.begin(), wallsPosition_.end(), wall);
return (wallFound != wallsPosition_.end());
}
bool Board::existsPawn(const Position & pawnPos) const
{
// Find player by its getPawn in vector
auto pawnFound = std::find_if(pawnsPosition_.begin(), pawnsPosition_.end(),
[pawnPos](const PawnPosition &p)->bool { return ((Position)p == pawnPos); });
return (pawnFound != pawnsPosition_.end());
}
bool Board::findPath(const WallPosition& wall, const PlayerName& name, const std::vector<BoardPosition>& arrival) const
{
AStarBoard generator{ width_, heigth_, wallsPosition_ };
auto current = static_cast<BoardPosition>(getPawn(name));
return generator.findPath(wall, current, arrival);
}
AStarBoard::AStarBoard(const int width, const int heigth, const std::vector<WallPosition>& walls) : generator_{}
{
// World = [ 0 ; WorldSize-1 ] ===> width = WorldSize
generator_.setWorldSize({ 2 * width - 1, 2 * heigth - 1 });
generator_.setHeuristic(AStar::Heuristic::manhattan); // x3 Faster
//generator_.setHeuristic(AStar::Heuristic::euclidean);
//generator_.setHeuristic(AStar::Heuristic::octagonal);
// generator.setDiagonalMovement(false); // false by default
// Generate board
for (const auto& w : walls)
add(w);
}
bool AStarBoard::findPath(const WallPosition& wall, const BoardPosition& current, const std::vector<BoardPosition>& arrivals)
{
int cpt(0); bool log = false;
//Add new wall to check
add(wall);
for (const auto & arrival : arrivals)
{
auto source = position(current);
auto target = position(arrival);
auto path = generator_.findPath(source, target);
// A path exists to win and ended on arrival position
if (!path.empty() && (*path.begin() == target) && (*path.rbegin() == source))
{
if (log)
{
std::cout << cpt++ << " - findPath( (" << source.x << " " << source.y << "), "
<< "(" << target.x << " " << target.y << ") :\n";
for (auto& coordinate : path) {
std::cout << "(" << coordinate.x << " " << coordinate.y << "), ";
}
std::cout << " *END*\n";
}
//Remove new wall checked
remove(wall);
return true;
}
}
//Remove new wall checked
remove(wall);
// No path to win
return false;
}
void AStarBoard::add(const WallPosition &wall)
{
for (const auto v : position(wall))
{
try
{
generator_.addCollision(v);
}
catch (const std::out_of_range &) {}
}
}
void AStarBoard::remove(const WallPosition &wall)
{
for (const auto v : position(wall))
{
try
{
generator_.removeCollision(v);
}
catch (const std::out_of_range &) {}
}
}
AStar::Vec2i AStarBoard::position(const BoardPosition &bp)
{
return AStar::Vec2i({ 2 * bp.x() - 2, 2 * bp.y() - 2 });
}
std::vector<AStar::Vec2i> AStarBoard::position(const WallPosition &wp)
{
std::vector<AStar::Vec2i> list;
if (wp.direction() == WallPosition::Direction::horizontal)
{
list.push_back({ 2 * wp.x() - 2 + 0, 2 * wp.y() - 1 });
list.push_back({ 2 * wp.x() - 2 + 1, 2 * wp.y() - 1 });
list.push_back({ 2 * wp.x() - 2 + 2, 2 * wp.y() - 1 });
list.push_back({ 2 * wp.x() - 2 + 3, 2 * wp.y() - 1 });
}
else
{
list.push_back({ 2 * wp.x() - 1, 2 * wp.y() - 2 + 0 });
list.push_back({ 2 * wp.x() - 1, 2 * wp.y() - 2 + 1 });
list.push_back({ 2 * wp.x() - 1, 2 * wp.y() - 2 + 2 });
list.push_back({ 2 * wp.x() - 1, 2 * wp.y() - 2 + 3 });
}
return list;
}