Click to See Complete Forum and Search --> : Simple question (involving rand() i think)


jaeger
August 14th, 2002, 01:17 PM
I'm making a black jack program as an excersize (mostly in structures and such) and i'm having a problem with the deal() method.

the problem seems to be that a) the random number seems to be 13 all the time ('k' is the output twice) and after i enter anything for the cin, it gives me a bus error and quits. any ideas?

(the player struct has a few ints (money, bet) and the name and hand (a 2-element array) for the player.)

this is the code for that method:
void deal(person player)
{
int i;
char askhit[3];
cout<<"You got: ";
for(i = 0; i < 3; i++) {
player.hand[i] = (rand()%13 + 1);
if (player.hand[i] == 11) player.hand[i] = 'j';
if (player.hand[i] == 12) player.hand[i] = 'q';
if (player.hand[i] == 13) player.hand[i] = 'k';
cout<<player.hand[i]<<" ";
}
cout<<endl;

do {
cout<<"Would you like to hit?"<<endl;
cin>>askhit>>endl;
if (askhit[0] == 'y' || askhit[0] == 'Y') hit(player);
} while (askhit[0] == 'y' || askhit[0] == 'Y');

}

kuphryn
August 14th, 2002, 01:30 PM
What kind of data type is hand? You are assign hand with an integer and assign it a character.

Kuphryn

jaeger
August 14th, 2002, 01:37 PM
char hand[2];

can't chars hold ints and characters?
katy

kuphryn
August 14th, 2002, 04:37 PM
No, a character cannot be an integer. An array of characters can be "13," but you will need a function like atoi() to convert it to an integer 13.

In your algorithm, use a temp integer to hold the random number.

Kuphryn

jaeger
August 14th, 2002, 07:29 PM
oh, ok... so what should i do to convert only the digits 11-13 to the chars 'j, q, k' respectively (or 'jack, queen, king' if it doesn't make much difference)?

kuphryn
August 14th, 2002, 07:49 PM
I made some changes to your algorithm.

-----
void deal(person player)
{
int randNum = 0;
char askhit[3];
cout<<"You got: ";
for(int i = 0; i < 3; ++i)
{

// I assume you want random [1, 13]
randNum = static_cast<int>(((static_cast<double>(rand())) / (static_cast<double>(RAND_MAX + 1))) * 13 + 1);

if (randNum == 11)
player.hand[i] = 'j';

if (randNum == 12)
player.hand[i] = 'q';

if (randNum == 13)
player.hand[i] = 'k';

cout<<player.hand[i]<<" ";
}
-----

Kuphryn

Graham
August 15th, 2002, 04:33 AM
A character can hold an integer: a signed char can hold a value in the range -128..+127 and an unsigned char can hold a value in the range 0..255. Where your code goes wrong is that you use 'j', 'q' and 'k' for the court cards, but you don't use '1', '2', etc for the others. In ASCII coding, the character '1' has the value 49, '2' has the value 50 and so on. So, for consistency your code should read:

player.hand[i] = (rand()%13 + 1);
if (player.hand[i] == 11)
player.hand[i] = 'j';
else if (player.hand[i] == 12)
player.hand[i] = 'q';
else if (player.hand[i] == 13)
player.hand[i] = 'k';
else if (player.hand[i] == 10)
player.hand[i] = '0'; // Needs a single char representation for "10"
else
player.hand[i] += '0'; // Get character representation of value.

Characters whose values lie between 0 and 31 (in ASCII) are generally not printable characters, so you won't see many of them in your printout (you might get the odd tab character coming out).

The more serious problem is that you say that "hand" is declared as char hand[2], yet you are accessing it in a loop that goes from 0 to 2 - i.e. you're going out of bounds in the array access.

A secondary problem is that you are not modelling a deck of cards: since each card you "deal" is simply a random number between 1 and thirteen, there is no account taken of the loss of a card once it has been "dealt" - e.g. if you deal the king of hearts, then you can't deal it again until the pack has been restored. A better approach may be to model a full deck, then randomise it and just keep picking cards off the top to deal them.

jaeger
August 15th, 2002, 09:03 AM
ok... that code makes sense. and yeah, the deck problem is something i planned to tackle maybe in my second edition of the program. but since you brought it up, how would you suggest i do it? i just started working in C++ so i don't know much about the possibilities for stacks or things like that that would model a real deck.

thanks kuphryn and Graham for your help!
katy

jfaust
August 15th, 2002, 11:09 AM
One way to do it, which conceptually maps well to the real world, is to use std::vector of Cards, which is basically what a deck is.


enum Suit
{
Hearts,
Diamonds,
Clubs,
Spades
};

struct Card
{
Suit suit;
unsigned int value;
}

typedef std::vector<Card> Deck;

....

Deck deck;


Initialize the deck by filling it with all the cards.

When dealing, pick a random number from the total remaining cards. When it's dealt, remove it from the deck.

Sounds like a fun problem to work on.

Jeff

jfaust
August 15th, 2002, 11:11 AM
Or, even better, initialize the deck and then "shuffle" it, which will randomly reorder it. Then deal off the top.

The closer a solution models the real world the better. Now, you just need free drinks and good buffets...

Jeff

Paul McKenzie
August 15th, 2002, 01:43 PM
To add to Jeff's suggestion, use the random_shuffle() algorithm function to shuffle the deck.

#include <algorithm>
#include <vector>
//...
typedef std::vector<Card> Deck;

using namespace std;

int main()
{
Deck deck(52);
//...Assume it is initialized
random_shuffle(deck.begin(), deck.end()); // Shuffle the cards
}

Regards,

Paul McKenzie

AnthonyMai
August 15th, 2002, 03:42 PM
<B>It is an extremely bad idea to use Paul's random_shuffle() function to shuffle the deck as the OP requested.</B> Actually it is so bad that you are going to lose big money on the bets.

Why? The OP's intend was clearly trying to shuffle the deck in a [B]random and un-predictable</B> way that no one can guess the cards, for the purpose of gaming or gambling. When you use random_shuffle(), the result is quite predictable, causing your opponent to always been able to guess your card and win your money.

There was precedence, a couple of years ago an on-line gambling site so trusted the security of their deck shuffling algorithm that they published the code publicly, the result was it was cracked without a huzzle and every card was completely predictable. It was a true story. The problem was not with the algorithm itself, but with the random number generator.

The rand() function may be useful for statistics purpose. But it is totally useless when it comes to cryptographically secure applications. It's sequence is completely predictable, especially when it has not been seeded. random_shuffle() relies on rand() internally, and hence it is unsafe.

Designing a cryptographically secure application is very difficult. It all boils down to introducing un-predictable elemements into the system, which in physics is called entropy.

It is very hard to obtain entropy on a computer because all computers are deterministic, virtually all methods of collection entropy on a computer involves some sort of highly platform dependent component.

For example, on a PC, you can use the RDTSC to get the current clock count, you can scan the whole memory space to get a checksum, you can measure the accurate time interval between two key strikes, etc. and a good thing to do is hash your data a couple of thousand times before you seed your random number generator. And above all, never use rand() or any thing that relies on rand().

To sum up, I do not see how random_shuffle() in STL has any real usage, except for as some homework assignment for students.

AnthonyMai
August 15th, 2002, 03:48 PM
I suggest people read Counterpane's CryptoGram and other security/cryptography related literatures. Very few people know any thing at all about concepts in the cryptography field, that is a big problem today when the IT is more and more vulnerable to information technology security flaws.

http://www.counterpane.com/crypto-gram.html

jfaust
August 15th, 2002, 03:53 PM
Most uses of random numbers don't need to be secure. Usually you just want a decent distribution of results

Case in point is the OP, which is a game. This is a perfectly good use for rand(). Unless this is going to be used for actually gambling for cash, it satisfies all the needs of a game.

But true, coming up with good random numbers is difficult, which can be seen by the large range of available pseudo-random number generators. Even with these, it is very important (and difficult) to pick a good starting value.

But in this case, rand() is completely suitable, as is random_shuffle<>.

Jeff

jfaust
August 15th, 2002, 04:02 PM
Furthermore, random_shuffle can take a predicate argument, so you don't need to use rand().

Jeff

PaulWendt
August 15th, 2002, 04:13 PM
Originally posted by AnthonyMai
[B]<B>It is an extremely bad idea to use Paul's random_shuffle() function to shuffle the deck as the OP requested.</B>

On the contrary, I think it is an extremely good idea to use Paul's
random_shuffle() function. The original poster stated:
"I'm making a black jack program as an excersize [sic]...."

This is clearly not a complicated gamgling simulation; nor is it
going to be a security/crypography piece of software.

I don't understand why you'd bother to make this post, given the
fact that you stated:
"To sum up, I do not see how random_shuffle() in STL has any real usage, except for as some homework assignment for students."

This is exactly what the original poster is doing: doing an exercise
so that [s]he can learn about C/C++. My guess is that you're
still going about trying to make Paul McKenzie look bad.
Unfortunately, you've failed at this attempt too; better luck next
time.

--Paul

Paul McKenzie
August 15th, 2002, 04:58 PM
Originally posted by jfaust
Furthermore, random_shuffle can take a predicate argument, so you don't need to use rand().

Jeff Hello Jeff,

Anyone who is versed in standard C++ would have known this or would have taken just a few seconds to look it up. Here is the definition, for those who wish to criticize before they research:

http://www.sgi.com/tech/stl/random_shuffle.html

Note the second definition which takes a predicate.

Regards,

Paul McKenzie

Graham
August 15th, 2002, 05:01 PM
One of the guarantees given in the standard for random_shuffle is that any given random sequence from N objects has a probability of appearing of exactly 1/N! - i.e there is no "clumpiness" to the result: it's evenly distributed over all possibilities.

BTW, I wouldn't use a vector<card>, I'd use a deque<card> :D .

Graham
August 15th, 2002, 05:02 PM
Paul got his reply in as I was typing mine - look at the link under "Notes" for the behaviour guarantee.

jfaust
August 15th, 2002, 05:13 PM
Graham,

Do you recommend deque because you simply can't resist a pun, or is it because a certain someone says that nobody ever uses deque? ;)

Actually a deque would work better here since you are only taking off the end. vector would be preferrable if I didn't improve my first example by shuffling, as random access in a deque is done in linear time, not constant time.

Although I fear shuffling a deque might be slower.

Jeff

Bob Davis
August 15th, 2002, 05:24 PM
Instead of using if/else statements or switch/case statements to determine the card, why not create an enum type for the card's value? I remember in a C++ class I took, it was the professor's example for creating an enum.


enum Value
{
One = 1,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
Ace
};


Makes it a bit prettier to output that way. Ignore it if you like, I just always love a good enum.

jfaust
August 15th, 2002, 05:36 PM
I agree. An enum works well here. Then when you have a method to, say, get the numeric value of the card, the switch statement can reference Ten, Jack, Queen and King for value of 10 instead of integers.

Jeff

Graham
August 16th, 2002, 03:31 AM
Jeff: I could argue that I foresaw a member function called cheat() that dealt off the bottom, but really I just liked the pun.

jaeger
August 16th, 2002, 09:22 AM
This got into quite the discussion... no, I don't need a hardcore, secure randomizer. I just want to shuffle a deck a little.

I've never used enum (I'm really a beginner, so I apologize for asking really basic question), so how does it work? do I put it outside all the functions and then it is accessible from deal() and it just treats it like a constant?

(and out of curiosity: what's a deque?)

Thanks everyone!
katy

Graham
August 16th, 2002, 10:03 AM
a deque is a Double-Ended QUEue (pronounced "deck", hence the pun).

You can think of an enum as a way of declaring lots of constants in one go. there's a bit more to it than that but, at this stage, it'll do. I'm not sure that an enum provides too much value for money in this case (apart from what Jeff said about referring to Jack, etc, in the code), but it's not a bad idea to learn about them.

With a properly object-oriented design, you'll often find enums declared inside classes (it's also a work around for one of VC++'s many failings).

class some_class
{
public:
enum { relevant_constant1 = 1, relevant_constant2 = 17 };
// etc;
};

// then refer to the values in code as:

if (some_value == some_class::relevant_constant1)
{
// whatever
}

AnthonyMai
August 16th, 2002, 02:08 PM
Do you recommend deque because you simply can't resist a pun, or is it because a certain someone says that nobody ever uses deque?


I guess you refered me for that someone. Once again you are putting words into my mouth. I am not God, I do not have the capability of surveying every walk of life on this planet to find out who uses what and who doesn't use what. Therefore I never make such assertions like "no body uses so and so" or "no body does so and so".

Read my lips! What I said was:
There is NOT a single thing in this world that any one can think of that can NOT be done WITHOUT using deque.

So there is this strange two-headed snake called deque. So what? Two-headed snakes do exist. Is that a big deal? What about three-headed snake?

Deque is a fancy invention. But I don't see it any more useful than a tri-que, quad-que, quant-que, or even deca-que, hexa-que. You can invent any thing you want. But it remains that anything that you do using deque CAN BE DONE WITHOUT it, with NO sacrifice of convenience or code efficiency or readability whatsoever.

Graham
August 16th, 2002, 03:19 PM
Yeah. And all languages are equally powerful. There's no program that you can write in C++ that can't be written in FORTRAN or COBOL or PL1 or whatever. We don't need classes, recursion, bitwise operators, switch statements or any other paraphenalia of modern languages. All you need is a conditional statement, a loop construct that can be potentially infinite, a goto statement, somewhere to put your data and some basic manipulation methods. There is NOT a single thing in this world that anyone can think of that can NOT be done WITHOUT using C++. Now, anyone know where I can get a copy of masm?

AnthonyMai
August 16th, 2002, 03:36 PM
Graham:

You know I talked bout deque in the context of C++ programming. I am not talking about lawyers or doctors using deque. I am talking about programmers doing C++ programming.

Can you tell me just one thing that using deque is superior than using other method? The mere fact that a lot of C++ programmer would ask "just what is deque" says how rarely deque is ever used at all.

Talking about assembly, it is a fact that this IT world can live without Java, or C++.net or VBScript or any other high level languages. But the IT simply can NOT live without the assembly language. It is as true as programming languages is useless without the existance of CPUs.

Yves M
August 16th, 2002, 04:17 PM
Well, if you're using a stack, would you rather use a vector instead of a deque ?

The point of deque is that when you use it, you know that you're only supposed to take stuff off the end (or beginning) and add stuff there. It is a self-imposed restriction that makes for nicer and better readable code.

Why do people write comments in their code ? They are totally useless, they are even ignored by the compiler ! Hum, weird, isn't it ?

jfaust
August 16th, 2002, 08:02 PM
I used deque recently for creating and undo/redo stack. It had everything I needed.

And Anthony, you do use definitives such as "always". It's one of the things I dislike most about your posts.


Therefore I never make such assertions


Which is an assertion as well as false.

Jeff

cup
August 17th, 2002, 01:36 AM
Haven't written card games since Uni. Anyway, this is how I used to do it.

// Declare a deck of cards
const int VALMAX = 13; // 14 for some European sets
const int SUITMAX = 4;
const int DECKMAX = VALMAX * SUITMAX;
int deck[DECKMAX];

// Initialize the deck
remain = DECKMAX;
for (int i = 0; i < remain; i++)
deck[i] = i;

// Deal the next one
int choice = rand () % remain;
card = deck[choice];
// replace the chosen card with the last card in the remaining deck
remain--;
deck[choice] = deck[remain];

// Decoding
int value = card % VALMAX;
int suit = card / VALMAX;

It is sort of inline shuffling.

jaeger
August 19th, 2002, 12:07 PM
i'm sorry again, but what's a vector? i'm familiar with it in terms of math (as in, a magnitude and direction), but is that what a vector in C++ is?
thanks,
katy

cup
August 19th, 2002, 12:18 PM
In STL, you can think of it as an array where you don't need to worry about the size. For instance, you could start with an array of integers with no elements

vector<int> victor;

To add an element, say 200, into the vector

victor.push_back (200);

It will grow to the appropriate size. To retrieve the 10 element

int xxx = victor[9];

To modify the values

victor[9] = something;

That is about as simple as I can make it.