Here's my take at the Rock-Paper-Scissors-Lizard-Spock challenge. The outcomes are as follows:
- Scissors cuts paper
- paper covers rock
- rock crushes lizard
- lizard poisons Spock
- Spock smashes scissors
- scissors decapitate lizard
- lizard eats paper
- paper disproves Spock
- Spock vaporizes rock
- rock crushes scissors
I've decided to implement this in procedural form, partly because it's just one player against another. The program doesn't output any of the above outcomes, just generic ones, but I may try to figure out the former at another time. Points are awarded to the winner each turn with the total displayed upon termination. I've also used std::rand()
instead of something "better" (such as std::mt19937
and std::uniform_int_distribution
) since this is a simple program.
My main concerns:
- I feel that there can be a good substitute to
possibleMoves
; it looks quite large. - I couldn't find a good STL function to do the searching in
determineOutcome()
, although what I have now may suffice. - Not enough/not good enough validation to avoid breaking the game.
Other than that, nothing else sticks out to me. Please do criticize anything you may find.
#include <array>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <stdexcept>
#include <string>
#include <utility>
enum Weapon { ROCK=1, PAPER, SCISSORS, LIZARD, SPOCK };
enum Outcome { WIN, LOSE, DRAW };
typedef std::pair<Weapon, Weapon> PlayerMoves;
const std::array<PlayerMoves, 10> possibleMoves =
{ std::make_pair(SCISSORS, PAPER),
std::make_pair(PAPER, ROCK),
std::make_pair(ROCK, LIZARD),
std::make_pair(LIZARD, SPOCK),
std::make_pair(SPOCK, SCISSORS),
std::make_pair(SCISSORS, LIZARD),
std::make_pair(LIZARD, PAPER),
std::make_pair(PAPER, SPOCK),
std::make_pair(SPOCK, ROCK),
std::make_pair(ROCK, SCISSORS)
};
std::istream& operator>>(std::istream& in, Weapon& weapon)
{
int val;
if (in >> val)
weapon = static_cast<Weapon>(val);
else
throw std::logic_error("invalid weapon");
return in;
}
std::ostream& operator<<(std::ostream& out, Weapon const& weapon)
{
switch (weapon)
{
case ROCK: return out << "rock";
case PAPER: return out << "paper";
case SCISSORS: return out << "scissors";
case LIZARD: return out << "lizard";
case SPOCK: return out << "Spock";
default: throw std::logic_error("invalid weapon");
}
}
Weapon getPlayerWeapon()
{
std::cout << "\n\n(1) -> Rock\n";
std::cout << "(2) -> Paper\n";
std::cout << "(3) -> Scissors\n";
std::cout << "(4) -> Lizard\n";
std::cout << "(5) -> Spock\n\n";
Weapon weapon;
do
{
std::cout << "Your move: ";
std::cin >> weapon;
} while (weapon < ROCK || weapon > SPOCK);
return weapon;
}
Weapon getOpponentWeapon()
{
return static_cast<Weapon>(1 + std::rand() % 5);
}
Outcome determineOutcome(PlayerMoves const& playerMoves)
{
if (playerMoves.first == playerMoves.second)
return DRAW;
for (auto iter = possibleMoves.cbegin(); iter != possibleMoves.cend(); ++iter)
{
if (playerMoves == *iter)
return WIN;
}
return LOSE;
}
int main()
{
std::srand(static_cast<unsigned int>(std::time(nullptr)));
std::cout << "Rock, Paper, Scissors, Lizard, Spock\n";
unsigned int playerScore = 0;
unsigned int opponentScore = 0;
for (;;)
{
Weapon playerWeapon = getPlayerWeapon();
Weapon opponentWeapon = getOpponentWeapon();
PlayerMoves playerMoves = std::make_pair(playerWeapon, opponentWeapon);
std::cout << "\n\nYou've picked : " << playerWeapon;
std::cout << "\nComputer picked: " << opponentWeapon;
Outcome outcome = determineOutcome(playerMoves);
switch (outcome)
{
case WIN:
std::cout << "\n\nYou win! Point awarded to you.";
playerScore++;
break;
case LOSE:
std::cout << "\n\nYou lose! Point awarded to opponent.";
opponentScore++;
break;
case DRAW:
std::cout << "\n\nIt's a draw! No points awarded.";
break;
default:
throw std::logic_error("\n\ninvalid outcome");
break;
}
std::cout << "\n\nPlay again (Y/N)? ";
char choice;
std::cin >> choice;
if (choice == 'n' || choice == 'N') break;
}
std::cout << "\n\nFinal Scores:\n\n";
std::cout << "Player : " << playerScore;
std::cout << "\nOpponent: " << opponentScore;
}
bool defeats(Weapon2& a, Weapon2& b) { return ((5 + a - b) % 5) < 3; }
. \$\endgroup\$