I am to draw 3 balls from an urn of 24 and add up the total discount the balls represent. I am not allowed to replace the balls after drawing, so there can be no duplicate balls drawn. The discounts are 1, 2, 3, 4, 5, 6, 7, 8, and there are 3 of each.
My solution to this problem was to create multiple while loops that roll out of 24 and re-roll until no duplicates are drawn. I have done a loop like this in the past that would loop random numbers until a non-duplicate was chosen and it worked fine, so I set this program up the same way.
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int draw(int urn[], int draws[]);
int main()
{
int discountSum,discount;
int urn[24]={1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8};
int draws[1000]={0};
draw(urn,draws);
cin >> discount;
int averageDiscount=discount/1000;
return 0;
}
int draw(int urn[], int draws[])
{
static int discountSum=0;
int i; //simulations counter
int ball1, ball2, ball3;
int score1, score2, score3;
int totalDiscount;
srand(time(0));
for(i=0;i<1000;i++)
{
ball1=rand()%24;
while (ball2==ball1)
{
ball2=rand()%24;
}
while ((ball3==ball2)||(ball3==ball1))
{
ball3=rand()%24;
}
score1=urn[ball1];
score2=urn[ball2];
score3=urn[ball3];
totalDiscount=score1+score2+score3;
draws[i]=totalDiscount;
cout << "1) " << draws[i] << " percent discount.\n";
discountSum+=totalDiscount;
}
return discountSum;
}
When I run this code, instead of receiving an error, the program runs with no output, and a return of a negative garbage value instead of 0. I would like to see the output from each discount up to the 1000th loop.
It looks as if the bug is that ball2 and ball3 are compared before they're ever set to anything. They're never even initialized, which is the likely cause of your "garbage value." It'll probably work if you "draw" each ball before comparing it, as:
ball1=rand()%24;
ball2=rand()%24;
while (ball2==ball1)
{
ball2=rand()%24;
}
ball3=rand()%24;
while ((ball3==ball2)||(ball3==ball1))
{
ball3=rand()%24;
}
An even better way would be to use do...while loops instead, which always run once, as:
ball1=rand()%24;
do
{
ball2=rand()%24;
} while (ball2==ball1);
do
{
ball3=rand()%24;
} while ((ball3==ball2)||(ball3==ball1));
A much simpler way to do this is to use the facilities build into the C++ standard library:
#include <iostream>
#include <algorithm>
#include <random>
std::mt19937 gen(std::random_device{}()); // initialize random number generator
/*
* or
std::mt19937 gen(std::time(NULL));
* if std::random_device is not well-implemented
*/
int draw()
{
static int urn[24]={1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8};
std::shuffle(std::begin(urn), std::end(urn), gen); // shuffle array
return urn [0] + urn[1] + urn[2]; // pick first three balls from array
}
int main()
{
int discount = draw();
// Use discount. For example,
std::cout << discount;
return 0;
}
Documentation:
std::mt19937
std::random_device
std::shuffle
Related
I want to make a function that generates numbers but doesn't repeat it self. If every number is generated the array can be emptied and it can start over again.
This is the code I made but it doesn't work.
The comments in the code explains the code a little.
The largest number that is allowed is "howManyWords".
This is used to display words which are stored in an array
I want to use it like this: array\[random()\]
#include <stdio.h>
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
//public scope
int howManyWords; // how many words you have enter
int random(){
int random;
int numbers[howManyWords];
srand(time(0)); //changing the algorithm
random = rand() % howManyWords;
numbers[random] = random; // store the digit in the position in the array equal to the digit that is generated
for(int i=0; i<howManyWords; i++){ // going through every element in the array
if(numbers[i] == random){ // if the number is already generated, generate a different number
random = rand() % howManyWords;
}
}
return random;
}
Rather than your function, which discards the state of which numbers it has returned each time it is called, you should use a function object.
struct random_t {
random_t(int max) : values(max), current(max) {
std::iota(values.begin(), values.end(), 0);
}
template<typename URBG = std::random_device &>
int operator()(URBG&& urbg = default_random) {
if (current == values.size()) {
shuffle(std::forward<URBG>(urbg));
}
return values[current++];
}
private:
template<typename URBG>
void shuffle(URBG&& urbg) {
std::shuffle(values.begin(), values.end(), std::forward<URBG>(urbg));
current = 0;
}
std::vector<int> values;
std::vector<int>::size_type current;
static thread_local std::random_device default_random;
};
See it live
I need to make a simulator for a college homework. In this simulator there are 3 computers, 2 of which send messages to computer 1 which then decides to either send the message or reject it. The rejection is random chance with 20% of rejection on computer 2 and 50% on computer 3. I use the rand()%100+1 function with the srand(time(NULL)) seed. It makes a random number however I need to run this multiple times and every time the same random number is used. For example if I run the simulation 12 times and the number generated is 45, 45 is used 12 times. I've both placed the random number generator inside the code and made a function outside.
How can you make a random number generator that generates a random number every time?
#include <iostream>
#include <new>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
using namespace std;
int randomgen()
{
int rndnum=0;
srand (time(NULL));
rndnum=rand()%100+1;
cout<< rndnum<<endl;
return rndnum;
}
struct comp1
{
int rejected=0;
int received=0;
int sent=0;
int onhold=0;
bool comp2reception()
{
received++;
bool result=false;
int rndnum=0;
srand (time(NULL));
rndnum=rand()%100+1;
if(rndnum<=20)
{
rejected++;
result=false;
}
if(rndnum>=21)
{
onhold++;
result=true;
}
return result;
}
bool comp3reception()
{
received++;
bool result=false;
int rndnum=randomgen;
if(rndnum<=50)
{
rejected++;
result=false;
}
if(rndnum>=51)
{
onhold++;
result=true;
}
return result;
}
};
Use the C++11 header <random>.
#include <random>
static std::random_device rd;
static std::mt19937 gen(rd());
int randomgen()
{
std::uniform_int_distribution<> dis(0,100);
int rndnum = dis(gen);
std::cout << rndnum << std::endl;
return rndnum;
}
Call srand(time(NULL)) just once at the beginning of the program.
Since time() return number of seconds from 1970 and you program probably takes less than that to finish, you esentially reset the generator with same value before each call. Which of course returns same (first) value each call.
A problem set for people learning C++ is
Write a short program to simulate a ball being dropped off of a tower. To start, the user should be asked for the initial height of the tower in meters. Assume normal gravity (9.8 m/s2), and that the ball has no initial velocity. Have the program output the height of the ball above the ground after 0, 1, 2, 3, 4, and 5 seconds. The ball should not go underneath the ground (height 0).
Before starting C++ I had a reasonable, but primarily self taught, knowledge of Java. So looking at the problem it seems like it ought to be split into
input class
output class
calculations class
Physical constants class (recommended by the question setter)
controller ('main') class
The input class would ask the user for a starting height, which would be passed to the controller. The controller would give this and a number of seconds (5) to the calculations class, which would create an array of results and return this to the controller. The controller would hand the array of results to the output class that would print them to the console.
I will put the actual code at the bottom, but it's possibly not needed.
You can probably already see the problem, attempting to return an array. I'm not asking how to get round that problem, there is a workaround here and here. I'm asking, is the problem a result of bad design? Should my program be structured differently, for performance, maintenance or style reasons, such that I would not be attempting to return an array like object?
Here is the code (which works apart from trying to return arrays);
main.cpp
/*
* Just the main class, call other classes and passes variables around
*/
#include <iostream>
#include "dropSim.h"
using namespace std;
int main()
{
double height = getHeight();
int seconds = 5;
double* results = calculateResults(height, seconds);
outputResults(results);
return 0;
}
getHeight.cpp
/*
* Asks the user for a height from which to start the experiment
* SI units
*/
#include <iostream>
using namespace std;
double getHeight()
{
cout << "What height should the experiment start at; ";
double height;
cin >> height;
return height;
}
calculateResults.cpp
/*
* given the initial height and the physical constants, the position of the ball
* is calculated at integer number seconds, beginning at 0
*/
#include "constants.h"
#include <cmath>
#include <iostream>
using namespace std;
double getPosition(double height, double time);
double* calculateResults(double height, int seconds)
{
double positions[seconds + 1];
for(int t = 0; t < seconds + 1; t++)
{
positions[t] = getPosition(height, t);
}
return positions;
}
double getPosition(double height, double time)
{
double position = height - 0.5*constants::gravity*pow(static_cast<double>(time), 2);
if( position < 0) position = 0;
//Commented code is for testing
//cout << position << endl;
return position;
}
outputResults.cpp
/*
* Takes the array of results and prints them in an appropriate format
*/
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
void outputResults(double* results){
string outputText = "";
//The commented code is to test the output method
//Which is working
//double results1[] = {1,2,3,4,5};
//int numResults = sizeof(results1)/sizeof(results1[0]);
int numResults = sizeof(results)/sizeof(results[0]);
//cout << numResults; //= 0 ... Oh
for(int t = 0; t < numResults; t++)
{
ostringstream line;
line << "After " << t << " seconds the height of the object is " << results[t] << "\r";
outputText.append(line.str());
}
cout << outputText;
}
And finally a couple of headers;
dropSim.h
/*
* dropSim.h
*/
#ifndef DROPSIM_H_
#define DROPSIM_H_
double getHeight();
double* calculateResults(double height, int seconds);
void outputResults(double* results);
#endif /* DROPSIM_H_ */
constants.h
/*
* Contains physical constants relevant to simulation.
* SI units
*/
#ifndef CONSTANTS_H_
#define CONSTANTS_H_
namespace constants
{
const double gravity(9.81);
}
#endif /* CONSTANTS_H_ */
I would say that you're over-engineering a big solution to a little problem, but to answer your specific question:
Should my program be structured differently, for performance, maintenance or style reasons, such that I would not be attempting to return an array like object?
Returning an array-like object is fine. But that doesn't mean returning an array, nor does it mean allocating raw memory with new.
And it's not restricted to return values either. When you're starting out with C++, it's probably best to just forget that it has built-in arrays at all. Most of the time, you should be using either std::vector or std::array (or another linear collection such as std::deque).
Built-in arrays should normally be viewed as a special-purpose item, included primarily for compatibility with C, not for everyday use.
It may, however, be worth considering writing your computation in the same style as the algorithms in the standard library. This would mean writing the code to receive an iterator to a destination, and writing its output to wherever that iterator designates.
I'd probably package the height and time together as a set of input parameters, and have a function that generates output based on those:
struct params {
double height;
int seconds;
};
template <class OutIt>
void calc_pos(params const &p, OutIt output) {
for (int i=0; i<p.seconds; i++) {
*output = get_position(p.height, i);
++output;
}
}
This works somewhat more clearly along with the rest of the standard library:
std::vector<double> results;
calc_pos(inputs, std::back_inserter(results));
You can go a few steps further if you like--the standard library has quite a bit to help with a great deal of this. Your calc_pos does little more than invoke another function repeatedly with successive values for the time. You could (for example) use std::iota to generate the successive times, then use std::transform to generate outputs:
std::vector<int> times(6);
std::iota(times.begin(), times.end(), 0);
std::vector<double> distances;
std::transform(times.begin(), times.end(), compute_distance);
This computes the distances as the distance dropped after a given period of time rather than the height above the ground, but given an initial height, computing the difference between the two is quite trivial:
double initial_height = 5;
std::vector<double> heights;
std::transform(distances.begin(), distances.end(),
std::back_inserter(heights),
[=](double v) { return max(initial_height-v, 0); });
At least for now, this doesn't attempt to calculate the ball bouncing when it hits the ground--it just assumes the ball immediately stops when it hits the ground.
You should get rid of self-allocated double * and use std::vector<double> instead. It's not difficult to learn and a basic step in modern C++
This is how I would solve the problem:
#include <cmath>
#include <iostream>
#include <iomanip>
using std::cin;
using std::cout;
using std::endl;
using std::sqrt;
using std::fixed;
using std::setprecision;
using std::max;
using std::setw;
static const double g = 9.81;
class Calculator {
public:
Calculator(double inh) : h(inh)
{
}
void DoWork() const {
double tmax = sqrt(h / ( g / 2));
for (double t=0.0; t<tmax; t+=1.0) {
GenerateOutput(t);
}
GenerateOutput(tmax);
}
private:
void GenerateOutput(double t) const {
double x = g * t * t / 2;
double hremaining = max(h - x, 0.0);
cout << fixed << setprecision(2) << setw(10) << t;
cout << setw(10) << hremaining << endl;
}
double h;
};
int main() {
double h(0.0);
cout << "Enter height in meters: ";
cin >> h;
if (h > 0.0) {
const Calculator calc(h);
calc.DoWork();
} else {
return 1;
}
return 0;
}
i am trying to have a function determine the result
a. If the numbers add up to 5, 7, or 12, then the player wins, and the function should return an indication of this (use some integer to represent a win).
b. If the numbers add up to 2, 4, or 11, then the player loses, and the function should return an indication of this (once again, use an integer).
c. If the numbers add up to anything else, then the game is a draw and the function should say this (by way of an integer).
question, do i need a different func for winner, loser, and draw?
and what how can i return a integer to main to let main know that if we have a winner a loser a draw.
just learning to program any help would be greatly appreciated
//function
int outcome(int, int)
{
int die1;
int die2;
int winner;
int loser;
int draw;
if (die1&&die2==5||7||12)
return 99;
if (die1&&die2==2||4||11)
return loser;
else
return draw;
}
// func to get a random number
int rollDice()
{
int roll;
roll = (rand()%6)+1;
return roll;
}
the main func
#include <iostream>
#include <cstdlib>
#include <fstream>
using namespace std;
int main()
{
double die1=0;
double die2=0;
int winner=0; //counter for winners
int loser=0; //counter for losers
int draw=0; //counter for draw
//func to determine the outcome
int outcome(int, int);
//func for random numbers
int rollDice();
int outcome(int, int)
if (return==99)
cout <<"winner";
Your code has several syntax errors. If I want to, say, make a function to add two integer numbers, I'd do something like this:
int add(int a, int b) //VARIABLES MUST CARRY A NAME!
{
return a+b;
}
If you want to work with conditions, do this:
if(a==5 && b==6 || a==6 && b==7) //Just as an example
Your fixed condition would be this:
if (die1+die2==5 || die1+die2==7 || die1+die2==12)
Also, study variable scope. Let's say I have the following:
int main()
{
int myVar = 1;
}
int anotherFunction()
{
println("%d", myVar); //This will cause an error, because myVar doesn't exist here, it only exists in main()
}
These are the most notable errors I can see in your code.
I have written a practice code for a 'battle' that allows you to select number of combatants, number of rounds and number of dice-rolls per fighter per round storing the result into a 3D vector array. The storage part is working; however, the printResult() function is botched (i have put a // before it in main() ) and the srand() isnt working either. The complete program is below for convenience:
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <ctime>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
class Combat{
private:
int numberOfRounds;
int numberOfCombatants;
int numberOfRolls;
int sidesDie;
vector <int> rollz;
vector <vector <int> >combatant;
vector <vector <vector <int> > > round;
public:
void printMenu();
void battle();
void printResult();
Combat(int, int , int, int );
Combat(int );
Combat();
int roll();
int roll(int die);
};
void Combat::printMenu()
{
cout<<setw (10)<<"Welcome to the Combat Menu";
cout<<'\n'<<setw (10)<<"Choose:";
cout<<'\n'<<setw (10)<<"Number of combatants: ";
cin>>numberOfCombatants;
cout<<'\n'<<setw (10)<<"Die sides:";
cin>>sidesDie;
cout<<'\n'<<setw (10)<<"Enter number of rounds: ";
cin>>numberOfRounds;
cout<<setw(10)<<"Enter number of rolls (per combatant per round):";
cin>>numberOfRolls;
}
Combat::Combat(){
numberOfRounds=8;
}
Combat::Combat(int x){
x=numberOfRounds;
}
Combat::Combat(int rnds,int cmb,int rll, int sides){
numberOfRounds=rnds;
numberOfCombatants=cmb;
numberOfRolls=rll;
sidesDie=sides;
}
int Combat::roll(int die)
{
die=sidesDie;
srand(time(0));
int r=(1+rand()%die);
return r;
}
int Combat::roll(){
srand(time(0));
int r=(1+rand()%6);
return r;
}
void Combat::battle(){
cout<<setw(10)<<" Computing results of battle ...\n";
int i,j,k;
for (i=0;i<numberOfRounds;++i){
cout<<"\nRound number "<<i+1;
round.push_back(combatant);
for(j=0;j<numberOfCombatants;++j){
cout<<"\nCombatant number "<<j+1;
combatant.push_back(rollz);
cout<<endl;
for(k=0;k<numberOfRolls;++k){
rollz.push_back(roll(sidesDie));
cout<<rollz.at(k)<<'\t';
}
}
cout<<endl<<endl;
}
cout<<endl;
}
void Combat::printResult(){
cout<<endl;
vector< vector <vector<int> > >::const_iterator it1;
int combt, counter=0;
for (it1=round.begin();it1 !=round.end();++it1){
++counter;
cout<<"\nRound number "<<counter<<endl;
for(vector<vector<int> >::const_iterator it2=combatant.begin();it2!=combatant.end();++it2){
++combt;
cout<<"\nCombatant "<<combt<<" hits ";
for(vector<int>::const_iterator it3=rollz.begin();it3!=rollz.end();++it3){
cout<<*it3<<'\t';
}
}
}
}
int main ()
{
Combat fight;
fight.printMenu();
fight.battle();
//fight.printResult();
cout<<endl;
}
You have two problems you should tackle separately (and which you should have solved separately before you put them together into one code base). Loki Asteri has already addressed the problem with srand().
It looks as if round is a vector of Combatant, which is a vector of something else, but look here:
void Combat::printResult(){
...
for (it1=round.begin();it1 !=round.end();++it1){
++counter;
cout<<"\nRound number "<<counter<<endl;
// You never use counter or it1 again.
// You iterate over the same combatant for each it1:
for(vector<vector<int> >::const_iterator it2=combatant.begin();
it2!=combatant.end();++it2){
++combt;
cout<<"\nCombatant "<<combt<<" hits "; // bad variable name at best
// And now you iterate over the same rollz
// for every entry in combatant.
for(vector<int>::const_iterator it3=rollz.begin();
it3!=rollz.end();++it3){
cout<<*it3<<'\t';
}
}
}
}
Only call srand() once in an application.
int main()
{
srand(time(0));
// STUFF
}