Skip to content

Commit fc2f059

Browse files
committed
Merge remote-tracking branch 'origin/road_implementation' into serialization
Conflicts: include/GameBoard.h include/Player.h include/Road.h src/GameBoard.cpp src/Road.cpp tests/test_GameBoard.cpp
2 parents 5836761 + 2b3c207 commit fc2f059

File tree

10 files changed

+607
-48
lines changed

10 files changed

+607
-48
lines changed

include/GameBoard.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,25 @@ class GameBoard {
2222
private:
2323
std::map<Coordinate, std::unique_ptr<GamePiece>> corners;
2424
std::map<Coordinate, std::unique_ptr<GamePiece>> resources;
25-
26-
std::vector<std::unique_ptr<Road>> roads;
2725
std::vector<std::unique_ptr<Player>> players;
2826

2927
void addResource(int x, int y, resourceType res, int val);
3028
bool checkRolls(int* rolls);
31-
3229

30+
std::map<Coordinate, std::vector<Road*>> roads;
31+
32+
bool verifyRoadPlacement(Coordinate start, Coordinate end, Player& Owner);
33+
bool outOfBounds(const Coordinate& coord);
34+
bool roadExists(Coordinate start, Coordinate end);
35+
bool isRoadConnectionPoint(Coordinate start, Coordinate end, Player& Owner);
36+
37+
int constructBoardFromFile(std::ifstream &file);
38+
int constructFileFromBoard(std::ofstream &file);
39+
40+
void freeRoads();
41+
void removeRoadEnd(Road * startRoad);
42+
int FindLongestRoad_FromPoint(Coordinate curr, Player & owner, std::map<Coordinate, bool>& marked, int length);
43+
3344
public:
3445
GameBoard(std::vector<std::unique_ptr<Player>>&& players);
3546
GameBoard(std::istream& in);
@@ -40,10 +51,15 @@ class GameBoard {
4051
void save(std::ostream& out);
4152

4253
const std::map<Coordinate, std::unique_ptr<GamePiece>>& getResources() const;
54+
Road * getRoad(Coordinate start, Coordinate end);
4355

56+
int FindLongestRoad(Player & owner);
57+
4458
std::vector<Settlement*> GetNeighboringSettlements(Coordinate location);
4559

4660
void PlaceSettlement(Coordinate location, Player& Owner);
61+
void PlaceRoad(Coordinate start, Coordinate end, Player& Owner);
62+
4763

4864
void init_resources();
4965

include/Player.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class Player {
5252
int getDevCardsInHand();
5353

5454
void buyCard(std::unique_ptr<DevelopmentCard> card);
55+
std::string getName() const;
56+
5557
void playCard(DevelopmentCard* card);
5658

5759
int getWood() const;
@@ -66,8 +68,6 @@ class Player {
6668
void setWheat(int resource);
6769
void setWool(int resource);
6870

69-
std::string getName() const;
70-
7171
void accept(GameVisitor& visitor);
7272
bool operator==(const Player& player) const;
7373
};

include/Road.h

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,44 @@
22
#define ROAD_H
33

44
#include "Util.h"
5+
#include "Player.h"
6+
#include <vector>
7+
#include <cmath>
58

69
#include "Player.h"
710

811
class GameVisitor;
912

1013
class Road {
1114
private:
12-
Player& owner;
15+
bool checkRoad();
16+
1317
Coordinate start;
1418
Coordinate end;
19+
20+
bool marker;
1521
public:
16-
Road(Player& owner, Coordinate start, Coordinate end);
22+
Road(Coordinate start, Coordinate end, Player& Owner);
1723
Road(Road&) = delete;
18-
~Road();
24+
virtual ~Road();
1925
Road& operator=(Road&) = delete;
20-
21-
virtual void accept(GameVisitor& visitor);
26+
2227
Coordinate getStart() const;
2328
Coordinate getEnd() const;
29+
30+
bool equals(const Road& otherRoad);
31+
bool equals(const Coordinate& otherStart, const Coordinate& otherEnd);
32+
33+
bool isMarked();
34+
void mark();
35+
void unmark();
36+
2437
Player& getOwner();
2538
const Player& getOwner() const;
39+
40+
Player* owner;
2641

42+
virtual void accept(GameVisitor& visitor);
2743
bool operator==(const Road&) const;
2844
};
2945

src/GameBoard.cpp

Lines changed: 221 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,46 @@ GameBoard::GameBoard(istream& in) {
6666
}
6767

6868
GameBoard::~GameBoard() {
69-
69+
freeRoads();
70+
}
71+
72+
/*
73+
* Frees the roads data structure to prevent memory leaks
74+
*/
75+
76+
void GameBoard::freeRoads(){
77+
//Iterate over all the points in the roads map
78+
for (auto roadVector = roads.begin(); roadVector != roads.end(); ++roadVector)
79+
{
80+
//Iterate all the roads at a given point
81+
for (std::vector<Road*>::iterator road = roadVector->second.begin(); road != roadVector->second.end(); ++road) {
82+
Road * roadPtr = *road;
83+
84+
//If this is the start of the road we want to remove it, but we must first erase it the list at the other end of the road
85+
//If we don't then we may try to access a road which has already been freed
86+
if(roadPtr != NULL && roadPtr->getStart() == roadVector->first){
87+
removeRoadEnd(roadPtr);
88+
roadVector->second.erase(road);
89+
//Need to decrement the iterator to account for the lost item
90+
road--;
91+
delete roadPtr;
92+
}
93+
}
94+
}
95+
}
96+
97+
/**
98+
* Find and remove the road that matches startRoad
99+
*/
100+
void GameBoard::removeRoadEnd(Road * startRoad){
101+
std::vector<Road*> endRoadVector = roads[startRoad->getEnd()];
102+
for(std::vector<Road*>::iterator endRoad = endRoadVector.begin(); endRoad != endRoadVector.end(); ++endRoad){
103+
if((*endRoad) == startRoad){
104+
endRoadVector.erase(endRoad);
105+
//Need to decrement the iterator to account for the lost item
106+
endRoad--;
107+
}
108+
}
70109
}
71110

72111
void GameBoard::save(ostream& out) {
@@ -81,29 +120,203 @@ const map<Coordinate, unique_ptr<GamePiece>>& GameBoard::getResources() const {
81120
return resources;
82121
}
83122

84-
std::vector<Settlement*> GameBoard::GetNeighboringSettlements(Coordinate location) {
85-
static Coordinate adjacentCoordDiffs[] = {Coordinate(0, 1), Coordinate(1, 0), Coordinate(1, -1), Coordinate(0, -1), Coordinate(-1, 0), Coordinate(-1, 1)};
123+
std::vector<Settlement*> GameBoard::GetNeighboringSettlements(
124+
Coordinate location) {
125+
static Coordinate adjacentCoordDiffs[] = { Coordinate(0, 1), Coordinate(1,
126+
0), Coordinate(1, -1), Coordinate(0, -1), Coordinate(-1, 0),
127+
Coordinate(-1, 1) };
86128
std::vector<Settlement*> v;
87-
for(unsigned int i = 0; i < 6; i++) {
129+
for (unsigned int i = 0; i < 6; i++) {
88130
const Coordinate& diff = adjacentCoordDiffs[i];
89-
Coordinate adjacentPoint(location.first + diff.first, location.second + diff.second);
131+
Coordinate adjacentPoint(location.first + diff.first,
132+
location.second + diff.second);
90133
auto it = resources.find(adjacentPoint);
91-
if(it != resources.end()) {
134+
if (it != resources.end()) {
92135
GamePiece* piece = it->second.get();
93-
if(dynamic_cast<Settlement*>(piece)) {
136+
if (dynamic_cast<Settlement*>(piece)) {
94137
v.push_back(static_cast<Settlement*>(piece));
95138
}
96139
}
97140
}
98141
return v;
99142
}
100143

144+
/**
145+
* Checks to make sure the coordinate is within bounds of the board
146+
*/
147+
bool GameBoard::outOfBounds(const Coordinate& coord) {
148+
/**
149+
* This code is embarrassing, but I couldn't really figure out how to easily check for out of bounds
150+
* I'm sure there is a simple algebraic function that does it, but I went for the hacky way.
151+
*
152+
* Discussed that we can just do a find in the map, and if it's not found then it's out of bounds
153+
*/
154+
155+
switch (coord.second) {
156+
case 0:
157+
return !(coord.first >= 0 && coord.first <= 4);
158+
break;
159+
case 1:
160+
return !(coord.first >= -2 && coord.first <= 5);
161+
break;
162+
case 2:
163+
return !(coord.first >= -3 && coord.first <= 5);
164+
break;
165+
case 3:
166+
return !(coord.first >= -3 && coord.first <= 4);
167+
break;
168+
case 4:
169+
return !(coord.first >= -4 && coord.first <= 4);
170+
break;
171+
case 5:
172+
return !(coord.first >= -4 && coord.first <= 3);
173+
break;
174+
case 6:
175+
return !(coord.first >= -5 && coord.first <= 3);
176+
break;
177+
case 7:
178+
return !(coord.first >= -5 && coord.first <= 2);
179+
break;
180+
case 8:
181+
return !(coord.first >= -4 && coord.first <= 0);
182+
break;
183+
default:
184+
break;
185+
}
186+
return true;
187+
}
188+
189+
/**
190+
* Checks to make sure the road doesn't already exist. If it does, then we don't want to add it again
191+
*/
192+
bool GameBoard::roadExists(Coordinate start, Coordinate end) {
193+
Road * isRoad = getRoad(start, end);
194+
if (isRoad == NULL)
195+
return false;
196+
return true;
197+
}
198+
199+
/**
200+
* Checks to make sure the road being placed at a valid point according to the rules
201+
*/
202+
bool GameBoard::isRoadConnectionPoint(Coordinate start, Coordinate end, Player& Owner){
203+
/** Need to figure out the CornerPiece/GamePiece predicament
204+
CornerPiece * corner = corners[start];
205+
if(corner != NULL){
206+
if (corner->getOwner() == Owner)
207+
return true;
208+
}
209+
return false;
210+
**/
211+
return true;
212+
}
213+
214+
/**
215+
* Runs a series of checks to make sure the road can be placed
216+
*/
217+
bool GameBoard::verifyRoadPlacement(Coordinate start, Coordinate end, Player& Owner) {
218+
if (outOfBounds(start) || outOfBounds(end))
219+
return false;
220+
221+
if (roadExists(start, end))
222+
return false;
223+
224+
if (!isRoadConnectionPoint(start, end, Owner))
225+
return false;
226+
227+
return true;
228+
}
229+
230+
/**
231+
* Places a road at the specified coordinates that will be owned by the given player
232+
*/
233+
void GameBoard::PlaceRoad(Coordinate start, Coordinate end, Player& Owner) {
234+
if (!verifyRoadPlacement(start, end, Owner))
235+
return;
236+
237+
Road * newRoad;
238+
try {
239+
newRoad = new Road(start, end, Owner);
240+
} catch (int n) {
241+
//Coordinates did not meet the criteria for a valid road
242+
return;
243+
}
244+
std::vector<Road*> roadVector = roads[start];
245+
roadVector.push_back(newRoad);
246+
roads[start] = roadVector;
247+
248+
roadVector = roads[end];
249+
roadVector.push_back(newRoad);
250+
roads[end] = roadVector;
251+
}
252+
253+
/**
254+
* returns a pointer to the road located at the specified coordinates. Will return NULL if the road is not found
255+
*/
256+
Road * GameBoard::getRoad(Coordinate start, Coordinate end){
257+
std::vector<Road*> roadVector = roads[start];
258+
for (std::vector<Road*>::iterator road = roadVector.begin(); road != roadVector.end(); ++road) {
259+
if ((*road)->equals(start, end))
260+
return *road;
261+
}
262+
return NULL;
263+
}
264+
265+
/**
266+
* Parent function for the find longest road traversal. Note that longest path is NP-Hard, so there is no simple algorithm for this.
267+
*/
268+
int GameBoard::FindLongestRoad(Player & owner){
269+
int longest_path = 0;
270+
//for each road vertex v on the board
271+
for (auto roadVector = roads.begin(); roadVector != roads.end(); ++roadVector){
272+
//find the longest path from v
273+
std::map<Coordinate, bool> marked;
274+
Coordinate start = roadVector->first;
275+
int temp_longest_path = FindLongestRoad_FromPoint(start, owner, marked, 0);
276+
277+
//if that path is longer than the current longest, set to the longest
278+
if (temp_longest_path > longest_path)
279+
longest_path = temp_longest_path;
280+
}
281+
282+
return longest_path;
283+
}
284+
285+
286+
int GameBoard::FindLongestRoad_FromPoint(Coordinate curr, Player & owner, std::map<Coordinate, bool>& marked, int length){
287+
marked[curr] = true;
288+
int longest_path = length;
289+
//traverse all the surrounding edges and vertices
290+
std::vector<Road*> roadVector = roads[curr];
291+
for (std::vector<Road*>::iterator road = roadVector.begin(); road != roadVector.end(); ++road) {
292+
int temp_longest_path = length;
293+
294+
//if the owner is correct and the road is unmarked
295+
if ( !(*road)->isMarked() && (*road)->owner->getName().compare(owner.getName()) == 0){
296+
297+
temp_longest_path++;
298+
(*road)->mark();
299+
//Check if you can traverse to the next vertex and make that step if you can
300+
if(curr != (*road)->getStart() && !marked[(*road)->getStart()]){
301+
temp_longest_path = FindLongestRoad_FromPoint((*road)->getStart(), owner, marked, temp_longest_path);
302+
}else if (curr != (*road)->getEnd() && !marked[(*road)->getEnd()]){
303+
temp_longest_path = FindLongestRoad_FromPoint((*road)->getEnd(), owner, marked, temp_longest_path);
304+
}
305+
(*road)->unmark();
306+
}
307+
308+
if(temp_longest_path > longest_path)
309+
longest_path = temp_longest_path;
310+
}
311+
marked[curr] = false;
312+
return longest_path;
313+
}
314+
101315
/*
102316
* Initialize board with a set of resources.
103317
* Currently only the standard configuration (no custom shapes or expansion packs) is implemented.
104318
* Board tiles and roll numbers are randomized.
105319
*/
106-
107320
void GameBoard::init_resources()
108321
{
109322
std::srand(std::time(0));
@@ -150,9 +363,6 @@ void GameBoard::accept(GameVisitor& visitor) {
150363
for(auto& it : resources) {
151364
it.second->accept(visitor);
152365
}
153-
for(auto& it : roads) {
154-
it->accept(visitor);
155-
}
156366
for(auto& it : players) {
157367
it->accept(visitor);
158368
}
@@ -180,17 +390,6 @@ bool GameBoard::operator==(const GameBoard& other) const {
180390
return false;
181391
}
182392
}
183-
for(auto& it : roads) {
184-
bool hasIt = false;
185-
for(auto& otherIt : other.roads) {
186-
if(*it == *otherIt) {
187-
hasIt = true;
188-
}
189-
}
190-
if(hasIt == false) {
191-
return false;
192-
}
193-
}
194393
if(players.size() != other.players.size()) {
195394
return false;
196395
}

0 commit comments

Comments
 (0)