A game called Bocce played on a Cartesian grid











up vote
3
down vote

favorite












You may know Bocce, so you should know that I've tweaked the rules a little. Three types of balls are thrown: a red type, a blue type, and single black ball called the jack.



These are all on the Cartesian coordinate system. The coordinates of the jack are given, and also distances of an equal amount of red and blue balls from the origins of the system (0, 0). If a ball's distance is larger than the distance of the jack, and if the distance of this ball is larger than the distance of its peer, it's a score. The team with the highest score wins.



Here's the code:



#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <cmath>
#include <array>
#include <algorithm>

typedef std::map<std::string, std::vector<int>> bocce_balls;
typedef std::vector<int> int_vec;
typedef std::array<int, 2> int_arr;

std::string bocce(bocce_balls balls, int_arr jack)
{
auto distance = std::sqrt(std::pow(jack[0], 2)+std::pow(jack[1], 2));
int red_count = 0;
int blue_count = 0;

int_vec red = balls["red"];
int_vec blue = balls["blue"];

if (blue.size() != red.size())
{
std::cerr << "Balls were different numbers!" << std::endl;
return "Fail!";
}

std::sort(blue.begin(), blue.end());
std::sort(red.begin(), red.end());

for (int i = 0; i < blue.size(); ++i)
{
if (red[i] > distance && red[i] > blue[i])
++red_count;
else if (blue[i] > distance && blue[i] > red[i])
++blue_count;
}


if (red_count > blue_count)
return "Red Wins!";
else if (blue_count > red_count)
return "Blue Wins!";
else
return "Draw!";

}



int main() {

bocce_balls insert;
insert["blue"] = {2, 9, 3, 4, 5, 1, 10, 2};
insert["red"] = {20, 11, 3, 4, 3, 1, 2, 3};
int_arr dist = {2, 2};

std::cout << bocce(insert, dist) << std::endl;
return 0;
}









share|improve this question









New contributor




ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 1




    Don't use std::pow for squaring, you can hardly be less efficient... Just multiply the value with itself instead.
    – Aconcagua
    2 days ago















up vote
3
down vote

favorite












You may know Bocce, so you should know that I've tweaked the rules a little. Three types of balls are thrown: a red type, a blue type, and single black ball called the jack.



These are all on the Cartesian coordinate system. The coordinates of the jack are given, and also distances of an equal amount of red and blue balls from the origins of the system (0, 0). If a ball's distance is larger than the distance of the jack, and if the distance of this ball is larger than the distance of its peer, it's a score. The team with the highest score wins.



Here's the code:



#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <cmath>
#include <array>
#include <algorithm>

typedef std::map<std::string, std::vector<int>> bocce_balls;
typedef std::vector<int> int_vec;
typedef std::array<int, 2> int_arr;

std::string bocce(bocce_balls balls, int_arr jack)
{
auto distance = std::sqrt(std::pow(jack[0], 2)+std::pow(jack[1], 2));
int red_count = 0;
int blue_count = 0;

int_vec red = balls["red"];
int_vec blue = balls["blue"];

if (blue.size() != red.size())
{
std::cerr << "Balls were different numbers!" << std::endl;
return "Fail!";
}

std::sort(blue.begin(), blue.end());
std::sort(red.begin(), red.end());

for (int i = 0; i < blue.size(); ++i)
{
if (red[i] > distance && red[i] > blue[i])
++red_count;
else if (blue[i] > distance && blue[i] > red[i])
++blue_count;
}


if (red_count > blue_count)
return "Red Wins!";
else if (blue_count > red_count)
return "Blue Wins!";
else
return "Draw!";

}



int main() {

bocce_balls insert;
insert["blue"] = {2, 9, 3, 4, 5, 1, 10, 2};
insert["red"] = {20, 11, 3, 4, 3, 1, 2, 3};
int_arr dist = {2, 2};

std::cout << bocce(insert, dist) << std::endl;
return 0;
}









share|improve this question









New contributor




ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
















  • 1




    Don't use std::pow for squaring, you can hardly be less efficient... Just multiply the value with itself instead.
    – Aconcagua
    2 days ago













up vote
3
down vote

favorite









up vote
3
down vote

favorite











You may know Bocce, so you should know that I've tweaked the rules a little. Three types of balls are thrown: a red type, a blue type, and single black ball called the jack.



These are all on the Cartesian coordinate system. The coordinates of the jack are given, and also distances of an equal amount of red and blue balls from the origins of the system (0, 0). If a ball's distance is larger than the distance of the jack, and if the distance of this ball is larger than the distance of its peer, it's a score. The team with the highest score wins.



Here's the code:



#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <cmath>
#include <array>
#include <algorithm>

typedef std::map<std::string, std::vector<int>> bocce_balls;
typedef std::vector<int> int_vec;
typedef std::array<int, 2> int_arr;

std::string bocce(bocce_balls balls, int_arr jack)
{
auto distance = std::sqrt(std::pow(jack[0], 2)+std::pow(jack[1], 2));
int red_count = 0;
int blue_count = 0;

int_vec red = balls["red"];
int_vec blue = balls["blue"];

if (blue.size() != red.size())
{
std::cerr << "Balls were different numbers!" << std::endl;
return "Fail!";
}

std::sort(blue.begin(), blue.end());
std::sort(red.begin(), red.end());

for (int i = 0; i < blue.size(); ++i)
{
if (red[i] > distance && red[i] > blue[i])
++red_count;
else if (blue[i] > distance && blue[i] > red[i])
++blue_count;
}


if (red_count > blue_count)
return "Red Wins!";
else if (blue_count > red_count)
return "Blue Wins!";
else
return "Draw!";

}



int main() {

bocce_balls insert;
insert["blue"] = {2, 9, 3, 4, 5, 1, 10, 2};
insert["red"] = {20, 11, 3, 4, 3, 1, 2, 3};
int_arr dist = {2, 2};

std::cout << bocce(insert, dist) << std::endl;
return 0;
}









share|improve this question









New contributor




ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











You may know Bocce, so you should know that I've tweaked the rules a little. Three types of balls are thrown: a red type, a blue type, and single black ball called the jack.



These are all on the Cartesian coordinate system. The coordinates of the jack are given, and also distances of an equal amount of red and blue balls from the origins of the system (0, 0). If a ball's distance is larger than the distance of the jack, and if the distance of this ball is larger than the distance of its peer, it's a score. The team with the highest score wins.



Here's the code:



#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <cmath>
#include <array>
#include <algorithm>

typedef std::map<std::string, std::vector<int>> bocce_balls;
typedef std::vector<int> int_vec;
typedef std::array<int, 2> int_arr;

std::string bocce(bocce_balls balls, int_arr jack)
{
auto distance = std::sqrt(std::pow(jack[0], 2)+std::pow(jack[1], 2));
int red_count = 0;
int blue_count = 0;

int_vec red = balls["red"];
int_vec blue = balls["blue"];

if (blue.size() != red.size())
{
std::cerr << "Balls were different numbers!" << std::endl;
return "Fail!";
}

std::sort(blue.begin(), blue.end());
std::sort(red.begin(), red.end());

for (int i = 0; i < blue.size(); ++i)
{
if (red[i] > distance && red[i] > blue[i])
++red_count;
else if (blue[i] > distance && blue[i] > red[i])
++blue_count;
}


if (red_count > blue_count)
return "Red Wins!";
else if (blue_count > red_count)
return "Blue Wins!";
else
return "Draw!";

}



int main() {

bocce_balls insert;
insert["blue"] = {2, 9, 3, 4, 5, 1, 10, 2};
insert["red"] = {20, 11, 3, 4, 3, 1, 2, 3};
int_arr dist = {2, 2};

std::cout << bocce(insert, dist) << std::endl;
return 0;
}






c++ c++14






share|improve this question









New contributor




ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 2 days ago









Josay

24.3k13782




24.3k13782






New contributor




ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 2 days ago









ChubakBidpaa

11716




11716




New contributor




ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








  • 1




    Don't use std::pow for squaring, you can hardly be less efficient... Just multiply the value with itself instead.
    – Aconcagua
    2 days ago














  • 1




    Don't use std::pow for squaring, you can hardly be less efficient... Just multiply the value with itself instead.
    – Aconcagua
    2 days ago








1




1




Don't use std::pow for squaring, you can hardly be less efficient... Just multiply the value with itself instead.
– Aconcagua
2 days ago




Don't use std::pow for squaring, you can hardly be less efficient... Just multiply the value with itself instead.
– Aconcagua
2 days ago










2 Answers
2






active

oldest

votes

















up vote
4
down vote













Bocce, as far as I know it, counts all the balls of one player that are closer to the jack than the closest one of his opponent.



That would mean that the distances from origin are irrelevant, instead, you need the distances from the balls to the jack:



auto dx = ball.x - jack.x;
auto dy = ball.y - jack.y;
auto distance2 = dx*dx + dy*dy;


Note that I avoided std::pow in favour to multiplying with itself, as std::pow inefficient for this purpose.



Note, too, that as the root function is strictly monotonely rising, you don't need to calculate it, but you can compare the squares as well and still will get the same results.



I personally strongly recommend that you create a class Ball containing three members: x, y for the coordinates and distance for the distance to jack:



class Ball
{
int x, y;
int distanceToJack2;
};


I'm not too happy with int as data type - it depends on the range of valid coordinates, though, if it is suitable or not. Assuming we have 32-bit int, then if the valid ranges for x and y can be covered with 16 bit, you will be safe from overflow while multiplying (this would yield undefined behaviour!), otherwise you'd need to calculate in next larger data type. For selecting the correct data types more safely, you might prefer the data types from <cstdint> header, e. g.:



 int32_t x, y;
int64_t distanceToJack2;


Or you simply have coordinates and distance in double right away. Be aware that with double, you can quickly get issues due to rounding, so if you compare for one value being less than the other, you should consider them only so if difference is larger than some yet to be defined epsilon value (minimum distance for two values for not considering them equal). You could get some hints to from this question. Sure, it is java, but as long as both C++ and Java follow IEEE 754 for floating point values, it applies for both languages equally. On the other hand, you could then use std::hypot for calculating the distances in a very safe manner (thanks Toby for the hint).



Then you might add:



 void Ball::calculateDistance(Ball const& jack)
{
uint64_t dx = static_cast<uint64_t>(x) - jack.x;
uint64_t dy = static_cast<uint64_t>(y) - jack.y;
distanceToJack2 = dx*dx + dy*dy;
}


Finally, you can sort your balls according to the distances to jack and select all balls from one vector of which the distance is smaller than the distance of the first element in the respective other vector.



One last point: std::string is a rather bad key type for the map if you only have two fix values (beware of typos, additionally, map mangement is rather expensive). You might prefer an enum instead: enum class Color { RED, BLUE }; and use this one as key instead. Even better: don't use a map at all, instead:



std::string bocce(std::vector<Ball>& red, std::vector<Ball>& blue, Ball const& jack);


Note that as you need to calculate the distances, which are stored in the balls, you cannot have const references for the two vectors (which otherwise would have been preferrable). From point of view of design, this is at least questionable (but at least, it's quite some improvement already). Ideally, the design would allow to pass in const vectors, but that would require some overhead, so for pragmatism, we might decide to live with the current design...






share|improve this answer










New contributor




Aconcagua is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.


















  • All these help me learn C++ better. Thanks.
    – ChubakBidpaa
    2 days ago


















up vote
4
down vote













typedef std::map<std::string, std::vector<int>> bocce_balls;


Are you interested in the ordering of the container? There really is no need to use std::set to wrap the ball distances for each player. std::unordered_map would be faster (consumes more space!), but do you even need a map-type? Have you considered using an array of vectors to represent the distances for each player? Do you need to wrap the distances or can you just pass each player as arguments?



Should the key be a string or an enumeration? Strings are great when you need to make keys on the fly at run-time. At compile-time, spelling errors with strings will result in new entries being created in mutable maps. With strongly typed enumerations, the possible range of keys is predefined.



Should distances be stored as integers or as a floating-point type?





std::string bocce(bocce_balls balls, int_arr jack)


Pick descriptive names that help readers understand what your function is supposed to do. bocce is the name of the game. What does this function do? Calculates the winner for a game of bocce. Cartesian point makes it clear what the type of jack should be. Balls is holding the results for one frame in a game of bocce.





    auto distance = std::sqrt(std::pow(jack[0], 2)+std::pow(jack[1], 2));


Use const to define objects with values that do not change after construction. const is useful for providing an immutable view of mutable data. This allows you to clarify to readers that the variable will not be modified and it prevents surprises when someone unexpectedly changes the objects value.



Also, distance from an origin exists in <cmath>. See std::hypot.





    int_vec red = balls["red"];
int_vec blue = balls["blue"];


Key-access through a map returns a reference to the mapped value. Here, you've opted into making a copy of the mapped value. If you look back at your function signature, bocce_balls is passed by value. Another copy. I'd advise that you pass the parameter by reference-to-const as to prevent accidental modifications to the map. Keep the copies of red and blue here as you'll need those copies for the sort.





    for (int i = 0; i < blue.size(); ++i) {
if (red[i] > distance && red[i] > blue[i])
++red_count;
else if (blue[i] > distance && blue[i] > red[i])
++blue_count;
}


i is a signed integer. blue.size() returns an unsigned integer. Each loops does a signed/unsigned comparison. Every time you index with i, the subscript operator is expecting an unsigned integer which leads to implicit conversions that change signedness. Turn up your warning levels.






share|improve this answer























  • Although it is against the rules to thank people, I shall thank you for taking your time to correct my code. So thanks.
    – ChubakBidpaa
    2 days ago











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});






ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.










 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207781%2fa-game-called-bocce-played-on-a-cartesian-grid%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
4
down vote













Bocce, as far as I know it, counts all the balls of one player that are closer to the jack than the closest one of his opponent.



That would mean that the distances from origin are irrelevant, instead, you need the distances from the balls to the jack:



auto dx = ball.x - jack.x;
auto dy = ball.y - jack.y;
auto distance2 = dx*dx + dy*dy;


Note that I avoided std::pow in favour to multiplying with itself, as std::pow inefficient for this purpose.



Note, too, that as the root function is strictly monotonely rising, you don't need to calculate it, but you can compare the squares as well and still will get the same results.



I personally strongly recommend that you create a class Ball containing three members: x, y for the coordinates and distance for the distance to jack:



class Ball
{
int x, y;
int distanceToJack2;
};


I'm not too happy with int as data type - it depends on the range of valid coordinates, though, if it is suitable or not. Assuming we have 32-bit int, then if the valid ranges for x and y can be covered with 16 bit, you will be safe from overflow while multiplying (this would yield undefined behaviour!), otherwise you'd need to calculate in next larger data type. For selecting the correct data types more safely, you might prefer the data types from <cstdint> header, e. g.:



 int32_t x, y;
int64_t distanceToJack2;


Or you simply have coordinates and distance in double right away. Be aware that with double, you can quickly get issues due to rounding, so if you compare for one value being less than the other, you should consider them only so if difference is larger than some yet to be defined epsilon value (minimum distance for two values for not considering them equal). You could get some hints to from this question. Sure, it is java, but as long as both C++ and Java follow IEEE 754 for floating point values, it applies for both languages equally. On the other hand, you could then use std::hypot for calculating the distances in a very safe manner (thanks Toby for the hint).



Then you might add:



 void Ball::calculateDistance(Ball const& jack)
{
uint64_t dx = static_cast<uint64_t>(x) - jack.x;
uint64_t dy = static_cast<uint64_t>(y) - jack.y;
distanceToJack2 = dx*dx + dy*dy;
}


Finally, you can sort your balls according to the distances to jack and select all balls from one vector of which the distance is smaller than the distance of the first element in the respective other vector.



One last point: std::string is a rather bad key type for the map if you only have two fix values (beware of typos, additionally, map mangement is rather expensive). You might prefer an enum instead: enum class Color { RED, BLUE }; and use this one as key instead. Even better: don't use a map at all, instead:



std::string bocce(std::vector<Ball>& red, std::vector<Ball>& blue, Ball const& jack);


Note that as you need to calculate the distances, which are stored in the balls, you cannot have const references for the two vectors (which otherwise would have been preferrable). From point of view of design, this is at least questionable (but at least, it's quite some improvement already). Ideally, the design would allow to pass in const vectors, but that would require some overhead, so for pragmatism, we might decide to live with the current design...






share|improve this answer










New contributor




Aconcagua is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.


















  • All these help me learn C++ better. Thanks.
    – ChubakBidpaa
    2 days ago















up vote
4
down vote













Bocce, as far as I know it, counts all the balls of one player that are closer to the jack than the closest one of his opponent.



That would mean that the distances from origin are irrelevant, instead, you need the distances from the balls to the jack:



auto dx = ball.x - jack.x;
auto dy = ball.y - jack.y;
auto distance2 = dx*dx + dy*dy;


Note that I avoided std::pow in favour to multiplying with itself, as std::pow inefficient for this purpose.



Note, too, that as the root function is strictly monotonely rising, you don't need to calculate it, but you can compare the squares as well and still will get the same results.



I personally strongly recommend that you create a class Ball containing three members: x, y for the coordinates and distance for the distance to jack:



class Ball
{
int x, y;
int distanceToJack2;
};


I'm not too happy with int as data type - it depends on the range of valid coordinates, though, if it is suitable or not. Assuming we have 32-bit int, then if the valid ranges for x and y can be covered with 16 bit, you will be safe from overflow while multiplying (this would yield undefined behaviour!), otherwise you'd need to calculate in next larger data type. For selecting the correct data types more safely, you might prefer the data types from <cstdint> header, e. g.:



 int32_t x, y;
int64_t distanceToJack2;


Or you simply have coordinates and distance in double right away. Be aware that with double, you can quickly get issues due to rounding, so if you compare for one value being less than the other, you should consider them only so if difference is larger than some yet to be defined epsilon value (minimum distance for two values for not considering them equal). You could get some hints to from this question. Sure, it is java, but as long as both C++ and Java follow IEEE 754 for floating point values, it applies for both languages equally. On the other hand, you could then use std::hypot for calculating the distances in a very safe manner (thanks Toby for the hint).



Then you might add:



 void Ball::calculateDistance(Ball const& jack)
{
uint64_t dx = static_cast<uint64_t>(x) - jack.x;
uint64_t dy = static_cast<uint64_t>(y) - jack.y;
distanceToJack2 = dx*dx + dy*dy;
}


Finally, you can sort your balls according to the distances to jack and select all balls from one vector of which the distance is smaller than the distance of the first element in the respective other vector.



One last point: std::string is a rather bad key type for the map if you only have two fix values (beware of typos, additionally, map mangement is rather expensive). You might prefer an enum instead: enum class Color { RED, BLUE }; and use this one as key instead. Even better: don't use a map at all, instead:



std::string bocce(std::vector<Ball>& red, std::vector<Ball>& blue, Ball const& jack);


Note that as you need to calculate the distances, which are stored in the balls, you cannot have const references for the two vectors (which otherwise would have been preferrable). From point of view of design, this is at least questionable (but at least, it's quite some improvement already). Ideally, the design would allow to pass in const vectors, but that would require some overhead, so for pragmatism, we might decide to live with the current design...






share|improve this answer










New contributor




Aconcagua is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.


















  • All these help me learn C++ better. Thanks.
    – ChubakBidpaa
    2 days ago













up vote
4
down vote










up vote
4
down vote









Bocce, as far as I know it, counts all the balls of one player that are closer to the jack than the closest one of his opponent.



That would mean that the distances from origin are irrelevant, instead, you need the distances from the balls to the jack:



auto dx = ball.x - jack.x;
auto dy = ball.y - jack.y;
auto distance2 = dx*dx + dy*dy;


Note that I avoided std::pow in favour to multiplying with itself, as std::pow inefficient for this purpose.



Note, too, that as the root function is strictly monotonely rising, you don't need to calculate it, but you can compare the squares as well and still will get the same results.



I personally strongly recommend that you create a class Ball containing three members: x, y for the coordinates and distance for the distance to jack:



class Ball
{
int x, y;
int distanceToJack2;
};


I'm not too happy with int as data type - it depends on the range of valid coordinates, though, if it is suitable or not. Assuming we have 32-bit int, then if the valid ranges for x and y can be covered with 16 bit, you will be safe from overflow while multiplying (this would yield undefined behaviour!), otherwise you'd need to calculate in next larger data type. For selecting the correct data types more safely, you might prefer the data types from <cstdint> header, e. g.:



 int32_t x, y;
int64_t distanceToJack2;


Or you simply have coordinates and distance in double right away. Be aware that with double, you can quickly get issues due to rounding, so if you compare for one value being less than the other, you should consider them only so if difference is larger than some yet to be defined epsilon value (minimum distance for two values for not considering them equal). You could get some hints to from this question. Sure, it is java, but as long as both C++ and Java follow IEEE 754 for floating point values, it applies for both languages equally. On the other hand, you could then use std::hypot for calculating the distances in a very safe manner (thanks Toby for the hint).



Then you might add:



 void Ball::calculateDistance(Ball const& jack)
{
uint64_t dx = static_cast<uint64_t>(x) - jack.x;
uint64_t dy = static_cast<uint64_t>(y) - jack.y;
distanceToJack2 = dx*dx + dy*dy;
}


Finally, you can sort your balls according to the distances to jack and select all balls from one vector of which the distance is smaller than the distance of the first element in the respective other vector.



One last point: std::string is a rather bad key type for the map if you only have two fix values (beware of typos, additionally, map mangement is rather expensive). You might prefer an enum instead: enum class Color { RED, BLUE }; and use this one as key instead. Even better: don't use a map at all, instead:



std::string bocce(std::vector<Ball>& red, std::vector<Ball>& blue, Ball const& jack);


Note that as you need to calculate the distances, which are stored in the balls, you cannot have const references for the two vectors (which otherwise would have been preferrable). From point of view of design, this is at least questionable (but at least, it's quite some improvement already). Ideally, the design would allow to pass in const vectors, but that would require some overhead, so for pragmatism, we might decide to live with the current design...






share|improve this answer










New contributor




Aconcagua is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









Bocce, as far as I know it, counts all the balls of one player that are closer to the jack than the closest one of his opponent.



That would mean that the distances from origin are irrelevant, instead, you need the distances from the balls to the jack:



auto dx = ball.x - jack.x;
auto dy = ball.y - jack.y;
auto distance2 = dx*dx + dy*dy;


Note that I avoided std::pow in favour to multiplying with itself, as std::pow inefficient for this purpose.



Note, too, that as the root function is strictly monotonely rising, you don't need to calculate it, but you can compare the squares as well and still will get the same results.



I personally strongly recommend that you create a class Ball containing three members: x, y for the coordinates and distance for the distance to jack:



class Ball
{
int x, y;
int distanceToJack2;
};


I'm not too happy with int as data type - it depends on the range of valid coordinates, though, if it is suitable or not. Assuming we have 32-bit int, then if the valid ranges for x and y can be covered with 16 bit, you will be safe from overflow while multiplying (this would yield undefined behaviour!), otherwise you'd need to calculate in next larger data type. For selecting the correct data types more safely, you might prefer the data types from <cstdint> header, e. g.:



 int32_t x, y;
int64_t distanceToJack2;


Or you simply have coordinates and distance in double right away. Be aware that with double, you can quickly get issues due to rounding, so if you compare for one value being less than the other, you should consider them only so if difference is larger than some yet to be defined epsilon value (minimum distance for two values for not considering them equal). You could get some hints to from this question. Sure, it is java, but as long as both C++ and Java follow IEEE 754 for floating point values, it applies for both languages equally. On the other hand, you could then use std::hypot for calculating the distances in a very safe manner (thanks Toby for the hint).



Then you might add:



 void Ball::calculateDistance(Ball const& jack)
{
uint64_t dx = static_cast<uint64_t>(x) - jack.x;
uint64_t dy = static_cast<uint64_t>(y) - jack.y;
distanceToJack2 = dx*dx + dy*dy;
}


Finally, you can sort your balls according to the distances to jack and select all balls from one vector of which the distance is smaller than the distance of the first element in the respective other vector.



One last point: std::string is a rather bad key type for the map if you only have two fix values (beware of typos, additionally, map mangement is rather expensive). You might prefer an enum instead: enum class Color { RED, BLUE }; and use this one as key instead. Even better: don't use a map at all, instead:



std::string bocce(std::vector<Ball>& red, std::vector<Ball>& blue, Ball const& jack);


Note that as you need to calculate the distances, which are stored in the balls, you cannot have const references for the two vectors (which otherwise would have been preferrable). From point of view of design, this is at least questionable (but at least, it's quite some improvement already). Ideally, the design would allow to pass in const vectors, but that would require some overhead, so for pragmatism, we might decide to live with the current design...







share|improve this answer










New contributor




Aconcagua is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this answer



share|improve this answer








edited 2 days ago





















New contributor




Aconcagua is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









answered 2 days ago









Aconcagua

2265




2265




New contributor




Aconcagua is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Aconcagua is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Aconcagua is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












  • All these help me learn C++ better. Thanks.
    – ChubakBidpaa
    2 days ago


















  • All these help me learn C++ better. Thanks.
    – ChubakBidpaa
    2 days ago
















All these help me learn C++ better. Thanks.
– ChubakBidpaa
2 days ago




All these help me learn C++ better. Thanks.
– ChubakBidpaa
2 days ago












up vote
4
down vote













typedef std::map<std::string, std::vector<int>> bocce_balls;


Are you interested in the ordering of the container? There really is no need to use std::set to wrap the ball distances for each player. std::unordered_map would be faster (consumes more space!), but do you even need a map-type? Have you considered using an array of vectors to represent the distances for each player? Do you need to wrap the distances or can you just pass each player as arguments?



Should the key be a string or an enumeration? Strings are great when you need to make keys on the fly at run-time. At compile-time, spelling errors with strings will result in new entries being created in mutable maps. With strongly typed enumerations, the possible range of keys is predefined.



Should distances be stored as integers or as a floating-point type?





std::string bocce(bocce_balls balls, int_arr jack)


Pick descriptive names that help readers understand what your function is supposed to do. bocce is the name of the game. What does this function do? Calculates the winner for a game of bocce. Cartesian point makes it clear what the type of jack should be. Balls is holding the results for one frame in a game of bocce.





    auto distance = std::sqrt(std::pow(jack[0], 2)+std::pow(jack[1], 2));


Use const to define objects with values that do not change after construction. const is useful for providing an immutable view of mutable data. This allows you to clarify to readers that the variable will not be modified and it prevents surprises when someone unexpectedly changes the objects value.



Also, distance from an origin exists in <cmath>. See std::hypot.





    int_vec red = balls["red"];
int_vec blue = balls["blue"];


Key-access through a map returns a reference to the mapped value. Here, you've opted into making a copy of the mapped value. If you look back at your function signature, bocce_balls is passed by value. Another copy. I'd advise that you pass the parameter by reference-to-const as to prevent accidental modifications to the map. Keep the copies of red and blue here as you'll need those copies for the sort.





    for (int i = 0; i < blue.size(); ++i) {
if (red[i] > distance && red[i] > blue[i])
++red_count;
else if (blue[i] > distance && blue[i] > red[i])
++blue_count;
}


i is a signed integer. blue.size() returns an unsigned integer. Each loops does a signed/unsigned comparison. Every time you index with i, the subscript operator is expecting an unsigned integer which leads to implicit conversions that change signedness. Turn up your warning levels.






share|improve this answer























  • Although it is against the rules to thank people, I shall thank you for taking your time to correct my code. So thanks.
    – ChubakBidpaa
    2 days ago















up vote
4
down vote













typedef std::map<std::string, std::vector<int>> bocce_balls;


Are you interested in the ordering of the container? There really is no need to use std::set to wrap the ball distances for each player. std::unordered_map would be faster (consumes more space!), but do you even need a map-type? Have you considered using an array of vectors to represent the distances for each player? Do you need to wrap the distances or can you just pass each player as arguments?



Should the key be a string or an enumeration? Strings are great when you need to make keys on the fly at run-time. At compile-time, spelling errors with strings will result in new entries being created in mutable maps. With strongly typed enumerations, the possible range of keys is predefined.



Should distances be stored as integers or as a floating-point type?





std::string bocce(bocce_balls balls, int_arr jack)


Pick descriptive names that help readers understand what your function is supposed to do. bocce is the name of the game. What does this function do? Calculates the winner for a game of bocce. Cartesian point makes it clear what the type of jack should be. Balls is holding the results for one frame in a game of bocce.





    auto distance = std::sqrt(std::pow(jack[0], 2)+std::pow(jack[1], 2));


Use const to define objects with values that do not change after construction. const is useful for providing an immutable view of mutable data. This allows you to clarify to readers that the variable will not be modified and it prevents surprises when someone unexpectedly changes the objects value.



Also, distance from an origin exists in <cmath>. See std::hypot.





    int_vec red = balls["red"];
int_vec blue = balls["blue"];


Key-access through a map returns a reference to the mapped value. Here, you've opted into making a copy of the mapped value. If you look back at your function signature, bocce_balls is passed by value. Another copy. I'd advise that you pass the parameter by reference-to-const as to prevent accidental modifications to the map. Keep the copies of red and blue here as you'll need those copies for the sort.





    for (int i = 0; i < blue.size(); ++i) {
if (red[i] > distance && red[i] > blue[i])
++red_count;
else if (blue[i] > distance && blue[i] > red[i])
++blue_count;
}


i is a signed integer. blue.size() returns an unsigned integer. Each loops does a signed/unsigned comparison. Every time you index with i, the subscript operator is expecting an unsigned integer which leads to implicit conversions that change signedness. Turn up your warning levels.






share|improve this answer























  • Although it is against the rules to thank people, I shall thank you for taking your time to correct my code. So thanks.
    – ChubakBidpaa
    2 days ago













up vote
4
down vote










up vote
4
down vote









typedef std::map<std::string, std::vector<int>> bocce_balls;


Are you interested in the ordering of the container? There really is no need to use std::set to wrap the ball distances for each player. std::unordered_map would be faster (consumes more space!), but do you even need a map-type? Have you considered using an array of vectors to represent the distances for each player? Do you need to wrap the distances or can you just pass each player as arguments?



Should the key be a string or an enumeration? Strings are great when you need to make keys on the fly at run-time. At compile-time, spelling errors with strings will result in new entries being created in mutable maps. With strongly typed enumerations, the possible range of keys is predefined.



Should distances be stored as integers or as a floating-point type?





std::string bocce(bocce_balls balls, int_arr jack)


Pick descriptive names that help readers understand what your function is supposed to do. bocce is the name of the game. What does this function do? Calculates the winner for a game of bocce. Cartesian point makes it clear what the type of jack should be. Balls is holding the results for one frame in a game of bocce.





    auto distance = std::sqrt(std::pow(jack[0], 2)+std::pow(jack[1], 2));


Use const to define objects with values that do not change after construction. const is useful for providing an immutable view of mutable data. This allows you to clarify to readers that the variable will not be modified and it prevents surprises when someone unexpectedly changes the objects value.



Also, distance from an origin exists in <cmath>. See std::hypot.





    int_vec red = balls["red"];
int_vec blue = balls["blue"];


Key-access through a map returns a reference to the mapped value. Here, you've opted into making a copy of the mapped value. If you look back at your function signature, bocce_balls is passed by value. Another copy. I'd advise that you pass the parameter by reference-to-const as to prevent accidental modifications to the map. Keep the copies of red and blue here as you'll need those copies for the sort.





    for (int i = 0; i < blue.size(); ++i) {
if (red[i] > distance && red[i] > blue[i])
++red_count;
else if (blue[i] > distance && blue[i] > red[i])
++blue_count;
}


i is a signed integer. blue.size() returns an unsigned integer. Each loops does a signed/unsigned comparison. Every time you index with i, the subscript operator is expecting an unsigned integer which leads to implicit conversions that change signedness. Turn up your warning levels.






share|improve this answer














typedef std::map<std::string, std::vector<int>> bocce_balls;


Are you interested in the ordering of the container? There really is no need to use std::set to wrap the ball distances for each player. std::unordered_map would be faster (consumes more space!), but do you even need a map-type? Have you considered using an array of vectors to represent the distances for each player? Do you need to wrap the distances or can you just pass each player as arguments?



Should the key be a string or an enumeration? Strings are great when you need to make keys on the fly at run-time. At compile-time, spelling errors with strings will result in new entries being created in mutable maps. With strongly typed enumerations, the possible range of keys is predefined.



Should distances be stored as integers or as a floating-point type?





std::string bocce(bocce_balls balls, int_arr jack)


Pick descriptive names that help readers understand what your function is supposed to do. bocce is the name of the game. What does this function do? Calculates the winner for a game of bocce. Cartesian point makes it clear what the type of jack should be. Balls is holding the results for one frame in a game of bocce.





    auto distance = std::sqrt(std::pow(jack[0], 2)+std::pow(jack[1], 2));


Use const to define objects with values that do not change after construction. const is useful for providing an immutable view of mutable data. This allows you to clarify to readers that the variable will not be modified and it prevents surprises when someone unexpectedly changes the objects value.



Also, distance from an origin exists in <cmath>. See std::hypot.





    int_vec red = balls["red"];
int_vec blue = balls["blue"];


Key-access through a map returns a reference to the mapped value. Here, you've opted into making a copy of the mapped value. If you look back at your function signature, bocce_balls is passed by value. Another copy. I'd advise that you pass the parameter by reference-to-const as to prevent accidental modifications to the map. Keep the copies of red and blue here as you'll need those copies for the sort.





    for (int i = 0; i < blue.size(); ++i) {
if (red[i] > distance && red[i] > blue[i])
++red_count;
else if (blue[i] > distance && blue[i] > red[i])
++blue_count;
}


i is a signed integer. blue.size() returns an unsigned integer. Each loops does a signed/unsigned comparison. Every time you index with i, the subscript operator is expecting an unsigned integer which leads to implicit conversions that change signedness. Turn up your warning levels.







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 days ago

























answered 2 days ago









Snowhawk

5,06911028




5,06911028












  • Although it is against the rules to thank people, I shall thank you for taking your time to correct my code. So thanks.
    – ChubakBidpaa
    2 days ago


















  • Although it is against the rules to thank people, I shall thank you for taking your time to correct my code. So thanks.
    – ChubakBidpaa
    2 days ago
















Although it is against the rules to thank people, I shall thank you for taking your time to correct my code. So thanks.
– ChubakBidpaa
2 days ago




Although it is against the rules to thank people, I shall thank you for taking your time to correct my code. So thanks.
– ChubakBidpaa
2 days ago










ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.










 

draft saved


draft discarded


















ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.













ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.












ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.















 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207781%2fa-game-called-bocce-played-on-a-cartesian-grid%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Costa Masnaga

Fotorealismo

Sidney Franklin