#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <regex>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <boost/range/algorithm/stable_partition.hpp>
static constexpr char ErrorThatHandIsNotImplemented[] = "その手は実装されていません。";
enum class Hand
{
Rock = 0, // グー
Scissors, // チョキ
Paper, // パー
First = Rock,
Last = Paper
};
std::ostream& operator<<(std::ostream& os, Hand hand)
{
switch (hand)
{
case Hand::Rock:
os << "グー";
break;
case Hand::Scissors:
os << "チョキ";
break;
case Hand::Paper:
os << "パー";
break;
default:
throw std::runtime_error(ErrorThatHandIsNotImplemented);
}
return os;
}
class Player
{
public:
Player() = default;
Player(const std::string& name, Hand hand);
std::string GetName() const;
Hand GetHand() const;
void SetHand(Hand hand);
friend std::ostream& operator<<(std::ostream& os, const Player& player);
private:
std::string name_;
Hand hand_;
};
Player::Player(const std::string& name, Hand hand)
: name_(name), hand_(hand){ };
inline std::string Player::GetName() const
{
return name_;
}
inline Hand Player::GetHand() const
{
return hand_;
}
inline void Player::SetHand(Hand hand)
{
hand_ = hand;
}
std::ostream& operator<<(std::ostream& os, const Player& player)
{
os << player.name_ << ": " << player.hand_;
return os;
}
std::size_t GetPlayerNumber()
{
std::size_t number = 0;
while (number == 0)
{
std::cout << "プレイヤーの人数を入力してください。: ";
std::string input;
std::getline(std::cin, input);
if (std::regex_match(input, std::regex("[\\d]+")))
{
number = boost::lexical_cast<std::size_t>(input);
}
}
return number;
}
std::vector<Player> MakePlayers(std::size_t number)
{
std::vector<Player> players;
for (std::size_t i = 0; i < number; ++i)
{
// 最初はグー(初期値的な意味で)
players.emplace_back((boost::format("プレイヤー%1%") % (i + 1)).str(), Hand::Rock);
}
return players;
}
void RemoveLosers(std::vector<Player>& players, Hand winners_hand)
{
auto pos = boost::stable_partition(players, [winners_hand](Player& player)
{
return player.GetHand() == winners_hand;
});
players.erase(pos, std::end(players));
};
void Janken(std::vector<Player>& players)
{
std::random_device seed_gen;
std::mt19937 rand_engine(seed_gen());
std::uniform_int_distribution<int> rand_dist(static_cast<int>(Hand::First), static_cast<int>(Hand::Last));
std::size_t round = 1;
// 最後の独りになるまで戦え……
while (players.size() != 1)
{
std::cout << std::endl;
std::cout << "第" << round << "回戦" << std::endl;
++round;
for (auto& player : players)
{
player.SetHand(static_cast<Hand>(rand_dist(rand_engine)));
}
std::size_t rock_players_counter = 0;
std::size_t scissors_players_counter = 0;
std::size_t paper_players_counter = 0;
for (auto& player : players)
{
std::cout << player << std::endl;
switch (player.GetHand())
{
case Hand::Rock:
++rock_players_counter;
break;
case Hand::Scissors:
++scissors_players_counter;
break;
case Hand::Paper:
++paper_players_counter;
break;
default:
throw std::runtime_error(ErrorThatHandIsNotImplemented);
}
}
if ((rock_players_counter == players.size()) ||
(scissors_players_counter == players.size()) ||
(paper_players_counter == players.size()))
{
// あいこ
}
else
{
if (rock_players_counter == 0)
{
// グーがいなければ、チョキのプレイヤーだけ生き残り
RemoveLosers(players, Hand::Scissors);
}
else if (scissors_players_counter == 0)
{
// チョキがいなければ、パーのプレイヤーだけ生き残り
RemoveLosers(players, Hand::Paper);
}
else if (paper_players_counter == 0)
{
// パーがいなければ、グーのプレイヤーだけ生き残り
RemoveLosers(players, Hand::Rock);
}
else
{
// あいこ
}
}
}
std::cout << std::endl;
std::cout << "勝者: " << players[0].GetName() << std::endl;
}
int main()
{
int result = 0;
try
{
std::size_t number = GetPlayerNumber();
std::vector<Player> players = MakePlayers(number);
Janken(players);
}
catch(const std::exception& ex)
{
std::cout << "ゲームを継続できません。" << std::endl;
std::cout << ex.what() << std::endl;
result = 1;
}
std::cout << "Enterキーを押すと終了します。" << std::endl;
std::string ignore;
std::getline(std::cin, ignore);
return result;
}