@@ -66,7 +66,46 @@ GameBoard::GameBoard(istream& in) {
6666}
6767
6868GameBoard::~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
72111void 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-
107320void 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