Moving one vector element into another vector?

Nov 21, 2019 at 9:11pm
Hi all,

I will try to put my question in an example:

If I have a vector of card objects mimicking a deck of cards:
std::vector<Card>Deck

and wanted to "draw" one card from that deck vector and transfer it into another vector of a player's current hand:
std::vector<Card>MyHand

How would I go about that? I saw many posts about a vector's move function, but I'm still a bit unsure.

Thank you in advance for the help!
Nov 22, 2019 at 2:15am
1
2
3
4
void dealCard(std::vector<Card>& deck, std::vector<Card>& hand) {
    hand.push_back( deck.back() );
    deck.pop_back();
}

Nov 22, 2019 at 2:58am
indeed, you should use std::stack to simulate deck of cards.
vector is not suited for this task.
Nov 22, 2019 at 4:44am
you should use std::stack to simulate deck of cards.

And how is a std::stack supposed to be shuffled (cards randomized)? std::vector (or std::array) can be shuffled as if were a deck of cards.

http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3551.pdf
Last edited on Nov 22, 2019 at 4:46am
Nov 22, 2019 at 6:01am
> And how is a std::stack supposed to be shuffled

With the advent of move semantics, we can do this (if we must shuffle the contents of a stack):
move the items in the stack to a vector; shuffle the vector; move shuffled items back into the stack.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stack>
#include <vector>
#include <algorithm>
#include <random>

template < typename T, typename C >
std::stack<T,C>& shuffle( std::stack<T,C>& stk )
{
    std::vector<T> vec ;

    while( !stk.empty() )
    {
        vec.push_back( std::move( stk.top() ) ) ;
        stk.pop() ;
    }

    static std::mt19937 rng( std::random_device{}() ) ;
    std::shuffle( vec.begin(), vec.end(), rng ) ;

    for( T& v : vec ) stk.push( std::move(v) ) ;

    return stk ;
}
Nov 22, 2019 at 4:49pm
move the items in the stack to a vector; shuffle the vector; move shuffled items back into the stack.

That is rather a bit of overkill IMO, especially when seen in the context of a repeatable card game.

Yes, the code below is Frankensteined. Yes, it isn't OOPed. It IMO shows how using a std::vector overall can make more sense than using a std::stack.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <iostream>
#include <vector>
#include <numeric>
#include <random>
#include <algorithm>

using card = int;

void create_deck(std::vector<card>&);
void display_deck(std::vector<card>&);
void deck_cap(std::vector<card>&);
void deal_cards(std::vector<card>&, int, int);

int main()
{
   std::vector<card> deck;

   deck_cap(deck);

   create_deck(deck);
   display_deck(deck);
   deck_cap(deck);

   std::cout << "Dealing cards......\n\n";

   while (!deck.empty()) { deck.pop_back(); }
   deck_cap(deck);

   create_deck(deck);
   display_deck(deck);
   deck_cap(deck);

   std::cout << "Dealing that deck......\n";
   deal_cards(deck, 5, 7); // five players, 7 card stud
   deck_cap(deck);
}

void create_deck(std::vector<card>& deck)
{
   static std::default_random_engine rng(std::random_device{}());

   std::cout << "Creating a deck....\n";
   deck.resize(52);

   std::iota(deck.begin(), deck.end(), 0);
   std::shuffle(deck.begin(), deck.end(), rng);
}

void display_deck(std::vector<card>& deck)
{
   auto suit = [] (card c) { return "SHDC"[c / 13]; };
   auto rank = [] (card c) { return "23456789TJQKA"[c % 13]; };

   int count { };

   for (const auto& itr : deck)
   {
      std::cout << rank(itr) << suit(itr) << ' ';
      count++;
      if (0 == count % 13) { std::cout << '\n'; }
   }
   std::cout << '\n';
}

void deck_cap(std::vector<card>& deck)
{
   std::cout << "The deck's capacity: " << deck.capacity()
      << ", deck's size: " << deck.size() << "\n\n";
}

void deal_cards(std::vector<card>& deck, int num_players, int num_cards)
{
   auto suit = [] (card c) { return "SHDC"[c / 13]; };
   auto rank = [] (card c) { return "23456789TJQKA"[c % 13]; };

   std::vector<std::vector<card>> players(num_players, std::vector<card>(num_cards));

   for (size_t cards { }; cards < num_cards; cards++)  // fixed dealing
   {
      for (size_t player { }; player < num_players; player++)
      {
         players[player][cards] = deck.back();
         deck.pop_back();
      }
   }

   for (size_t player { }; player < num_players; player++)
   {
      std::cout << "Player#:" << player + 1 << ' ';

      for (const auto& itr : players[player])
      {
         std::cout << rank(itr) << suit(itr) << ' ';
      }
      std::cout << '\n';
   }
   std::cout << '\n';
}

The deck's capacity: 0, deck's size: 0

Creating a deck....
QC QS 7D 5D 8D AH 3H 4S 6S AC JH 7S 6D
TC 4H KD 9C 5S 9H JC KC 2C JS AS 6C 9D
TS 4D 3D 6H 8S KS 5C TD 2H TH 7H 3C 8H
3S AD 7C QH JD KH 2D 5H 4C 8C 2S 9S QD

The deck's capacity: 52, deck's size: 52

Dealing cards......

The deck's capacity: 52, deck's size: 0

Creating a deck....
6S 6H 2C AC 7H 8H 6D AH 9D 3H 4H 8C 7D
9C 8S 4S JH TC AD 2H 9S 5D 5H 6C 8D JC
2D QC JD QS 7C 2S KS KD 3S AS 9H 4D TH
4C KC 3C 3D 7S QH 5S TD KH TS QD JS 5C

The deck's capacity: 52, deck's size: 52

Dealing that deck......
Player#:1 5C JS QD TS KH TD 5S
Player#:2 QH 7S 3D 3C KC 4C TH
Player#:3 4D 9H AS 3S KD KS 2S
Player#:4 7C QS JD QC 2D JC 8D
Player#:5 6C 5H 5D 9S 2H AD TC

The deck's capacity: 52, deck's size: 17


Being a quick test bed I did no error checking, especially if the number of players and cards dealt to each player exceeds the number of cards in the deck.

Originally I was dealing players' hands "wrong." Fixed that. (One card to each player; lather rinse and repeat until each player has the appropriate number of a cards)
Last edited on Nov 22, 2019 at 5:11pm
Nov 23, 2019 at 3:43am
both answers are truly awesome!
I never worked on card game, but stack seems more logical for the purpose. IDK, it really depends on what you want. but yes, std::stack is little cumbersome on what you can do with it in this specific case.
Nov 23, 2019 at 2:08pm
wanted to "draw" one card from that deck vector and transfer it into another vector of a player's current hand:

A bit of advice: don't write functions and methods that "do the work." Write functions/methods that "make doing the work easy." If you think like this, you'll write code that is flexible. In this case, you could write a method that will transfer a card from the deck to a hand, but then what about when you put a card on the table? Or discard it?

What you want is a method that will remove a card from a deck (or hand). Then you can do whatever you want with the removed card:
1
2
3
4
5
Card removeCard(vector<Card> &hand) {
    Card result = hand.back();
    hand.pop_back();
    return result;
};


Now if you want to transfer a card from the deck to a hand, it's a one-liner:
hand.push_back(removeCard(deck));
Nov 23, 2019 at 5:19pm
you could leave all the cards in one place and use pointers to hold the 'deck' and the 'hands' and to 'deal', which minimizes excess copying / data movement.

pseudocode for that..
vector deck<cards*>;
init(deck); //probably just copying pointers from a fixed vector of cards
shuffle the deck; //just moves pointers, no data
index = 0;
cards * myhand[5] = {0};
myhand[0] = deck[index++]; //deal me a card

a 10 cent crude example of the idea.
Last edited on Nov 23, 2019 at 5:20pm
Nov 23, 2019 at 8:04pm
Write functions/methods that "make doing the work easy."

If I were coding a multiple card game app, as the OP apparently is wanting to do, I certainly wouldn't have written what I did in my example above. At least not as Frankensteined as I did.

I write code snippets to test out various ideas of what I want to achieve in a larger program. That way I have an idea if, for example, actually adding/removing a container's elements or using pointers is a better approach for what I want to do. What the costs/benefits are for the different ways to code what is needed for each part of the program.
Topic archived. No new replies allowed.