#include "environ.h" #include "fish.h" #include "utils.h" // constructor Environment::Environment(istream & input) : myWorld(0), myFishCreated(0), myFishCount(0) // precondition: input is open for reading, in correct format // postcondition: environment initialized and populated from input { int numRows, numCols, row, col; if (input >> numRows >> numCols) // resize the matrix { myWorld.resize(numRows); myNumCols = numCols; for(row = 0; row < numRows; row++) myWorld[row] = NULL; } else { cerr << "reading rows/columns failed in Environment" << endl; exit(1); } while (input >> row >> col) { AddFish(Position(row, col)); } } // public accessing functions int Environment::NumRows() const // postcondition: returns # rows in grid { return myWorld.length(); } int Environment::NumCols() const // postcondition: returns # columns in grid { return myNumCols; } apvector Environment::AllFish( ) const // postcondition: returned vector (call it fishList) contains all fish // in top-down, left-right order: // top-left fish in fishList[0], // bottom-right fish in fishList[fishList.length()-1]; // # fish in environment is fishList.length() { apvector fishList(myFishCount); int r, k; int count = 0; apstring s = ""; ListNode * tempPtr; // look at all grid positions, store fish found in vector fishList for (r = 0; r < NumRows(); r++) { for(tempPtr = myWorld[r]; tempPtr != NULL; tempPtr = tempPtr->next) { fishList[count] = tempPtr->theFish; count++; } } for (k = 0; k < count; k++) { s += fishList[k].Location().ToString() + " "; } DebugPrint(5, "Fish vector = " + s); return fishList; } bool Environment::IsEmpty(const Position & pos) const // postcondition: returns true if pos in grid and no fish at pos, // returns false otherwise { if (! InRange(pos)) { return false; // debug msg printed in InRange } ListNode * ptr = myWorld[pos.Row()]; while(ptr != NULL && ptr->columnIndex < pos.Col()) ptr = ptr->next; if(ptr == NULL || ptr->columnIndex > pos.Col()) return true; DebugPrint(5, pos.ToString() + " contains a fish."); return false; } // public modifying functions void Environment::Update(const Position & oldLoc, Fish & fish) // precondition: fish was located at oldLoc, has been updated // postcondition: if (fish.Location() != oldLoc) then oldLoc is empty; // Fish fish is updated properly in this environment { Fish emptyFish; if (InRange(oldLoc)) { ListNode * ptr = myWorld[oldLoc.Row()]; if(oldLoc.Row() == fish.Location().Row()) // no need to delete node, { // just replace fish and col while(ptr != NULL && ptr->columnIndex < oldLoc.Col()) { ptr = ptr->next; } if(ptr == NULL || ptr->columnIndex != oldLoc.Col() || ptr->theFish.Id() != fish.Id()) { cerr << "illegal fish move 1" << endl; } else { ptr->theFish = fish; ptr->columnIndex = fish.Location().Col(); } } else // fish changed row { // delete fish from oldLoc if(ptr == NULL || ptr->columnIndex > oldLoc.Col() || (ptr->columnIndex == oldLoc.Col() && ptr->theFish.Id() != fish.Id())) { cerr << "illegal fish move 2" << endl; } else if(ptr->columnIndex == oldLoc.Col()) // old location correct { // at first node, delete myWorld[oldLoc.Row()] = ptr->next; delete ptr; } else // not first node { while(ptr->next != NULL && ptr->next->columnIndex < oldLoc.Col()) ptr = ptr->next; if(ptr->next == NULL || ptr->next->columnIndex > oldLoc.Col() || ptr->next->theFish.Id() != fish.Id()) { cerr << "illegal fish move 3" << endl; } else // old location correct, { // delete node ListNode * temp = ptr->next; ptr->next = ptr->next->next; delete temp; } } DebugPrint(5, "fish deleted from oldPos " + oldLoc.ToString()); // insert fish at new location ptr = myWorld[fish.Location().Row()]; if(ptr == NULL || ptr->columnIndex > fish.Location().Col()) { myWorld[fish.Location().Row()] = new ListNode(fish, fish.Location().Col(), ptr); } else if(ptr->columnIndex == fish.Location().Col()) { cerr << "illegal fish move 4" << endl; } else // search for insertion point { while(ptr->next != NULL && ptr->next->columnIndex < fish.Location().Col()) ptr = ptr->next; if(ptr->next == NULL || ptr->next->columnIndex > fish.Location().Col()) { ptr->next = new ListNode(fish, fish.Location().Col(), ptr->next); } else { cerr << "illegal fish move 5" << endl; } } DebugPrint(5, "fish " + fish.ToString() + " inserted."); } } } void Environment::AddFish(const Position & pos) // precondition: no fish already at pos, i.e., IsEmpty(pos) // postcondition: fish created at pos { if (! IsEmpty(pos)) { cerr << "error, attempt to create fish at non-empty: " << pos << endl; return; } myFishCreated++; ListNode * ptr = myWorld[pos.Row()]; if(ptr == NULL || ptr->columnIndex > pos.Col()) { myWorld[pos.Row()] = new ListNode(Fish(myFishCreated, pos), pos.Col(), ptr); } else { while(ptr->next != NULL && ptr->next->columnIndex < pos.Col()) ptr = ptr->next; ptr->next = new ListNode(Fish(myFishCreated, pos), pos.Col(), ptr->next); } myFishCount++; } // private helper functions bool Environment::InRange(const Position & pos) const // postcondition: returns true if pos is in the grid, // returns false otherwise { if (0 <= pos.Row() && pos.Row() < NumRows() && 0 <= pos.Col() && pos.Col() < NumCols()) { return true; } DebugPrint(5, pos.ToString() + " is out of range."); return false; } ListNode::ListNode() // sets the Fish to emptyFish, columnIndex to -1 { theFish = Fish(); columnIndex = -1; } ListNode::ListNode(const Fish f, int c, ListNode * link) // sets theFish to f, columnIndex to c, next to link { theFish = f; columnIndex = c; next = link; }