Representing decks of cards
The way you store decks of cards and shuffle them is really very strange.
There's the unnecessary conversion (even for Python) from numbers to strings and back.
Using std::set
for a deck is wrong, because it doesn't preserve the order of the cards in the deck. Instead, I would use a std::deque
(no pun intended); it is fast to insert and remove cards from either end, and preserves their order. To create a deck of 52 cards (and lets keep them represented using int
s for now), you could write:
std::deque<int> deck(52);
std::iota(deck.begin(), deck.end(), 1);
Here I've used std::iota()
to initialize the value of each card in the deck, although a regular for-loop would be fine too. To shuffle the cards, use std::shuffle()
:
std::random_device rd;
std::default_random_engine rng(rd());
std::shuffle(deck.begin(), deck.end(), rng);
Then to split the deck evenly among the two players (as mentioned in the rules of War), just copy each half of the deck, using std::deque
's constructor that takes two iterators:
auto midpoint = std::advance(deck.begin(), 26);
std::deque<int> p1(deck.begin(), midpoint);
std::deque<int> p2(midpoint, deck.end());
Now you can just draw a card from the deck like so:
auto card = p1.front();
p1.pop_front();
And to push the card to the back of the deck you could write:
p1.push_back(card);
Note that we didn't need any random number generator after the initial shuffling anymore.
You can also move multiple cards in one go using insert()
and erase()
. Instead of keeping track of recursiveWarCount
and only moving cards when the war is resolved, consider moving cards from both player's decks to the deck on the table every step of the war.
Avoid repeating yourself
The code that deals with player 1 winning the war is almost identical to the one for player 2 winning the war, just with p1
and p2
reversed. Whenever you see yourself mostly duplicating the same lines of code, consider writing a function instead.
You could also consider creating a function that moves a card from one deck to another, so you can just call that instead of explicitly taking a card from one deck and adding it to another.
Consider creating new types or type aliases
Explicitly writing std::deque<int>
every time you declare a deck of cards is not great; it's quite long, you have to remember the correct type, and from the type it's not clear that it represents a deck of cards. Having a better name for a deck of cards would be great. You can create an alias for that type with the using
keyword:
using Card = int;
using Deck = std::deque<Card>;
And then you can use it like so:
Deck p1, p2;
Another way would be to create class Card
and class Deck
that represent cards and decks of cards, and have member functions that perform typical operations on it, like get_value()
for a Card
, and shuffle()
, split()
, draw()
and so on for a Deck
. This is a bit more work up front, but it might make implementing the actual logic of the War game much easier.