I am writing a program that generates any size maze you want. It does this by first creating every cell in the maze and assuming they are entirely walled in. They are each declared as their own set. Then a random cell is selected and then a random direction to break down a wall. The random direction funcion makes sure that its also a valid direction for that cell. The program makes sure that the two cells its looking to join arent already connected somehow and if they arent it breaks the wall. If they are already connected either directly or indirectly then it selects a new random cell and direction. This continues until the number of sets left is just 1 ensuring that you can get from any point in the maze to any other point. The program works but it is painfully slow. I dont think it should be as slow as it is and I am unsure why.
I can imagine a scenario where all the cells are connected but one. Thus it would take a little while to randomly select that one cell and that could slow things down but I would imagine when you are dealing with under 100,000 cells it still shouldn't take as long as it does. Rand should be prettu fast at spitting out numbers.
Ive attatched my code below. Its fairly simple but I am sorry about the lack of notes.
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;
class dset {
struct element {
element() { rank=0, parent=-1; }
int rank;
int parent;
vector<int> connections;
};
public:
dset(int nr=0,int nc=0);
int size() {return Nsets; }
int merge (int, int);
int find(int);
// Functions
bool isin(int i, vector<int> test);
int randdir(int i);
int randcell();
int dir(int, int);
void print();
vector<int> possibledir(int cell);
vector<int> walls(int cell, vector<int> possible);
private:
int Nsets;
int nrows, ncols;
vector<element> S;
};
int main(int argc, char* argv[]){
int nrows, ncols, cell, direction;
if (argc != 3){
cout << "Usage: nrows ncols\n";
}
stringstream convert;
convert << argv[1];
convert << " ";
convert << argv[2];
convert >> ncols;
convert >> nrows;
dset maze(nrows,ncols);
srand(time(NULL));
while(maze.size() != 1){
cell = maze.randcell();
// cell = 11;
direction = maze.randdir(cell);
// direction = 0;
// cout << "cell: " << cell << " direction: " << direction << " new cell: " << maze.dir(cell, direction) <<endl << endl;
// cout << maze.size() << endl<<endl;;
maze.merge(cell, maze.dir(cell, direction));
}
maze.print();
}
dset::dset(int nr,int nc) {
nrows = nr;
ncols = nc;
int N = (nrows * ncols);
if (0<N) S.insert(S.end(), N, element());
Nsets = N;
}
void dset::print(){
vector<int> wall;
cout << "MAZE " << nrows << " " << ncols << endl;
for ( int i = 0; i < (nrows*ncols); i++ ){
wall = walls(i,possibledir(i));
for( int j = 0; j < wall.size(); j++){
if (i < wall[j])
cout << i << " " << wall[j] << endl;
}
}
}
int dset::randcell(){
return (rand()%(nrows*ncols));
}
int dset::dir(int cell, int direction){
if(direction == 0)
return (cell - 1);
if(direction == 1)
return (cell - (ncols));
if(direction == 2)
return (cell+1);
if(direction == 3)
return (cell + ncols);
}
int dset::randdir(int i){
srand(time(NULL));
int direction;
vector<int> used;
//cout << "i : " << i << endl;
while (true){
direction = rand() % 4;
while (true){
if(isin(direction,used))
direction = rand()%4;
else
break;
}
// cout << "rand: " << direction << endl;
if(direction ==0){
if( i != 0){
// cout << 0 << " i%(ncols -1) :" << (i%(ncols -1)) << endl;
if(i%(ncols) != 0){
break;
}
}
}
if(direction == 1){
// cout << 1 << " i - ncols :" << (i-ncols) << endl;
if(i-ncols > 0){
break;
}
}
if (direction == 2){
// cout << 2 << " i%(ncols) :" << (i%ncols) << endl;
if ( i == 0 )
break;
if (i%ncols != ncols-1){
break;
}
}
if (direction == 3){
if (i+ncols < ((nrows*ncols))){
// cout << 3 << " i+ncols :" << (i+ncols) << endl;
break;
}
}
used.push_back(direction);
}
return direction;
}
vector<int> dset::possibledir(int cell){
vector<int> possible;
// cout << "cell " << cell << " possible connections:\n";
for (int i = 0; i < 4; i++){
if (i == 0){
if( cell != 0 ){
if(cell%(ncols) !=0){
// cout << dir(cell,i) <<endl;
possible.push_back(dir(cell,i));
}
}
}
if(i==1){
if (cell-ncols > 0){
// cout<<dir(cell,i) <<endl;
possible.push_back(dir(cell,i));
}
}
if(i==2){
if(cell == 0){
// cout<<dir(cell,i) <<endl;
possible.push_back(1);
}else if(cell%ncols != ncols-1){
// cout<<dir(cell,i) <<endl;
possible.push_back(dir(cell,i));
}
}
if(i==3){
if ( cell+ncols < ((nrows*ncols))){
// cout<<dir(cell,i) <<endl;
possible.push_back(dir(cell,i));
}
}
}
// cout << endl;
return possible;
}
vector<int> dset::walls(int cell, vector<int> possible){
vector<int> walls;
// cout << cell << " connection 0: " << S[cell].connections[0] << endl;
for(int i = 0; i < possible.size(); i++){
if (!isin(possible[i], S[cell].connections)){
// cout << "true\n";
walls.push_back(possible[i]);
}
// cout << "false\n";
}
return walls;
}
int dset::merge(int i, int j) {
int cell1 = i;
int cell2 = j;
i = find(i);
j = find(j);
if (i != j) {
element &Si = S[i];
element &Sj = S[j];
// Adjust Adjacency List
// cout << "inconnections\n";
S[cell1].connections.push_back(cell2);
S[cell2].connections.push_back(cell1);
// cout << "notinconnections\n";
// merge (union) by rank
if (Si.rank > Sj.rank) Sj.parent = i;
else if (Si.rank < Sj.rank) Si.parent = j;
else { Sj.parent = i; Si.rank +=1; }
Nsets -=1;
}
return find(i);
}
int dset::find(int i) {
if (S[i].parent == -1){
return i;
}
// recursive path compression
S[i].parent = find(S[i].parent);
return S[i].parent;
}
bool dset::isin(int i, vector<int> test){
bool out = false;
for(int j = 0; j < test.size(); j++){
if(test[j] == i)
out = true;
}
return out;
}
Please learn to pass by reference, not value.
For example:
bool dset::isin(int i, vector<int> test)
You are passing a vector by value. That means that an entire copy is made when the function is called. If your vector has 100,000 items, then an unnecessary copy is made. Change to this:
bool dset::isin(int i, vector<int>& test)
Now no copy is done. Make this same change in all of your other functions.
You also return a vector by value, but I would leave those alone unless it is proven that your compiler can't or won't optimize the copy away.
Also, make sure you are timing a release, optimized program, and not a "debug" or unoptimized program. Since you didn't mention the compiler you're using, use the settings that generate optimized code when building your program.
Although I do not know much about c++, it would seem to me from your program description at the start that your slowdown may happen when your program is determining whether two prospectively connectable cells are already connected. Since the majority if not all cases when this is done that are used must determine that the cells are NOT connected, so that there is only one proper solution, every time this is done your program has to examine/solve the entire maze to that point to make sure that there is no way in which it could already be connected. This means that as the existing part of the maze gets larger, the time it takes to complete this task will get longer and longer.
To test whether this is the case, you could have your program record how long it takes to determine if two cells are connected every time ( or 10 times) it does so, and if the times on the list get longer linearly, then this or something similar is part of the issue.
You could fix this by either allowing already-connected to be connected by another path, or by simplifying the way in which your program checks what cells are connected.
Sorry I can't give better code-specific advice, but I'm researching how to create a maze and ran across your question, hopefully my answer at least is food for thought.
Related
I have to dynamically allocate an array and pass it to a function to calculate odds of a weighted die being rolled. Whenever I run through my code the function doesn't remember the values added to my array and returns random values, what's wrong about the way I'm passing *weight into the roll function? I added print statements after adding weights in and the weight is entered fine up until it's passed to the function via pointer.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
int roll (int sides, double *weight) {
int total[sides + 1];
total[0] = 0;
for (int i = 1; i <= sides; i++) {
total[i] = total[i - 1] + weight[i];
}
int current = (rand() % total[sides + 1] - 1 + 1);
//cout << current << " ";
for (int i = 1; i <= sides; i++) { // 1 to weight 1,,,,, weight 1 to weight
2
if (current <= total [i] && current > total[i - 1]) {
current = i;
}
}
return current;
}
Function that is supposed to retrieve the random number rolled. ^
int main () {
int sides = 0;
int rolls = 0;
int answer = 0;
int currentRoll = 0;
bool done = false;
double* weight;
double totalWeight;
srand(time(NULL));
cout << "Dice Roll Menu: " << endl << "1. Specify an output file" << endl <<
"2. Enter sides and weight for a die" << endl << "3. Simulate a specified
number of rolls of the weighted die" << endl << "4. Exit" << endl;
while (done != true) {
cout << endl << "Enter a number that corresponds to you choice: ";
cin >> answer;
while (answer == 2) { //SIDES
cout << "Please enter the number of sides on the die (must be
greater than two): ";
cin >> sides;
if (sides < 2) {
cout << "Invalid input, try again." << endl;
}
else {
weight = new double[sides + 1];
for (int i = 0; i < sides + 1; i++) {
weight[i] = 0;
}
break;
}
}
while (answer == 2) {
totalWeight = 0;
for (int i = 1; i <= sides; i++) { //WEIGHT
cout << "Enter a weight for side " << i << ": ";
cin >> weight[i];
cout << "TEST: " << weight[i] << endl;
totalWeight = weight[i] + totalWeight;
if (weight[i] < 0) {
cout << "Invalid input. Try again.";
totalWeight -= weight[i];
i--;
}
}
break;
}
Loop that determines sides and weight and dynamically allocates the array. ^
while (answer == 3) {
cout << "Enter the amount of rolls you would like to perform: ";
cin >> rolls;
if (rolls < 0) {
cout << "Invalid input. Try again.";
}
else {
else if (totalWeight == 0) {
cout << "Please enter weights of the dice first!" << endl;
answer = 1;
}
else {
done = true;
break;
}
}
}
//ACTUAL CODE HERE
for (int i = 1; i <= rolls; i++) { //CALCULATES
currentRoll = roll(sides, &weight[i]);
cout << currentRoll << " ";
}
}
Perhaps many of the misunderstandings that dominate the comments have to do with simply using C++ (and yet without using std::containers).
My out-of-the-box idea (or just plain crazy) is that there really is no conflict between:
"I have to be able to complete this program using 'dynamically allocated arrays', sadly I am not allowed to use vectors
yet all concerned seemed to agree that this is a C++ class assignment.
So, we need think of a way to create an array dynamically (I consider this part easy, not sure why). We want something with compile time fixed size. The array must exist in dynamic memory. (And no std containers.)
The goal has also been stated more simply
I have to dynamically allocate an array and pass it to a function to
calculate odds of a ...
I propose the following. (This code compiles and runs. )
#include <iostream>
using std::cout, std::flush, std::endl;
// Step 1 - wrap an array inside a class
class Array_t
{
const int m_sz;
int64_t* m_arr;
public:
Array_t()
: m_sz(128)
, m_arr (new int64_t[m_sz]) // allocate array in dynamic memory
{
// init for easy sum ... -------------v
for (int j=0; j<m_sz; j+=1) m_arr[j] = 1; // easy sum
}
~Array_t() = default;
int64_t sum() {
int64_t retVal = 0;
for (int i=0; i<m_sz; i+=1)
retVal += m_arr[i]; // direct access to the data!
return retVal;
}
};
// If your C++ 'Hello World' has no class ... why bother?
// Step 2 - auto var the above
class DUMY999_t
{
public:
DUMY999_t() = default;
~DUMY999_t() = default;
int operator()(int argc, char* argv[]) { return exec(argc, argv); }
private:
int exec(int , char** )
{
// here is the array wrapped in a class, an automatic var!
// the array is dynamically allocated in the class (see ctor)
Array_t arr;
// ctor provides the compile time constant
// Step 3
// pass the array (in the class) to some function foo()
cout << "\n foo(arr) :" << foo(arr) << endl;
// Step 4 - can we solve the 'how pass' question?
// It should be obvious that foo is redundant ...
// the following is both more direct
// and object-oriented (a good thing)
// >>> put the function in the object that has the data <<<
cout << "\n arr.sum() :" << arr.sum() << endl;
// invoke an object method which has
// direct access to the data!
return 0;
}
// why pass the data to the function? (c-style?)
int64_t foo(Array_t& arr)
{
return arr.sum();
}
// why not install the function into the object? (c++?)
}; // class DUMY999_t
int main(int argc, char* argv[]) { return DUMY999_t()(argc, argv); }
Typical output:
foo(arr) :128
arr.sum() :128
I'm writing a program to simulate Left Right Center. If you're not familiar, the game involves 3 dice with 1 side "L", 1 side "R", 1 side "C", and 3 sides dots. Everyone starts with $3. If you roll an "L", you pass a dollar to the left. If you roll an "R", you pass a dollar to the right. If you roll a "C", you put a dollar in the center. If you roll a dot, you take no action. Play then passes to the left. Play continues until only 1 player has money remaining, and that player wins everything.
I got the program operating correctly, except for one strange thing. When I run it as below, it runs fine, usually taking 70-150 turns to complete. When I comment out the lines
cout << "In gameOver(). Number of brokeJamokes: " << brokeJamokes;
cin.ignore();
the program takes hundreds of thousands (or millions) of turns to complete. Why would a simple output change that?
Full code follows:
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
int player[10] = {0};
int bank[10] = {0};
int rollDie() {
srand(time(NULL));
int randNum = rand()%6+1;
//cout << "In rollDie(), die roll is " << randNum << "\n";
//cin.ignore();
return randNum;
}
int distributeCash(int roll, int playerNum) {
if(roll == 1) { //pass left
bank[playerNum]--;
/* if active player is player 10 (player[9]), we need to pass to player 1 (player[0])
instead of the nonexistant player 11, so we change the array value to -1 */
if(playerNum == 9) {playerNum = -1; }
bank[playerNum + 1]++;
return 0;
}
if(roll == 2) { //pass right
bank[playerNum]--;
/* if active player is player 1 (player[0]), we need to pass to player 10 (player[9])
instead of the nonexistant player 0, so we change the array value to 11 */
if(playerNum == 0) {playerNum = 10;}
bank[playerNum - 1]++;
return 0;
}
if(roll == 3) { //pass to center
bank[playerNum]--;
return 0;
}
else {
return 0;
}
return 0;
}
int gameOver() {
int brokeJamokes = 0;
for(int i = 0; i < 10; i++) {
if(bank[i] == 0) { brokeJamokes++; }
}
cout << "In gameOver(). Number of brokeJamokes: " << brokeJamokes;
cin.ignore();
if(brokeJamokes==9) {return 1;}
else return 0;
}
void showWinner() {
for(int i = 0; i < 10; i++) {
if(bank[i] != 0) {
cout << "Player " << (i+1) << " is the winner!\n";
cin.ignore();
return;
}
}
}
int main()
{
int roll[3] = {0};
for(int x = 1; x < 10; x++) { //initialize all banks to 3 except test player (player 1)
bank[x] = 3;
}
bank[0] = 3; //test player bank initialization
int turnCount = 0;
while(!gameOver()){
for(int i = 0; i < 10; i++) {
if(gameOver()) {break;}
for(int j = 0; j < 3; j++) {
roll[j] = rollDie();
if(bank[i] != 0) {
distributeCash(roll[j], i);
}
}
/* cout << "After player " << (i + 1) << "'s roll: \n";
for(int l = 0; l < 10; l++) {
cout << "Player " << (l + 1) << " $" << bank[l] << "\n";
}
cin.ignore();
*/
turnCount++;}
}
showWinner();
cout << "Number of turns: " << turnCount << "\n";
cout << "Game over!\n";
}
As melpomene stated you repeatedly call srand, setting the same seed (as I think it uses time with a second resolution). Therefore you will get thousands or millions of 'random' numbers in a row of the same value until the time changes. Think what happens if everyone gets the same die roll, the game will never end.
When you have the cout line, it will slow the program considerably, so get less of the same roll in a row from setting srand to the same value.
To fix it move the call to srand to the main function so its only called once.
This is my code so far the problem I am having is with it printing out the smallest diameter of the planet.
Update Code....and still don't work...
#include <iostream>
#include <string>
using namespace std;
struct Planet
{
string name;
int distanceSun;
int diameter;
int mass;
};
int PrintPlanet(Planet planet)
{
cout << "Name: " << planet.name << endl;
cout << "Distance to the sun: " << planet.distanceSun << endl;
cout << "Diameter: " << planet.diameter << endl;
cout << "Mass: " << planet.mass << endl;
return 0;
}
int FindSmallestDiameter(Planet * arr, int n)
{
int resultSmallest = INT_MAX;
for (int j = 1; j < n; j++)
{
if(arr[j].diameter < arr[resultSmallest].diameter)
{
resultSmallest = j;
}
}
return resultSmallest;
}
int main()
{
struct Planet * planet;
int numberPlanet;
cout << "Enter a value for planets: ";
cin >> numberPlanet;
planet = new Planet[numberPlanet];
int enterSelection;
do
{
cout << "Enter selection: \n" <<
"1. Print the planet with the smallest diameter\n" <<
"0. Exit progrma\n";
cin >> enterSelection;
switch(enterSelection)
{
case 1:
{
int heaviest = FindHeaviestPlanet(planet, numberPlanet);
if (heaviest < 0)
{
cout << "No planet defined.\n";
}
else
{
cout << "Heaviest planet: \n";
PrintPlanet(planet[heaviest]);
}
}
break;
}
'
When in the menu set the print command on the planet with the smaller diameter console print:
Name:
Distance to the sun: 0
Diameter: 0
Mass: 0
Regardless of the missing code in main(), the syntactic errors there, and the way you could populate the planets, your search function FindSmallestDiameter() will never work:
you start with resultSmallest = INT_MAX. This is a very very large number
then you start your loop with j=1 (normally array indexing startw with 0)
then you try to access arr[resultSmallest].diameter, which is out of bounds, and causes undefined behaviour. It could cause havoc or segmentation faults, but it could also return a random number, or even 0.
Note that this function will never return a negative number, even if the planet array is empty. So your message "No planet defined" will never be displayed. Even worse, if no planet is defined, you'll return INT_MAX, which could cause your code in main() to (try to) access further elements out of bounds.
Possible correction:
int FindSmallestDiameter(Planet * arr, int n)
{
if (n==0)
return -1; // handle special case first
else {
int resultSmallest = 0; // let's suppose the smallest is the first element
for (int j = 1; j < n; j++) { // then it makes sense to loop starting with the second
if(arr[j].diameter < arr[resultSmallest].diameter) // and challenge the current smalest
resultSmallest = j;
}
return resultSmallest;
}
}
Or a shorter one, using standard algorithm std::min_element():
int FindSmallestDiameter(Planet * arr, int n)
{
return n==0 ? -1 : std::min_element(arr,arr+n,[](const Planet &a,const Planet &b)->bool {return a.diameter<b.diameter;})-arr;
}
The problem is solved with the following function:
Planet FindSmallestDiameter(Planet * arr, int n)
{
Planet smallestDiameter = arr[0];
for (int i = 0; i < n; i++)
{
if (smallestDiameter.diameter < arr[i].diameter)
{
smallestDiameter = arr[i];
}
}
return smallestDiameter;
}
I'm in desperate need of assistance.
I'm working on a population program in C++ for my Systems Software class.
This is my first foray into C++ territory, I only have some Java knowledge to help me out.
Basically, the program is supposed simulate a simple population. The guidelines are as follows:
The first elements (starting population) have random age and sex.
2 elements can pair if their lifespan falls between [0.25,0.50] (assuming they die at 1) and they are of the opposite sex.
Each element can only pair twice.
So here's my code, and take it easy guys I'm not very well versed in C++ yet...:
#include <vector>
#include <ctime>
#include <stdlib.h>
#include <iostream>
#include <iterator>
using namespace std;
class Element {
public:
int pair;
double life;
int tag;
void setValues(double, int);
int getPair() {
return pair;
}
void incrementPair() {
pair = pair++;
}
double getLife() {
return life;
}
void incrementLife() {
life = life + 0.05;
}
int getTag() {
return tag;
}
}; //Element
void Element::setValues(double b, int c) {
pair = 0;
life = b;
tag = c;
}
int main() {
double Time = 0.0;
srand(time(NULL));
vector<Element> vec;
for (int i = 0; i<50; ++i) {
Element x;
x.setValues(((double) rand() / (RAND_MAX)), rand()%2);
vec.push_back(x);
}//for
while (vec.size() != 0) {
int newPopCount = 0;
int Dead = 0;
for(int count = 0; count != vec.size(); ) {
std::vector<Element>::iterator p = vec.begin();
std::vector<Element>::iterator i = vec.begin() + 1;
if ((p->getPair() == 2) || (p->getLife() < 0.25) || (p->getLife() > 0.50)) {
count++;
p++;
}//if
else {
for(int count1 = count + 1 ; count1 != vec.size() ; ) {
if ((i->getLife() < 0.25) || (i->getLife() > 0.50) || (i->getPair() == 2) || (p->getTag() == i->getTag())) {
++i;
count1++;
}//if
else {
cout << i->getTag() << " " << p->getTag() << endl;
cout << i->getPair() << " " << p->getPair() << endl;
cout << i->getLife() << " " << p->getLife() << endl;
p->incrementPair();
i->incrementPair();
newPopCount++;
count1++;
count++;
p++;
i++;
}//else
}//for
}//else
}//for
Time += 0.05;
for ( vector<Element>::iterator m = vec.begin(); m != vec.end(); ++m ) {
m->incrementLife();
if ( m->getLife() >= 1.00 ) {
Dead++;
//vec.clear();
vec.erase(m);
//vec.shrink_to_fit();
}//if
for (int i = 0; i = newPopCount; i++) {
Element woo;
woo.setValues(0.0, rand()%2);
vec.push_back(woo);
}//for
}//for
cout << "The total number of dead is: " << Dead << endl;
cout << "The total number born is: " << newPopCount << endl;
cout << "Current population is: " << vec.size() << endl;
cout << "Population has survived for: " << Time << endl;
sleep(1);
}//while
cout<< "The populace is now extinct." << endl;
cout<< "The populace survived for: " << Time << endl;
}//main
You can see my silly debugging methods, I was getting a Segmentation Fault error before, but I believe that to be fixed. The issue now is that I'm getting stuck in the loops. The program seems to run almost erratically, and I can't pinpoint the issue any closer than inside of one of the loops.
My Dead integer is incremented and displayed properly, but the newPopCount integer is not, which makes no sense to me.
Also the program never gets out of the while loop, it will continue until it gets stuck in another of the many loops I have.
I have had several other issues, which I've been fixing slowly but surely as you can see by my patchwork code.
Any help at all will be greatly appreciated.
Two obvious issues, which your compiler will warn you about if you turn up your warnings high enough.
First:
void incrementPair() {
pair = pair++;
}
This is undefined behavior. Should be just:
void incrementPair() {
++pair;
}
Second:
for (int i = 0; i = newPopCount; i++) {
Element woo;
woo.setValues(0.0, rand()%2);
vec.push_back(woo);
}
That condition in your for loop is almost certainly wrong. It likely should be i <= newPopcount, or something like that.
As a side note, your setValues() member function looks like it's doing the job that a constructor should be doing.
EDIT: Look here:
for(int count = 0; count != vec.size(); ) {
std::vector<Element>::iterator p = vec.begin();
std::vector<Element>::iterator i = vec.begin() + 1;
Imagine you have a std::vector with only one element in it, and then think about what i is going to represent when you do i->getLife() a few lines later. Just having those definitions inside the for loop looks a bit suspicious in itself, since you increment both p and i during the loop, but you're going to reset them again on every iteration, but it's not all that easy to follow the logic, so perhaps that's what you intended.
vec.erase(m); results in an invalid m. You want to do m = vec.erase(m)
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
I'm having difficulty commenting on my code for a blackjack app for c++. I have coded it but now I am confused as to what to put in for comments, my instructor is frugal when it comes to commenting.
Thanks for any and all help! :)
here is my code:
#include <iostream> // in/out for form
#include <ctime> // uses time for randomizing
#include <Windows.h> //
using namespace std; // prevents redundancey of ::STD
char enter[1]; //
int hand[52] = {}, dealer[52]; // array of 52 for 52 cards that holds zero
int GetScore(int param) // function prototype that calls getscore
{
int score = 0; //
int temp[52]; //
if(param == 0) for(int i = 0; i < 52; i++) temp[i] = hand[i]; //
if(param == 1) for(int i = 0; i < 52; i++) temp[i] = dealer[i]; //
for(int i = 0; i < 52; i++) //
{
if(temp[i] == 0) break; //
if(temp[i] != 11)
{
score += temp[i];
}
}
for(int i = 0; i < 52; i++) // simple loop to ....
{
if(temp[i] == 0) break;
if(temp[i] == 11)
{
if(temp[i] + score <= 21)
{
score += 11;
}
else
{
score += 1;
}
}
}
return score;
}
void ShowDealersHand(int show) //
{
cout << "\n Dealer's hand: "; //
if(show == 1) //
{
if(dealer[0] == 11)
{
cout << "A [Not Shown]";
}
else
{
cout << dealer[0] << " [Not Shown]";
}
}
else
{
for(int i = 0; i < 52; i++)
{
if(dealer[i] == 0) break;
if(dealer[i] == 11)
{
cout << "A ";
}
else
{
cout << dealer[i] << " ";
}
}
}
}
void Blackjack()
{
for(int i = 0; i < 2; i++) //
{
int num, temp;
if(hand[0] == 0) temp = 0;
else temp = 1;
num = rand() % 10 + 2;
hand[temp] = num;
num = rand() % 10 + 2;
dealer[temp] = num;
}
ShowDealersHand(1); //
cout << endl << endl << " Your hand: "; //
for(int i = 0; i < 52; i++) //
{
if(hand[i] == 0) break;
if(hand[i] == 11)
{
cout << "A ";
}
else
{
cout << hand[i] << " ";
}
}
cout << endl << " Your score: " << GetScore(0) << endl << endl;
while(GetScore(0) <= 21)
{
cout << " Hit(h) or stand(s): ";
cin >> enter;
if(strcmp(enter, "h") == 0)
{
int card = rand() % 10 + 2;
for(int i = 0; i < 52; i++)
{
if(hand[i] == 0)
{
hand[i] = card;
break;
}
}
cout << " Your hand: ";
for(int i = 0; i < 52; i++)
{
if(hand[i] == 0) break;
if(hand[i] == 11)
{
cout << "A ";
}
else
{
cout << hand[i] << " ";
}
}
cout << endl << " Your score: " << GetScore(0) << endl << endl;
if(GetScore(0) > 21)
{
cout << " - ..BUST.. -" << endl ;
cout << "\n - !!House Wins!! -";
goto end;
break;
}
}
else if(strcmp(enter, "s") == 0)
{
cout << endl;
break;
}
system("pause > nul");
}
Sleep(2000);
ShowDealersHand(0);
cout << endl << " Dealer score: " << GetScore(1) << endl << endl;
if(GetScore(1) < GetScore(0))
{
while(GetScore(1) < 17 && GetScore(0) <= 21)
{
Sleep(2000);
int card = rand() % 10 + 2;
for(int i = 0; i < 52; i++)
{
if(dealer[i] == 0)
{
dealer[i] = card;
break;
}
}
cout << " Dealer's hand: ";
for(int i = 0; i < 52; i++)
{
if(dealer[i] == 0) break;
if(dealer[i] == 11)
{
cout << "A ";
}
else
{
cout << dealer[i] << " ";
}
}
cout << endl << " Dealer score: " << GetScore(1) << endl << endl;
if(GetScore(1) >= GetScore(0)) break;
}
}
end:
if(GetScore(1) > GetScore(0) && GetScore(1) <= 21)
{
cout << " - !!House Wins!! -";
}
else if(GetScore(1) == GetScore(0) && GetScore(0) <= 21)
{
cout << " * Tie * - !!House Wins!! -";
}
else if(GetScore(0) <= 21)
{
cout << " - !!!You win!!! -"; // outputs if you win
}
system("pause > nul");
system("cls");
}
void main() // no return on main for form to start
{
srand((unsigned int)time(0)); // randomizer unasigned initializer
cout << " *-*-*-*-*Zachattack's Blackjack*-*-*-*-*" << endl << endl; // Name of program outputs to user
Blackjack();
}
As they are, you comments are useless. Take, for example, this:
int hand[52] = {}, dealer[52]; // array of 52 for 52 cards that holds zero
Anyone that uses C/C++ is expected to know what that line is doing, without having to read the comment.
Instead of commenting what your code does ("this line declares an int"), comment why the code does what it does (what you were thinking when you wrote that code), or, if the algorithm is complicated, comment on how it does something, or document how to use your functions.
For example, your GetScore function takes has a parameter called param. I've no idea what values I am expected to give to param, so you should explain it: "when param is 1, this happens, when it is 0, that happens".
Another example: in your code you have a line Sleep(2000). Why did you use that function? Explain it in a comment:
// Sleep 2 seconds to make the game more exciting
Sleep(2000);
Always assume that the person reading your code knows how to use the language. Never assume that the person reading your code is able to understand your way of thinking about a certain problem.
Comments should explain why, not what.
So your comment for using namespace std; is unnecessary, because any C++ programmer will already know what the using keyword does.
However, for the GetScore() function, you've omitted to give the rules for totalling the score.
The comments should add value, not just duplicate things that are obvious from even a cursory look at the code.
Assume the person reading the code is familiar with the programming environment, but wasn't party to what was going on in your mind as you wrote it.
Here's an example I sometimes use - a piece of code with useless comments (can you work out what is going on here, and why?):
// Is the new selection end above the selection start?
if newSelEnd.Line < FSelection.SelStart.Line then
begin
// Is the selection start at the left margin and above the selection end?
if (FSelection.SelStart.Line < FSelection.SelEnd.Line) and
(FSelection.SelStart.Column = 0) then
begin
// Move the selection start down one line
Inc(FSelection.SelStart.Line);
And with helpful comments:
if newSelEnd.Line < FSelection.SelStart.Line then
begin
// The new selection end is above the selection start, so will become the
// top of the new selection.
if (FSelection.SelStart.Line < FSelection.SelEnd.Line) and
(FSelection.SelStart.Column = 0) then
begin
// The start of the selection was at the top of the old selection and the
// new line is above this, so the selection is about to change direction.
// Since the start column is 0 we assume the original selection was an
// entire line, so we keep the original line selected by moving the start
// position down one line.
Inc(FSelection.SelStart.Line);
Function/method purpose with parameters purposes
Magic numbers
Those are my most important rules about commenting. Optional is "why am I iterating/what am I looking for" about loops. Magic numbers is every declaration/condition that uses const values like GetScore(0) <= 21, or hand[52].
Those are places that should be commented even for yourself... It feels realy good when you look at your code after year or more and still read it without any problem.
Apart from the other answers, often, it is a good idea to get rid of a comment by replacing it with a named function:
// Find top-scorers:
for (Iter it=scorers.begin(), end=scorers.end(); it!=end; ++it) {
...
{
top.push_back (*it);
}
}
Instead, do:
const std::vector<Scorer> top = find_top_scorers (scorers.begin(),
scorers.end());
This decreases miss-maintenance (comments are not enforced and may get out-of-date) and reusability. Personally, I always endeavour for commentless code, as I am sick of out-of-date comments, when possible and sane.
Of course, in the example above, you should probably use std::partial_sort, std::partition or std::stable_partition.
Also, magic numbers should be replaced by constants instead, with the same argumentation about miss-maintenance and reusability:
const float x = radius * 3.14159...; // radius * pi
const float pi = 3.14159...,
x = radius * pi;