For anyone who's interested, here's an implementation with the cards
represented as integers (or wrapping integers). Perhaps this could be the
basis of a super-compact representation. In any case, sorting hands becomes
simpler, but either dealing (creating a card object) or checking that a play
is legal becomes more involved (because at some point you would have to
reconstruct the symbolic information regarding suit and rank).
Alternatively, if you want to make the deck bridge-specific you could change
the undealt variable into an Array or OrderedCollection, and after shuffling
treat each of the quarters as belonging to a specific hand. Again, more
compact, less simplicity. Taking something out of the hand could be
represented by replacing that card's integer with 0 in the deck/hand array.
Another alternative would be to use an "ordinary" representation for
shuffling etc. then write that into a bit-packed representation with each
two bits representing a player, as the original questioner wanted. Some
utility classes could go over that to make handling such a thing look like
an array of players, and use a formatting method similar to the one used in
the attached code.