Created
March 10, 2014 03:39
-
-
Save Rapptz/9459087 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <vector> | |
#include <string> | |
#include <algorithm> | |
#include <random> | |
#include <map> | |
#include <stdexcept> | |
#include <functional> | |
#include <cstdlib> | |
void print(const char* str) { | |
while(*str) { | |
if(*str == '%') { | |
if(*(str + 1) == '%') { | |
++str; | |
} | |
else { | |
throw std::runtime_error("invalid format string: missing arguments"); | |
} | |
} | |
std::cout << *str++; | |
} | |
} | |
template<typename T, typename... Args> | |
void print(const char* str, T&& value, Args&& ... args) { | |
while(*str) { | |
if(*str == '%') { | |
if(*(str + 1) == '%') { | |
++str; | |
} | |
else { | |
std::cout << std::forward<T>(value); | |
print(str + 1, std::forward<Args>(args)...); | |
return; | |
} | |
} | |
std::cout << *str++; | |
} | |
throw std::logic_error("extra arguments provided to print"); | |
} | |
struct Card { | |
private: | |
int att = 1; | |
int def = 1; | |
public: | |
constexpr Card() = default; | |
constexpr Card(int attack, int defence = 1): att(attack), def(defence) {} | |
friend auto operator<<(std::ostream& out, const Card& c) -> decltype(out) { | |
return out << "ATT: " << c.att << ", DEF: " << c.def << "\n"; | |
} | |
constexpr bool dead() noexcept { | |
return def <= 0; | |
} | |
void battle(Card& other) { | |
other.def -= att; | |
def -= other.att; | |
} | |
}; | |
static std::random_device rd; | |
static std::mt19937 g(rd()); | |
struct Deck { | |
private: | |
std::vector<Card> cards; | |
public: | |
Deck(): cards(20) { | |
std::generate(std::begin(cards), std::end(cards), [] { | |
static std::uniform_int_distribution<> gen(1, 20); | |
return Card{ gen(g), gen(g) }; | |
}); | |
} | |
Card draw() { | |
if(cards.empty()) { | |
return {}; | |
} | |
Card copy = cards.back(); | |
cards.pop_back(); | |
return copy; | |
} | |
void shuffle() { | |
std::shuffle(std::begin(cards), std::end(cards), g); | |
} | |
bool empty() { | |
return cards.empty(); | |
} | |
auto cards_left() -> decltype(cards.size()) { | |
return cards.size(); | |
} | |
}; | |
struct Player { | |
private: | |
friend class Game; | |
Deck deck; | |
Card hand; | |
public: | |
std::string name = "anonymous"; | |
Player() = default; | |
Player(std::string name): name(std::move(name)) {} | |
void battle(Player& other) { | |
print("% is attacking %!\n", name, other.name); | |
hand.battle(other.hand); | |
if(other.hand.dead()) { | |
other.draw(); | |
} | |
if(hand.dead()) { | |
draw(); | |
} | |
} | |
void draw() { | |
hand = deck.draw(); | |
} | |
bool lost() { | |
return deck.empty(); | |
} | |
}; | |
struct Game { | |
private: | |
Player one; | |
Player two; | |
Player* current; | |
Player* other; | |
std::map<std::string, std::function<bool()>> commands; | |
bool running = true; | |
public: | |
Game() { | |
one.deck.shuffle(); | |
two.deck.shuffle(); | |
one.draw(); | |
two.draw(); | |
current = &one; | |
other = &two; | |
commands["help"] = [this] { | |
print("available commands: \n"); | |
for(auto && c : commands) { | |
print("%\n", c.first); | |
} | |
return true; | |
}; | |
commands["attack"] = [this] { | |
current->battle(*other); | |
return false; | |
}; | |
commands["status"] = [this] { | |
print("Cards left in your deck: %\n", current->deck.cards_left()); | |
return true; | |
}; | |
commands["clear"] = [] { | |
std::system("cls"); // evil! | |
return true; | |
}; | |
} | |
void check_loss() { | |
if(other->lost()) { | |
print("% losses!\n% wins!\n", other->name, current->name); | |
running = false; | |
} | |
else if(current->lost()) { | |
print("% losses!\n% wins!\n", current->name, other->name); | |
running = false; | |
} | |
} | |
void process_input() { | |
print("What would you like to do? (type help for commands): "); | |
std::string command; | |
while(std::getline(std::cin, command)) { | |
auto it = commands.find(command); | |
if(it == commands.end()) { | |
commands.at("help")(); | |
} | |
else if(!it->second()) { | |
break; | |
} | |
print("What would you like to do? (type help for commands): "); | |
} | |
} | |
void turn() { | |
print("It is currently %'s turn\n", current->name); | |
process_input(); | |
check_loss(); | |
using std::swap; | |
swap(current, other); | |
} | |
int run() { | |
print("What is your name player one? "); | |
std::string name; | |
std::getline(std::cin, name); | |
one.name = std::move(name); | |
print("Welcome to the game %!\n", one.name); | |
two.name = "Bob"; | |
while(running) { | |
print("%: %", one.name, one.hand); | |
print("%: %", two.name, two.hand); | |
turn(); | |
} | |
return 0; | |
} | |
}; | |
int main() { | |
Game game; | |
return game.run(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment