C++ selecting a number of random items without repeating - c++

Write a program that randomly selects from a bag of eight objects.
Each object can be red, blue, orange, or green, and it can be a ball or a cube.
Assume that the bag contains one object for each combination (one red ball, one
red cube, one orange ball, one orange cube, and so on). Write code similar to
Example 5.3, using two string arrays—one to identify colors and the other to
identify shapes.
I am trying to write a program to carry out the above exercise - the problem I am having is the same object can be selected more than once each time.
This is the code so far
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
int rand_0toN1(int n);
void choose_object();
char *colour[4] =
{"Red", "Blue", "Orange", "Green"};
char *object[2] =
{"Ball", "Cube"};
int main()
{
int n, i;
srand(time(NULL)); // Set seed for randomizing.
while (1) {
cout << "Enter no. of objects to draw ";
cout << "(0 to exit): ";
cin >> n;
if (n == 0)
break;
for (i = 1; i <= n; i++)
choose_object();
}
return 0;
}
void choose_object() {
int c; // Random index (0 thru 4) into
// colours array
int o; // Random index (0 thru 2) into
// object array
c = rand_0toN1(4);
o = rand_0toN1(2);
cout << colour[c] << "," << object[o] << endl;
}
int rand_0toN1(int n) {
return rand() % n;
}

Let's try to solve this by making a real world analogy:
Let's say you have a massive jar of marbles, of the colors listed above. It's so massive (infinite size!) that you always have the same chance to draw a marble of a given color, always 1/4 each time.
How would you do this in real life? Would you just keep picking randomly, chucking the marble away as you draw it? Or would you maybe keep a little list of things you've drawn already?
Or maybe you only have one of each in the jar... You wouldn't put it back in would you? Because that's kind of what you're doing here.
Each of these thought paths will lead you to a good solution. I don't want to provide a code or anything because this kind of assignment is one that teaches you how to think like a computer.

Since this is homework, I'm not going to give an exact answer, but describe what you could do:
Keep a list of objects you've already chosen.
After you choose an object, compare that object to the list of objects you've already chosen. If it's in the list, choose another object. If it's not in the list, add it to the list.
Make sure that you don't try to choose more than 8 objects, or else you'll end up in an infinite loop in part 2.
These would go in your choose_object() subroutine. You could do it in a while() loop, something like:
int seen_before = 0;
while(!seen_before) {
pick your random numbers
if(numbers not in list) {
add to list
break
}
}

Related

How to generate random fruit for C++ 2D Snake game

I am having trouble generating random fruit for my Snake game. (I am very new to programming and this is my first language).
When I run my code all works fine so far (except from some minor issues). I'm using Visual Studio C++ in an empty project. Here is my full code (I'm not displaying my #includes):
using namespace std;
bool gameOver = false;
int gameScore;
int fruitX;
int fruitY;
string bGameW = "###########";
string bGameL = "# #\n";
class gameStart
{
public:
void start()
{
cout << bGameW;
cout << bGameL;
cout << bGameL;
cout << bGameL;
cout << bGameL;
cout << bGameL;
cout << bGameL;
cout << bGameL;
cout << bGameL;
cout << bGameW;
}
void generateFruit()
{
srand(time(NULL));
fruitX = rand() % 21;
fruitY = rand() % 21;
bGameW.insert(fruitX, "F");
bGameL.insert(fruitY, "F");
}
void clearscreen()
{
system("cls");
}
private:
};
int main ()
{
gameStart gameObj;
gameObj.generateFruit();
gameObj.clearscreen();
gameObj.start();
return 0;
}
To generate the random the random fruit for the string. I use a string to make the game board, then I create random values for the fruit (X and Y) then I append them into my game board.
But the issue is: I want to make only one fruit with a random X and Y and append it into my game board to display it. But my current code is this:
bGameW.insert(fruitX, "F");
bGameL.insert(fruitY, "F");
This code makes 2 fruits with 1 at a random X and 1 at a random Y. I want to turn these 2 fruits into 1 fruit, with 1 random X and 1 random Y.
There's a whole host of things worth commenting on. Here goes:
bGameW has no \n
bGameW and bGameL are 10 and 11 characters long (both with be 11 after you add the other \n). Your RNG is generating numbers between 0 and 20... if you ever generate a number > 11 (and you will), Bad Things will happen (and probably have).
Snake games like this let you eat multiple fruit, which is why people brought up the whole "don't call srand more than once" thing, as you'll be calling generate fruit every time someone eats the old one. OTOH, that mostly removes the "calling srand multiple times per second can return the same value" problem too.
Rather than writing out those two lines, bGameW and bGameL, I recommend that you build a character array that holds your entire game display (NOT your game state, just the display of that state). You then clear it and redraw it every move. You'll need a game area, walls, something that tracks where your snake is, and the current fruit. You then 'render' all these things into your character-array-game-display. Don't forget to clear it every time you redraw it or you'll get all kinds of problems.
Rather than redrawing everything, you could use something like the "curses" library to clear and redraw specific character locations on the screen. You'd then face problems 'clearing' and redrawing different spots.
As far as programming style goes, you will find that so called "magic numbers" (like 21 in your case) can lead to bugs. What people generally do instead is to define a const with the appropriate value, and then define things in terms of that const.
// constants are often named in ALL_UPPER_CASE_WITH_UNDERSCORES
// to help you recognize them.
const int PLAY_AREA_HEIGHT = 10;
const int PLAY_AREA_WIDTH = 10;
const char EMPTY_PLAY_SQUARE = '.';
// have you learned about 2d arrays yet? Arrays at all?
char playAreaDisplay[PLAY_AREA_HEIGHT][PLAY_AREA_WIDTH];
void wipePlayArea()
{
for (int heightIdx = 0; heightIdx < PLAY_AREA_HEIGHT; ++heightIdx)
{
for (int widthIdx = 0; widthIdx < PLAY_AREA_WIDTH; ++widthIdx)
{
playAreaDisplay[heightIdx][widthIdx] = EMPTY_PLAY_SQUARE;
}
}
}

How can I 'pan out' (make screen bytes smaller) of the console screen to render 2d pyramids larger?

I am using Windows 10 with code blocks to compile my code.
I wonder WHY you want to do that. This seems to be a typical homework assignment problem for practising loops and logic. That usually is restricted to numbers easily fitting on a console. Could you elaborate what causes the need to go beyond say a size of 30? – Yunnosch 10 hours ago
#Yunnosch For pure hypothetical and experimental reasons. I essentially have a dream I could write a program that renders massive 2d pyramids on a console screen, and maybe create some game out of it. I was hoping I could figure out a way to 'pan out' of the console screen thus making the screen bytes smaller. Somebody has to know more than me, and can lead me in the right direction to accomplishing this '2d pyramid rendering' program. Thanks in advance! – Fibonacci 3 mins ago
My goal is to be able to render massive pyramid structures onto a console output screen. The code here simply asks for a number of rows and prints out a pyramid. ex. drawPyramid(50);
#include <iostream> // include iostream
using namespace std; // include std
// Draw pyramid function here
void drawPyramid(int rows)
{
// initializes space and creates for loop to keep track of rows, I and k
int space;
for(int i = 1, k = 0; i <= rows; ++i, k=0)
{
// draws spaces required
for(space = 1; space <= rows-i; ++space)
{
cout << " ";
}
// draws matter
while(k != 2*i-1)
{
cout << "* ";
++k;
}
//prints new line based on rows
cout << endl;
}
}
//driver program
int main()
{
bool fTrue = false;
// loops until user presses '0'
while(!fTrue)
{
cout << "Press (0) to quit...\n";
int i,rows;
cout << "Enter number of rows: \n";
cin >> rows;
drawPyramid(rows); // draw function called
if(rows == 0)
{
fTrue = true;
}
}
return 0;
}
Output:
While the program works great I'd like to be able to pass in bigger values such as drawPyramid(500); or drawPyramid(1000); anything above the value 50 produces results like so.
Results:
Hopefully you can understand what I am trying to ask. I want to be able to 'pan out' and move the asterisks closer together so that I can pass in larger input values into the drawPyramid() function... Thanks in advance!
I am using Windows 10 with code blocks to compile my code.

C++ Generate random numbers for dominoes

My assignment involves writing several classes that will work together to randomly sort 28 dominoes for the user and display them. The main trouble I'm having so far is just creating the dominoes without any duplication. If you're familiar with dominoes, you know that each half of them are either blank or have 1-6 dots. Basically I'll have a dynamic array of 28 unique structs (dominoes) but I'm just stuck on generating these dominoes without having identical ones. I was thinking of using FOR loops to just go through and assign values within each struct but I figured there had to be some easier way.
This is what I have so far below; I know it's not much but I can't and don't want to go on with writing methods for sorting and display without getting this right first.
class CDominoes{
public:
struct Data
{
int top;
int bottom;
Data()
{
top = 0;
bottom = 0;
}
} domino[28];
//methods to assign spots to halves
};
The simplest solution is to generate, and then shuffle. To generate, you need to avoid wasting time generating duplicates. For example, (4,5) is the same as (5,4), so you don't want to generate both. That means that your inner loop should always begin at the current value of the outer loop. In so doing, you'll never repeat a combination. Here's an example:
int main () {
for( int t = 0; t <= 6; ++t ) {
for( int b = t; b <= 6; ++b ) {
std::cout << "(" << t << "," << b << ")\n";
}
}
return 0;
}
In this example, we're considering '0' to be the same as a blank domino.
Next, instead of printing these, put them into a random access container such as std::array or std::vector, and then use std::shuffle to shuffle your container.

Out of Range error

The question is:
Jay had borrowed a friend's coffee mug and somehow lost it. As his friend will be extremely angry when he finds out about it, Jay has decided to buy his friend a replacement mug to try to control the damage.
Unfortunately, Jay does not remember the color of the mug he had borrowed. He only knows that the color was one of White, Black, Blue, Red or Yellow.
Jay goes around his office asking his colleagues if they are able to recall the color but his friends don't seem to remember the color of the mug either. What they do know is what color the mug definitely was not.
Based on this information, help Jay figure out what the color of the mug was.
The way I'm going about this:
I create a vector of all possible colors: White, Black, Blue, Red or Yellow. Then ask the user to enter the number of colleagues he will be questioning. Then take the color suggestions, and for every entry I compare it against the vector. If it is in there, I pop the color out. Eventually only one color will be left in the vector which is the color of the lost mug.
My issue:
I get an out of bound error after entering the first color and I am not able to figure out why. The exact error is:
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check
Abort (core dumped)
My code is:
#include <iostream>
#include <string>
#include <algorithm>
#include <climits>
#include <stdio.h>
#include <vector>
using namespace std;
int main(int argv, char* argc[])
{
string color;
vector<string> colorVector;
colorVector.push_back("White");
colorVector.push_back("Black");
colorVector.push_back("Blue");
colorVector.push_back("Red");
colorVector.push_back("Yellow");
int numColleagues;
cout<< "Please enter the number of Colleagues" << endl;
cin >> numColleagues;
cout<< "Please enter each suggested color" << endl;
int counter = 0;
while (counter < numColleagues) {
getline(cin, color);
counter++;
for (int i = 0; i < 5; i++) {
if (colorVector.at(i) == color) {
colorVector.erase(colorVector.begin() + i);
}
}
}
return 0;
}
You are erasing elements of your vector, but you wish to access all five elements (the loop runs from 0 to 5). So, let's say you remove the first and then you try to access the element at position 4. Out of bounds!
So change your loop to this:
colorVector.erase(std::remove(colorVector.begin(),
colorVector.end(), color), colorVector.end());
More on erase-remove idiom.
When you call vector::erase, it will return an iterator pointing to the new location of the element that followed the erased element. So if we erase this element:
1 2 3 4 5 6
^
Our iterator will automatically update to point to the 5. So we don't have to increment the iterator again, it's already sort of incremented. With that in mind:
auto it = colorVector.begin();
for (; it != colorVector.end(); /* do not increment it */ )
{
if (*it == color)
{
it = colorVector.erase(it); // erase and update
}
else
{
++it; // just update
}
}
Of course even better to just use the algorithms which are less error prone
colorVector.erase(
std::remove(colorVector.begin(), colorVector.end(), color),
colorVector.end()
);
You are modifying colorVector during an iteration.
As soon as you remove one of the colors, the vector is suddenly only 4 items in length. Now when you try to go to the 5th item (which was safe to do before the deletion) - it crashes
Try this:
for (int i = 0; i < colorVector.size(); i++) {
if (colorVector.at(i) == color) {
colorVector.erase(colorVector.begin() + i);
--i;
}
}
By stopping at colorVector.size instead of a hard-coded 5 you are ensured that the list never goes out of bounds.
Edit:
Added --i statement to avoid skipping next one
Edit2:
As the comments below state, it is generally a bad idea to remove items from the array you're currently iterating from.

how to improve the efficient of program of crazy guy waiting airplane

I recently wrote a program about the crazy guy waiting airplane question, which says:
A line of 100 airline passengers is waiting to board a plane. They each hold a ticket to one of the 100 seats on that flight. (For convenience, let's say that the nth passenger in line has a ticket for the seat number n.)
Unfortunately, the first person in line is crazy, and will ignore the seat number on their ticket, picking a random seat to occupy. All of the other passengers are quite normal, and will go to their proper seat unless it is already occupied. If it is occupied, they will then find a free seat to sit in, at random.
What is the probability that the last (100th) person to board the plane will sit in their proper seat (#100)?
I did monte carlo to get the answer, but not very efficient, since for the passengers, whose seat is sited. I first get a random number, and then checked from the first seat, if it is sited, then skip that one.
By the way the answer should be 1/2 :)
anybody has a better idea to do this one?
#include <iostream>
#include <vector>
#include <random>
using namespace std;
mt19937 generator;
uniform_real_distribution<double> ranuni(0, 1);
bool test(){
vector<int> line(100, 0);
int remaining(100);
int temp = remaining * ranuni(generator);
if (temp == 99)
return 0;
line[temp] = 1;
--remaining;
for (int i = 1; i < 99; ++i){
temp = remaining * ranuni(generator);
auto itr = line.begin();
while (temp != 0){
++itr;
if (*itr == 0)
--temp;
}
if (itr == line.end()-1)
return 0;
else
*itr = 1;
--remaining;
}
return 1;
}
int main(){
cout << "please input number of simulations" << endl;
int num;
cin >> num;
int sum(0);
for (int i = 0; i < num; ++i)
sum += test();
cout << double(sum) / double(num) << endl;
return 0;
}
I'll offer a couple of thoughts. Probably not a definitive answer, though.
First, I wondered: if you pre-computed a "shuffled" list of plane seats to use, would that help things? The idea being: when a passenger attempts to sit in his/her seat and finds it occupied, you simply pop values off the list until you find one that is unoccupied instead of calling random(). You can pop them off because you don't want later passengers to waste time considering those (occupied) seats either. This means you DO avoid the problem near the end of the line where a random number generator keeps generating occupied seats. (Although, not yours I see, since you deterministically find an unoccupied seat when the assigned seat is occupied). Given such a shuffled list of seat assignments, it is very quick and easy to evaluate the original problem.
The real problem is that generating this "shuffled" list is exactly the same problem as the original one (for ticket# in 0..99, put ticket# in slot(random). Is it occupied? etc.) So, given that generating a nicely shuffled list of seat assignments has the same complexity as the original problem, is there a way we can simplify doing this lots and lots of times?
That brings me to my second thought: once you have one such shuffled list, there are lots of ways of creating other ones, much easier than 100 additional calls to random(). For example, just swap two of the values. The resulting list represents a different run of the problem with slightly different selections by passengers. Do this lots of times and you get many different runs.
The part I can't quite answer, though, is how to ensure the samples you get have a good sampling of the problem space (which is necessary for monte carlo to give you good results). I'll have to leave that for someone else.