Rock Paper Scissors Game for PPP 2

I wrote this with srand() and rand(), since I know it best with that, but the book says to use a vector holding the integers 1, 2 and 3 and have the program use that to "randomly" generate the next Rock, Paper or Scissors. The book says to use the vector since "true randomness is hard to provide just now" (the book hasn't covered random number generation yet).

Here's the exercise specification:
Write a program that plays the game “Rock, Paper, Scissors.” If you are not
familiar with the game do some research (e.g., on the web using Google).
Research is a common task for programmers. Use a switch -statement to
solve this exercise. Also, the machine should give random answers (i.e.,
select the next rock, paper, or scissors randomly). Real randomness is too
hard to provide just now, so just build a vector with a sequence of values
to be used as “the next value.” If you build the vector into the program,
it will always play the same game, so maybe you should let the user en-
ter some values. Try variations to make it less easy for the user to guess
which move the machine will make next.

Here's my code right now, which seems to run pretty well but uses rand() and srand():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Osman Zakir
// 12 / 25 / 2016
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 4 Exercise 10
// Exercise Specifications:
/**
 * Write a program that plays the game “Rock, Paper, Scissors.” If you are not
 * familiar with the game do some research (e.g., on the web using Google).
 * Research is a common task for programmers. Use a switch -statement to
 * solve this exercise. Also, the machine should give random answers (i.e.,
 * select the next rock, paper, or scissors randomly). Real randomness is too
 * hard to provide just now, so just build a vector with a sequence of values
 * to be used as “the next value.” If you build the vector into the program,
 * it will always play the same game, so maybe you should let the user enter 
 * some values. Try variations to make it less easy for the user to guess
 * which move the machine will make next.
 */

#include "../../std_lib_facilities.h"

void play(int player_move, int computer_move);
int get_input();

int main()
{
	cout << "Welcome to this Rock-Paper-Scissors Game! Just press a 1 for 'Rock', 2 for "
		<< "'Paper' and 3 for 'Scissors'!\n";
	int computer_move = 0;
	int player_move = 0;
	char answer = ' ';
	do
	{
		player_move = get_input();
		computer_move = (rand() % 3) + 1;
		play(player_move, computer_move);
		cout << "Would you like to continue playing? (Y/N): ";
		cin >> answer;
		cin.ignore();
	} 
	while (answer == 'y' || answer == 'Y');
	keep_window_open();
}

void play(int player_move, int computer_move)
{
	time_t t;
	srand(static_cast<unsigned int>(time(&t)));
	rand();
	rand();
	switch (computer_move)
	{
	case 1:
		if (player_move == 1)
		{
			cout << "Computer chose Rock.\nPlayer chose Rock.\n";
			cout << "That's a tie.  Try again.\n";
		}
		else if (player_move == 2)
		{
			cout << "Computer chose Rock.\nPlayer chose Paper.\n";
			cout << "Congratulations! You win!\n";
		}
		else if (player_move == 3)
		{
			cout << "Computer chose Rock.\nPlayer chose Scissors.\n";
			cout << "Sorry! You lose! Better luck next time.\n";
		}
		break;
	case 2:
		if (player_move == 1)
		{
			cout << "Computer chose Paper.\nPlayer chose Rock.\n";
			cout << "Sorry! You lose! Better luck next time.\n";
		}
		else if (player_move == 2)
		{
			cout << "Computer chose Paper.\nPlayer chose Paper.\n";
			cout << "That's a tie. Try again.\n";
		}
		else if (player_move == 3)
		{
			cout << "Computer chose Paper.\nPlayer chose Scissors.\n";
			cout << "Congratulations! You win!\n";
		}
		break;
	case 3:
		if (player_move == 1)
		{
			cout << "Computer chose Scissors.\nPlayer chose Rock.\n";
			cout << "Congratulations! You win!\n";
		}
		else if (player_move == 2)
		{
			cout << "Computer chose Scissors.\nPlayer chose Paper.\n";
			cout << "Sorry! You lose! Better luck next time.\n";
		}
		else if (player_move == 3)
		{
			cout << "Computer chose Scissors.\nPlayer chose Scissors.\n";
			cout << "That's a tie.  Try again.\n";
		}
		break;
	}
}

int get_input()
{
	int player_move = 0;
	do
	{
		cout << "Make your move now (you will continue to be prompted until "
			<< "you cooperate): ";
		cin >> player_move;
		cin.ignore();
	} 
	while (player_move != 1 && player_move != 2 && player_move != 3);
	return player_move;
}


So yeah, how should I have this follow the exercise specification more? Thanks for any help you guys can give me on this.
Last edited on
closed account (L1vUM4Gy)
Here's my code right now, which seems to run pretty well but uses rand() and srand()

So what is your problem?
Why does your professor care about "true randomness"? What would be the problem if it is "true randomness" or something else?
The problem is exactly as I said: I just want to know how to do this with a vector and without rand(). Since that's what the exercise seems to be asking for. Or maybe I shouldn't care about that now since I can do it with rand()?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
enum class Move{ rock = 1, paper, scissors };

int get_seed()
{
    int seed{};
    do {
        cout << "enter seed: ";
        cin >> seed;
    } while( cin && seed == 0 );

    if( !cin ) {
        cin.clear();
        cin.ignore( numeric_limits<streamsize>::max(), '\n' );
    }
    return seed;
}

vector<Move> get_computer_moves( int seed, int num_rounds )
{
    if( num_rounds <= 0 ) {
        cerr << "number of rounds must be positive";
        return {};
    }

    vector<Move> moves{};
    for( int i{}; i < num_rounds; i++, seed++ )
        moves.push_back( static_cast<Move>( abs( seed ) % 3 + 1 ) );

    return moves;
}

int main()
{
    int seed{ get_seed() };
    auto computer_moves = get_computer_moves( seed, 10 );
    for( auto m : computer_moves )
        cout << static_cast<int>( m ) << ' ';
}


enter seed: 123
1 2 3 1 2 3 1 2 3 1  

enter seed: -100
2 1 3 2 1 3 2 1 3 2  

The problem is, is that the moves repeat themselves.

Also, no magic values. Either, define constants or use an enum.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
enum class Outcome{ lose = -1, tie, win };

Outcome play_round( Move player, Move computer )
{
    switch( player )
    {
    case Move::rock:
        switch( computer )
        {
        case Move::rock:
            return Outcome::tie;

        case Move::paper:
            return Outcome::lose;

        case Move::scissors:
            return Outcome::win;
        }
        break;

    case Move::paper:
        switch( computer )
        {
        case Move::rock:
            return Outcome::win;

        case Move::paper:
            return Outcome::tie;

        case Move::scissors:
            return Outcome::lose;
        }
        break;

    case Move::scissors:
        switch( computer )
        {
        case Move::rock:
            return Outcome::lose;

        case Move::paper:
            return Outcome::win;

        case Move::scissors:
            return Outcome::tie;
        }
        break;
    }
}

Last edited on
Right, I'll define a constant, then. Thanks for pointing that out. I think I'll leave the rest as it is.

Just that, I used rand() twice and discarded the result that way because I've heard that there's a problem on Windows systems that makes it so that unless you call it like that at least once, even using the current time as the seed won't make the numbers truly random. It'd be appreciated if someone who also knows they have that problem with rand() on their end could clarify for me if calling rand() twice is okay or if I should change it to just once (since I've heard that calling it once should be enough, but I've also seen that I may have to call it twice - but I'm not sure about that).
Topic archived. No new replies allowed.