I made a Rock Paper Scissors game. It works fine but I would like to know how can I improve it further.
#include <iostream>
#include <algorithm>
#include <string>
#include <random>
#include <array>
#include <map>
#include <limits>
namespace
{
enum Winner { Tie, Player, Computer, WinnerCount };
enum Items { Rock, Paper, Scissors, ItemsCount };
template<typename T, std::size_t N>
using Matrix = std::array<std::array<T, N>, N>;
}
std::string user_choice(const std::array<std::string, Items::ItemsCount>& data)
{
std::string result;
static auto comp = [&result](const std::string& str) { return str == result; };
bool is_input_valid = false;
do
{
std::cout << "Enter your choice, rock, paper, or scissors: ";
std::getline(std::cin, result);
is_input_valid = !(std::cin.fail() || std::none_of(data.begin(), data.end(), comp));
if (!is_input_valid) {
std::cout << "Not valid input.\n";
}
std::cin.clear();
std::cin.ignore(std::cin.rdbuf()->in_avail());
} while (!is_input_valid);
return result;
}
bool play_again()
{
char result;
bool is_input_valid = false;
do
{
std::cout << "Do you want to play again? [y/n]: ";
std::cin >> result;
result = std::toupper(result);
is_input_valid = !(std::cin.fail() || (result != 'Y' && result != 'N'));
if (!is_input_valid)
{
std::cout << "Not valid input.\n";
}
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} while (!is_input_valid);
return result == 'Y';
}
int main()
{
// Set up game
const Matrix<Winner, Winner::WinnerCount> table
{
{ // Rock Paper Scissors
{ Tie, Computer, Player }, // Rock
{ Player, Tie, Computer }, // Paper
{ Computer, Player, Tie }, // Scissors
}
};
const std::array<std::string, Items::ItemsCount> data
{
"rock",
"paper",
"scissors"
};
std::map<std::string, Items> binding_items
{
{ data[Items::Rock], Items::Rock },
{ data[Items::Paper], Items::Paper },
{ data[Items::Scissors], Items::Scissors },
};
const std::array<std::string, Winner::WinnerCount> winner_result
{
"It's a tie!\n\n",
"You win!\n\n",
"You lose!\n\n"
};
std::mt19937 engine{ std::random_device()() };
auto dist = std::uniform_int_distribution<>(0, Items::ItemsCount - 1);
// Game loop
do
{
std::cout << "\n\n\tRock Paper Scissors Game\n\n";
const auto user_chose = user_choice(data);
const Items player = binding_items[user_chose];
const Items computer = static_cast<Items>(dist(engine));
const auto computer_chose = data[computer];
std::cout << "\n\nYou entered: " << user_chose << '\n';
std::cout << "Computer chose: " << computer_chose << '\n';
std::cout << winner_result[table[player][computer]];
} while (play_again());
}