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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
| #include <iostream> // ostream, cout
#include <array> // array
#include <vector> // vector
#include <random> // std::random_device, std::mt19937, std::normal_distribution
#include <numeric> // iota, accumulate
#include <algorithm> // transform, sort, shuffle, rotate, find_if
#include <utility> // pair
constexpr unsigned NB_COLORS = 4;
constexpr unsigned NB_CARDS_BY_COLOR = 13;
constexpr auto NB_CARDS = NB_COLORS * NB_CARDS_BY_COLOR;
constexpr unsigned NB_CARDS_IN_HAND = 5;
constexpr std::array<const char*, 13> rank_names = { "2", "3", "4", "5", "6", "7", "8", "9", "10",
"valet", "dame", "roi", "as" };
constexpr std::array<const char*, 4> color_names = { "coeur", "pique", "carreau", "trèfle" };
using Card = std::pair<unsigned, unsigned>;
std::ostream& operator<<(std::ostream& os, Card c) { // surcharge de l'opérateur << . Ex: std::cout << Card(0,0)
os << rank_names[c.first] << " de " << color_names[c.second];
return os;
}
using Deck = std::array<Card, NB_CARDS>;
using Hand = std::vector<Card>;
template < typename Cont >
void print_cards(const Cont cs) {
for (auto& c : cs) {
std::cout << c << '\n';
}
std::cout << std::endl;
}
/* plus nécessaire après la modification de generate_deck
auto& operator++(Card& c) {
++c.first;
++c.second;
return c;
}*/
auto generate_deck() {
Deck d;
std::vector<unsigned> tank(52);
std::iota(std::begin(tank), std::end(tank), 0);
std::transform(std::begin(tank), std::end(tank), std::begin(d), [](auto&& i) {
return std::make_pair(i % NB_CARDS_BY_COLOR, i % NB_COLORS);
});
return d;
}
auto& shuffle_deck(Deck& d) {
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(std::begin(d), std::end(d), g);
return d;
}
auto& cut_deck(Deck& d) {
std::random_device rd;
std::mt19937 g(rd());
std::normal_distribution<> dist(d.size()/2, d.size()/10); // distribution gaussienne: on coupe en général près du milieu
std::ptrdiff_t cut_pos = dist(g); // on précise le type car le retour de dist(g) est un double -> arrondi à l'entier en dessous
cut_pos %= d.size();
std::rotate(std::begin(d),
std::begin(d) + cut_pos,
std::end(d) );
return d;
}
std::pair<unsigned, Hand> evaluate_hand(const Hand& h) {
// tri décroissant d'une copie de h par rang des cartes avant de regrouper les cartes de même rang
Hand phand = h;
std::sort(std::begin(phand), std::end(phand), [](auto&& a, auto&& b) { return a.first > b.first; });
auto straight_score = 0u;
// on vérifie si c'est une couleur
if (std::all_of(std::begin(phand)+1, std::end(phand), [&](auto&& c) { return c.second == std::begin(phand)->second; }))
straight_score += 8;
// on vérifie si c'est une suite
auto beg = std::begin(phand)->first;
if (std::all_of(std::begin(phand)+1, std::end(phand), [&beg](auto&& c) { return c.first == --beg; }))
straight_score += 7;
// s'il y a une couleur ou une suite, il ne peut y avoir d'autre figure, donc on retourne maintenant
// il suffirait de retourner également le rang de la carte la plus haute pour les cas d'égalité de score
// mais comme pour les autres figures, il faut comparer plusieurs cartes en cas d'égalité, on renvoie la main avec;
if (straight_score != 0) return std::make_pair(straight_score, phand);
// maintenant pour les figures de type paire, brelan, full...
// regrouper les cartes par rang dans un vector<Hand>
auto rshand = std::accumulate(std::begin(phand), std::end(phand), std::vector<Hand>(), [](auto&& a, auto&& b) {
if (!a.empty() && a.back().back().first == b.first) a.back().push_back(b); // un peu moche, d'accord
else a.push_back(Hand(1,b));
return a;
});
// on cherche le groupe de cartes identiques le plus nombreux
std::sort(std::begin(rshand), std::end(rshand), [](const auto& a, const auto& b) { return a.size() > b.size(); });
// et on déduit un score synthétique par: figure la plus nombreuse * (taille de la main - nombre de groupes de cartes)
auto figure_score = std::begin(rshand)->size() * (NB_CARDS_IN_HAND - rshand.size());
// pour les cas d'égalité de score, on retourne également la première carte de chaque groupe de carte dans un std::vector
Hand firsts(rshand.size());
std::transform(std::begin(rshand), std::end(rshand), std::begin(firsts), [](auto&& h) { return *std::begin(h); });
return std::make_pair(figure_score, firsts);
}
bool compare(const Hand& a, const Hand& b) {
auto score_a = evaluate_hand(a);
auto score_b = evaluate_hand(b);
if (score_a.first < score_b.first) return true;
if (score_a.first > score_b.first) return false;
return std::lexicographical_compare(std::begin(score_a.second), std::end(score_a.second),
std::begin(score_b.second), std::end(score_b.second),
[](auto&& l, auto&& r) { return l.first < r.first; });
}
auto winners(const std::vector<Hand>& hands) {
auto chands = hands;
std::sort(std::begin(chands), std::end(chands), [](auto&& a, auto&& b) { return !compare(a,b); });
auto first = *std::begin(chands);
auto last = std::find_if(std::begin(chands)+1, std::end(chands), [&first](auto&& c) { return compare(c, first); });
chands.erase(last, std::end(chands));
return chands;
}
int main() {
auto deck = generate_deck();
shuffle_deck(deck);
cut_deck(deck);
Hand hand1(NB_CARDS_IN_HAND), hand2(NB_CARDS_IN_HAND);
std::copy_n(std::begin(deck), NB_CARDS_IN_HAND, std::begin(hand1));
print_cards(hand1);
std::cout << std::endl;
std::copy_n(std::begin(deck)+NB_CARDS_IN_HAND, NB_CARDS_IN_HAND, std::begin(hand2));
print_cards(hand2);
std::cout << std::endl;
std::cout << "Score first hand: " << evaluate_hand(hand1).first << std::endl;
std::cout << "Score second hand: " << evaluate_hand(hand2).first << std::endl;
std::cout << "first hand < second hand? " << std::boolalpha << compare(hand1, hand2) << std::endl;
} |
Partager