Monday, 1 August 2016

Chapter 4 // Exercise 10 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 4 Exercise // 4.10

Write a program that plays the game "Rock, Paper, Scissors." 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 to hard to provide just now, so just build a vector with a sequence of values to be used as the "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 "stdafx.h"
#include "std_lib_facilities_new_version.h"
using namespace std;


int main()
{
//create comp moves
cout << "We're going to play Rock, Paper, Scissors.\n";
cout << "First the computer needs some moves. How many moves should the pc have?:\n";
int compMoves = 0;
cin >> compMoves;

vector<char> moves;

cout << "\nOk. Please enter 'r', 'p' or 's':\n";

for (int i = 0; i < compMoves; ++i)
{
char rps;
cin >> rps;
if (rps != 'p' && rps != 'r' && rps != 's')
{
cout << "Sorry, invalid input. Try again: \n";
cin >> rps;
}
moves.push_back(rps);
}

//play the game
char loop = 'y';

while(loop == 'y')

cout << "\nLets play! Enter 'r', 'p' or 's': \n";
char playerMove;
int plays = 0; 
int cm2 = compMoves;
char compMove = moves[cm2 - 1];
cin >> playerMove;

cout << "\nYour move: " << playerMove << " || Comp Move: " << compMove << endl;

switch (playerMove)
{

case 'r':
switch (compMove)
{
case 'r':
cout << "Tie!! r1\n";
break;
case 's':
cout << "You win!r2\n";
break;
case 'p':
cout << "I win!r3\n";
break;
}
break;

case 'p':
switch (compMove)
{
case 'p':
cout << "Tie!!p1\n";
break;
case 'r':
cout << "You win!p2\n";
break;
case 's':
cout << "I win!p3\n";
break;
}
break;

case 's':
switch (compMove)
{
case 's':
cout << "Tie!!s1\n";
break;
case 'p':
cout << "You win!s2\n";
break;
case 'r':
cout << "I win!s3\n";
}
break;

default:
cout << "Sorry, not recogised.\n";
break;
}

--cm2;
++plays;
//reset comp moves so it doesn't go out of vector range
if (plays > compMoves) { cm2 == compMoves; plays = 0; }

cout << "Would you like to play again? y /n: \n";
cin >> loop;

while (loop != 'y' && loop != 'n')
{
cout << "Sorry, not recognised. Try again. y / n: \n";
cin >> loop;
}

}

cout << "Thanks for playing!\n";
keep_window_open();

return 0;
}

This one did my freaking nut in. I spent bloody hours on it and when it finally worked it was just so simple I wanted to bash my head in with the book. My main problem was I constantly kept going out of the vector range and my original while loop got stuck in an infinite loop. Once you've figured it out though, it is actually quite easy, it just sounds hard.

EDIT 18/03/2018

So exercise 11 of chapter 7 has us revisit 2 exercises of your choice from chapter 4 or 5, This was one of the ones I chose. First off I noticed that everything is done in main(). If there's one thing I've learnt over the chapters it's that a function should only have 1 purpose.

#include "stdafx.h"
#include "std_lib_facilities.h"
#include <Windows.h>
#include <time.h>

vector<char> rps = { 'r', 'p', 's'}; //assign a vector with rock, paper and scissors

//---------------------------------CLASS PC Moves//
class PCMoves
{
public:
void setMoves();
char playMove();

vector<char> moveset;
int compMoves;
};

//set the computer moves using number set in getMoves() and rand()
void PCMoves::setMoves()
{
char move;
int min = 0;
int max = 2;
int randNum;

//for each move, get a random move from the rockpaperscissors vector and push it into moveset
//pc is given 100 different options to choose from
for (int i = 0; i < 100; ++i)
{
randNum = rand() % (max - min + 1) + min; //get a random number between 0 and vector size
move = rps[randNum];   //move found at randNum number is assigned to move
PCMoves::moveset.push_back(move);       //that move is then pushed into moveset
}

return;
}

//returns a move from the pc's moveset
char PCMoves::playMove()
{
int min = 0;
int max = 99; //due to vectors starting at 0, we gave it 100 options
int randNum = rand() % (max - min + 1) + min;

return PCMoves::moveset[randNum];       //return a random move in the given moveset
}

PCMoves pcMoves;
//-------------------------------------END PC Moves//

//----------------------------------CLASS Play Game//
class PlayGame
{
public:
char getPlayerMove();
void checkMoves();
void playGame();
char playAgain();

char playerMove;
char yesNo;
};

//get a move from the player
char PlayGame::getPlayerMove()
{
cout << "\nEnter 'r', 'p' or 's':\n>";
cin >> PlayGame::playerMove;

while (PlayGame::playerMove != 'r' && PlayGame::playerMove != 'p' && PlayGame::playerMove != 's')
{
cout << "Sorry, that's not a correct move. Try again.\n>";
cin >> PlayGame::playerMove;
}

return PlayGame::playerMove;
}

//compare player to computer move to see who won
void PlayGame::checkMoves()
{
char playerMove = PlayGame::getPlayerMove(); //get a move from the player
char compMove = pcMoves.playMove(); //get a move from the pc

cout << "\nYour move: " << playerMove << " || Comp Move: " << compMove << endl;

//see who won
switch (PlayGame::playerMove)
{

case 'r':
switch (compMove)
{
case 'r':
cout << "Tie!!\n";
break;
case 's':
cout << "You win!\n";
break;
case 'p':
cout << "I win!\n";
break;
}
break;

case 'p':
switch (compMove)
{
case 'p':
cout << "Tie!!\n";
break;
case 'r':
cout << "You win!\n";
break;
case 's':
cout << "I win!\n";
break;
}
break;

case 's':
switch (compMove)
{
case 's':
cout << "Tie!!\n";
break;
case 'p':
cout << "You win!\n";
break;
case 'r':
cout << "I win!\n";
}
break;

default:
cout << "Sorry, not recogised.\n";
break;
}

return;
}

//ask users if they want to play again
char PlayGame::playAgain()
{
cout << "\nWould you like to play again? y /n: \n>";
cin >> PlayGame::yesNo;

while (yesNo != 'y' && yesNo != 'n')
{
cout << "Sorry, not recognised. Try again. y / n: \n>";
cin >> yesNo;
}

return yesNo;
}

void PlayGame::playGame()
{
cout << "We're going to play Rock, Paper, Scissors.\n";

//create compMoves
pcMoves.setMoves();
//continue to play until numOfMoves runs out or users wants to quit
while (PlayGame::yesNo != 'n')
{
//get moves from each player and compare the moves to see who won
PlayGame::checkMoves();

//ask users if they want to continue playing
PlayGame::yesNo = PlayGame::playAgain();
}

cout << "\nThanks for playing!\n";
Sleep(2000); //pause program for 2 seconds before closing

return;
}

PlayGame game;
//-----------------------------------------END Play Game//

//start program
int main()
{
//set seed for rand() based on pc's current time
srand(time(NULL));

//play game
game.playGame();

return 0;
}

The code is a lot bigger however, everything is done from within 2 classes and has appropriate error checking. I also changed the program so that instead of giving the pc a number of moves to create a 'random looking' sequence, it now pushes back 100 choices into a vector from another vector containing r, p or s. This provides almost real randomness to the pc's choices instead of choosing what it might select.

Most functions now only have 1 purpose; to either set or get values, check values or play the game. I wrote this code pretty much off the top of my head in about 40 minutes which is kind of shocking because I remember how long it took me to do this originally and how frustrated I got. It's crazy to think that practice and studying really do pay off. It also showed me some logic errors from the first time round and made me think "why did I do it that way?" But it's all a part of the learning process.

1 comment:

  1. I am stuck on this one.
    I didn't understand the instructions.

    I understood everything until it came to making it random.
    I saw how he did the problem on his site, but he didn't explain any of that in the chapter.

    Thanks for publishing this, this helps. Keep being awesome.

    ReplyDelete