How to update values in C++ std::pair<int, int> - c++

I have this function that returns the location of a robot (which is just a [row][col] pair of indices from a matrix):
std::pair<int, int> World::getRobotLocation(char robot_name){
auto const & location = robots.find(robot_name);
if (location == robots.end()) {
std::cout << "Robot " << robot_name << " does not exist." << std::endl;
}
return location->second;
}
Below, I am trying to implement the move() function, which takes in the robot name, location and which direction to move and updates the position accordingly:
std::string move(char robot, char direction) {
// Get robot and its location
std::pair<int, int> robot_location = std::pair<int, int> World::getRobotLocation(robot);
// Get direction to move from user
// if L, map_[row+1][col]
// if D, map_[row][col+1]
// if R, map_[row-1][col]
// if U, map_[row][col+1]
// According to user input, update the robot's location
if (direction == 'L') {
robot_location = robot_location[+1][]
}
else if (direction == 'D') {
robot_location = robot_location[][-1]
}
else if (direction == 'R') {
robot_location = robot_location[-1][]
}
else {
robot_location = robot_location[][+1]
}
}
In my variable robot_location, I am saving the location of that particular robot. How can I access the values of this std::pair<int, int> to be able to update them?

Your first function has a bug. It reports when a robot is not found, but still dereferences the end iterator, which causes undefined behavior. Instead, you should return a pointer, which is conditionally null:
// Returns null if the robot is not found:
std::pair<int, int>*
World::getRobotLocation(char robot_name){
auto const location = robots.find(robot_name);
if (location == robots.end()) {
return nullptr;
}
return &location->second;
}
And in your other function, you check to see, if the pointer is not null, you update the value:
// Returns true if move happens,
// false otherwise.
bool
move(char robot, char direction) {
auto const robot_location = World::getRobotLocation(robot);
if (!robot_location) return false;
switch (direction) {
case 'L': {
++robot_location->first;
} break;
case 'D': {
--robot_location->second;
} break;
case 'R': {
--robot_location->first;
} break;
default: {
++robot_location->second;
} break;
}
return true;
}

I think you want something like this:
if (direction == 'L') {
robot_location.first += 1;
}
else if (direction == 'D') {
robot_location.second -= 1;
}
// ...etc (you get the idea)
first and second are the names of the two elements in a std::pair (that's also why the return value of robots.find(...) dereferences to something that has first and second - that's a std::pair of the key and value types of the map).
Bear in mind that getRobotLocation, as it's currently written, will return a copy of the std::pair of coordinates, not a reference to the original coordinates inside the map. Therefore, just updating that std::pair won't be enough on its own. You'll need to either save the value back into the robots map, or change what getRobotLocation returns (see #Goswin and #Ted's comments).

Related

Have issues determining if array is sorted

I trying to figure out if an array set is sorted or not using sentinal-terminated sequences.
In attempting I have tried to check if the array is ascending, descending, or not sorted.
#define isNaN(X) (X != X)
#define NaN std::numeric_limits<float>::quiet_NaN()
enum sortType { ASCENDING, DESCENDING, UNKNOWN, UNSORTED };
I think there is an error in my bool inSorted function and I believe the issue is with for checking the NaN value at the end.
bool isSorted(const float data[], const int currentDataItem, const sortType typeOfSort) {
switch(typeOfSort) {
case ASCENDING:
if(currentDataItem == 0){
return isSorted(data, (currentDataItem + 1), ASCENDING);
} else if(data[currentDataItem] > data[currentDataItem+1]){
return false;
} else if(data[currentDataItem] == data[currentDataItem]){
return isSorted(data, (currentDataItem+1), ASCENDING);
} else {
return true;
}
case DESCENDING:
if(currentDataItem == 0){
return isSorted(data, (currentDataItem + 1), DESCENDING);
} else if(data[currentDataItem] < data[currentDataItem+1]){
return false;
} else if(data[currentDataItem] == data[currentDataItem]){
return isSorted(data, (currentDataItem+1), DESCENDING);
} else {
return true;
}
}
}
The isSorted is then called by bool sorted
bool sorted(const float data[]) {
bool ascending = isSorted(data, 0, ASCENDING);
bool descending = isSorted(data, 0, DESCENDING);
if(!ascending && !descending){
return false;
}
return true;
}
Wrapped up by main
int main(const int argc, const char* const argv[]) {
float data[] = {1, 2, 4, 5, 6, NaN};
if (sorted(data))
cout << "Data is sorted" << endl;
else
cout << "Data is not sorted" << endl;
return 0;
}
When implementing a recursive function, you need to ask yourself the following questions explicitly:
What is the base case of your recursive function?
What is the recursive case of your recursive function?
Answers:
If the current array position compares against NaN, then we are sorted.
If our position is not sorted, we know the list isn't sorted. If our position is sorted, then the array is sorted if the recursive condition holds on the next pair.
Therefore:
case ASCENDING:
// Empty list
if (std::isnan(data[currentDataItem]))
return true;
// One element list.
else if (std::isnan(data[currentDataItem + 1])
return true;
// Recursive case: we've found a location where the data isn't sorted.
else if (data[currentDataItem] > data[currentDataItem + 1])
return false;
// This location is sorted, check the next location.
else
return isSorted(data, currentDataItem + 1, typeOfSort);
Note that I only directly return true; on the base cases. Otherwise, we either fail the function, or we recurse.

"List iterators incompatible" while running

void GameLogic::isHit(int mousePressX, int mousePressY)
{
for each(BallObject* ball in ballList) {
for (it = ballList.begin(); it != ballList.end();)
{
bool isHit = ball->EvaluateHit(mousePressX, mousePressY);
if (isHit == true)
{
mScore++;
ballList.remove(ball);
}
else
{
++it;
}
}
}
I am trying to remove ball from "ballList" while playing game via click on surface(ball should dissapear). Program is running correctly until click. When I click, it gives an error from the title. How does it right?
void GameLogic::isHit(int mousePressX, int mousePressY)
{
// iterate all the balls in the list...
for (it = ballList.begin(); it != ballList.end();)
{
bool isHit = (*it)->EvaluateHit(mousePressX, mousePressY);
if (isHit == true)
{
mScore++;
// This invalidates iterators, and is linear in complexity
// (it iterates the list too, but you're already doing that)
// ballList.remove(ball);
// erase the ball at this iteration, save off the result
// so you can continue iterating
it = ballList.erase(it);
}
else
{
// if the ball wasn't hit, increment the iterator normally
++it;
}
}
}

How to represent a mathematical domain in IR?

I would like to define an object representing a mathematical domain from a list of constraints, but I don't have a clear idea on how to do that.
For example, I start from IR and I have the following constraints :
x > 0
x is not in ]3,5]
x is not in [7,12[
Then, my domain is ]0,3] U ]5,7[ U [12,+oo .
How can I nicely store that in a C++ structure ? Have you ever did that before ? Moreover, I want to be able to check easilly if the domain is empty.
Unless you want to use "3rd party" tools like mentioned in the coments, you'll have to write your own Interval class.
To do this, you can do something like this:
class Interval{
struct Range{
bool leftInclusive, rightInclusive;
double left, right;
bool operator<(Range other){return left<other.left;}
}
std::Set<Range> trueRanges;
void addTrueRange(Range r){
//check for overlaps
//merge if overlapping
//otherwise add to trueRanges
}
bool trueAt(double at){
//find the range with the highest left-bound lower than at
auto candidate = truethRanges.upper_bound(at);
if(candidate == trueRanged.end()) return false; // no range found
//on-point checking here
if(at <= candidate->left) return false;
if(at >= candidate->right) return false;
return true;
}
}
The on-point checking is left out here because you cannot simply say doubleOne == doubleTwo because this mitght result in false negatives. So you have to say ABS(doubleOne-doubleTwo) < tinyValue.
For looking for overlaps you can have a look at this.
Answering my own question.
Actually, I followed the idea of sbabbi using a list of intervals coming from boost/numeric/interval, representing the union of intervals.
Here is an example :
typedef boost::numeric::interval_lib::rounded_math<double> RoundedPolicy;
typedef boost::numeric::interval_lib::checking_base<double> CheckingPolicy;
typedef boost::numeric::interval_lib::policies<RoundedPolicy,CheckingPolicy> IntervalPolicies;
typedef boost::numeric::interval<double,IntervalPolicies> interval;
//...
bool is_interval_empty(const interval& inter)
{
return boost::numeric::empty(inter);
}
void restrict(interval& domain, const interval& inter)
{
for(std::list<interval>::iterator it = domain.begin(); it != domain.end(); ++it)
*it = boost::numeric::intersect(*it, inter);
domain.remove_if(is_interval_empty);
}
void restrict(interval& domain, const interval& inter1, const interval& inter2)
{
for(std::list<interval>::iterator it = domain.begin(); it != domain.end(); ++it)
{
domain.push_front(boost::numeric::intersect(*it, inter1));
*it = boost::numeric::intersect(*it, inter2);
}
domain.remove_if(is_interval_empty);
}
//...
std::list<interval> domain;
for(unsigned long int i = 0; i < constraints.size(); ++i)
{
if(constraints[i].is_lower_bound())
{
interval restriction(constraints[i].get_lower_bound(), std::numeric_limits<double>::infinity());
restrict(domain, restriction);
}
else if(constraints[i].is_upper_bound())
{
interval restriction(-std::numeric_limits<double>::infinity(), constraints[i].get_upper_bound());
restrict(domain, restriction);
}
else if(constraints[i].is_forbidden_range())
{
interval restriction1(-std::numeric_limits<double>::infinity(), constraints[i].get_lower_bound());
interval restriction2(constraints[i].get_upper_bound(), std::numeric_limits<double>::infinity());
restrict(domain, restriction1, restriction2);
}
}
if(domain.size() == 0)
std::cout << "empty domain" << std::endl;
else
std::cout << "the domain exists" << std::endl;

How to change a value in an array C++

This function is for code to play a game of tic tac toe:
//--------------------FUNCTION--------------------
bool playCell(int player, int position, int gameBoard[]) {
if (gameBoard[position] == 10 || gameBoard[position] == 11) {
return false;
} else {
return true;
if (player == 0){
gameBoard[position] = 10;
} else {
gameBoard[position] = 11;
} // end if
}
} // end function
playCell takes a player (0 for "O", 1 for "X"), a position (1 to 9), and the nine element gameBoard, and returns true if the move is legal (i.e. that spot is not yet taken), and false otherwise. If the move is legal it changes the position to that players number (10 for "O", 11 for "X"). If the player or position input is invalid, it returns false.
I'm trying to figure out how to get the array to change its value to either a 10 or 11 depending on the player, and saving to the position they entered to play in.
The return keyword redirect the program flow back to the main program. So the code after return will not be executed. Change the position of return:
//--------------------FUNCTION--------------------
bool playCell(int player, int position, int gameBoard[])
{
if (gameBoard[position] == 10 || gameBoard[position] == 11)
{
return false;
}
else
{
if (player == 0)
{
gameBoard[position] = 10;
}
else
{
gameBoard[position] = 11;
} // end if
return true;
}
} // end function
You have a return statement prior to your array assignment here:
return true; // HERE
if (player == 0){
gameBoard[position] = 10;
} else {
gameBoard[position] = 11;
} // end if
this causes your code not to be executed. Remove this line from there and put in the correct place.

incompatible vector iterator

I'm getting a "incompatible vector iterator" error to what i believe is a invalid iterator
void Bomb::CreateExplosion(Game_Manager* EGame_Manager)
{
for(irr::f32 iteration = 0; iteration < BlastRadius; iteration++) //up direction blast
{
***//PROGRAM CRASHES AT THIS LINE-->*** for(EGame_Manager->getEntityManager()->GetEntityIterator() = EGame_Manager->getEntityManager()->GetEntityList().begin(); EGame_Manager->getEntityManager()->GetEntityIterator() != EGame_Manager->getEntityManager()->GetEntityList().end(); ++EGame_Manager->getEntityManager()->GetEntityIterator())
{
if(CheckForCollision(UpExplosion->getTransformedBoundingBox(), (*EGame_Manager->getEntityManager()->GetEntityIterator())->GetEntityNode()->getTransformedBoundingBox()) == true)//check for collision against the unbreakable blocks (entity.type equals 0)
{
if((*EGame_Manager->getEntityManager()->GetEntityIterator())->GetType() == unbreakableblock)
{
break;
}
else if((*EGame_Manager->getEntityManager()->GetEntityIterator())->GetType() == gameplayer)
{
(*EGame_Manager->getEntityManager()->GetEntityIterator())->SetLives(this->GetLives() -1);
break;
}
else if((*EGame_Manager->getEntityManager()->GetEntityIterator())->GetType() == gameitem)
{
break;
}
}
else
{
UpExplosion->setScale(irr::core::vector3df(1,1,iteration)); //standard width of UpExplosion, iterated height of the UpExplosion
}
}
}
CreateExplosion is called by Bomb::UpdateEntity() which is called by EntityManager::UpdateList() which then loops through the vector<*Entity> List calling each Entity's respective Update function.
This function adds the Entities to the vector I'm not sure if it causes the problem
EntityManager::AddEntity(Entity* addtoList)
{
List.push_back(addtolist);
addtolist->GetEntityNode()->setID(List.size());
EntityIterator = List.begin();
}
Also the instance of the Bomb class that calls these functions is declared in the Player class if that helps with anything. And I can post more code if needed.