Ladder poker in c ++

0

I have to make a program that identifies a poker hand in C ++. The user will say how many cards he has and he will write a number from 0-51, being 0 = king, 1 = as, 2 = two, 11 = jack, 12 = queen ... and 0-12 spades, from 13-25 they are diamonds, 26-38 are hearts and 39-51 are clubs.

The only thing I need is a method to identify the dirty ladder, for example: 2 of clubs (41), 3 spades (3), 4 spades (4), 5 hearts (31) and 6 spades (6 ). I have tried several ways, could you tell me which would be the easiest and fastest?

    
asked by dmiranda 13.10.2016 в 20:18
source

4 answers

3

Question.

  

I'm missing is a method to identify the dirty ladder

Taking into account that each of the suits is the same size and have the same displacement, you can transform any hand into spades and check if the difference between each hand card (ordered) is one unit.

Proposal.

Unfortunately, you do not contribute ANYTHING to your code, so it's all conjecture and the answer may not fit your needs; I assume that the cards are std::uint8_t and that the player's hand is a std::vector of those types:

using Carta = std::uint8_t;
using Mano = std::vector<Carta>;

bool escalera_sucia(const Mano &mano)
{
    Mano temporal, palo;

    // Transformamos toda la mano a Picas y a Palo
    for (const auto &carta : mano)
    {
        temporal.push_back(carta % 13u);
        palo.push_back(carta / 13);
    }

    // Comprobamos si la mano es sucia (tiene al menos dos palos)
    if (std::all_of(palo.begin(), palo.end(), [i = palo[0]](Carta &c) { return c == i;} ))
        return false;

    // Ordenamos la mano resultante.
    std::sort(temporal.begin(), temporal.end());

    /* Nos aseguramnos que entre carta y carta de la
    mano ordenada, haya solo una unidad de diferencia */
    for (Mano::size_type indice = 1u; indice < temporal.size(); ++indice)
        if ((temporal[indice] - temporal[indice - 1u]) != 1u)
            /* Si llegamos aqui, significa que en algun momento la
            diferencia entre una carta y la siguiente es mayor a 1 */
            return false;

    // Si llegamos aqui, la mano es una escalera sucia.
    return true;
}

To transform into Picas (the base club) it is enough to make the module between the total of cards per suit ( 13 ), to know which suit a card belongs to, just enough to divide between the cards of each suit ( 13 ) being 0 picas, 1 diamonds, 2 hearts and 3 trefoils. A ladder will be dirty if there are at least two sticks in the hand and if the hand is ascending.

Warning.

I do not know the rules of Poker, so the previous algorithm may be wrong considering that the King (values 0 , 13 , 26 and 39 ) goes before the Ace. This is could solve by placing the King at the end of the letters changing the order to 0 - 9 normal numbers, 10 Jack, 11 Reina, 12 Rey, etc ...

    
answered by 14.10.2016 в 09:24
2

I personally prefer to handle treated data before raw data ... one thing is that the user has to identify a letter with a number and another that you have, necessarily, to use that number within your algorithms:

enum class Palo
{
  Picas,
  Diamantes,
  Corazones,
  Treboles
};

class Carta
{
public:

  explicit Carta(int numero)
    : palo_{static_cast<Palo>(numero/13)},
      numero_{numero%13}
  { }

  Carta(int numero, Palo palo)
    : palo_{palo},
      numero_{numero}
  { }

  Palo GetPalo() const
  { return palo_; }

  int GetNumero() const
  { return numero_; }

private:

  Palo palo_;
  int numero_;
};

On the other hand detecting a dirty staircase has its crumb:

  • With the sequence of cards you have placed, the king seems to be the first card when for poker it is the last one
  • The AS can start a ladder (A 2 3 4 5) or finish it (10 J Q K A)
  • If all the cards are of the same suit it can not be a dirty ladder

With all this in mind a possible algorithm (compilable in C ++ 14) would be as follows:

bool escalera_sucia(std::vector<Carta> mano)
{
  Palo palo = mano.front().GetPalo();
  bool soloUnPalo = std::all_of(mano.begin(),mano.end(),
                                [palo](Carta const& carta)
                                { return carta.GetPalo() == palo; });

  // No puede ser escalera sucia si todas las cartas son del mismo palo
  if( soloUnPalo )
    return false;

  // Dado que lo siguiente SI es una escalera...
  // - 9 10 J Q K, siendo K = 0
  // ... y que lo siguiente NO es una escalera
  // - K A 2 3 4, siendo K = 0 y A = 1
  // La ordenación ideal requiere poner la K al final del mazo:
  // A 2 3 4 5 6 7 8 9 10 J Q K
  auto sortLambda = [](Carta const& a, Carta const& b)
  {
    if( a.GetNumero() == 0 ) return false;
    if( b.GetNumero() == 0 ) return true;

    return a.GetNumero() < b.GetNumero();
  };

  std::sort(mano.begin(),mano.end(),sortLambda);

  // Lambda anidada.
  // - detectorEscaleraLambda: Una lambda que permite configurar correctamente la lambda anidada
  //                           hay que facilitarle el numero de la primera carta de la secuencia.
  // - lambda anidada: función que comprueba que en una secuencia de cartas sus números son correlativos.
  auto detectorEscaleraLambda = [](int numeroInicial)
  {
    return [numero = numeroInicial](Carta const& carta) mutable
    {
      bool toReturn = (carta.GetNumero() == numero);
      numero = (numero+1) % 13;
      return toReturn;
    };
  };

  bool escalera = std::all_of(mano.begin(),mano.end(),detectorEscaleraLambda(mano.front().GetNumero()));

  if( !escalera )
  {
    // La combinación A 10 J Q K no puede se encontrada con el orden actual de la mano
    if( mano.front().GetNumero() == 1 )
    {
      // Ponemos la primera carta en la ultima posicion, luego A 10 J Q K se convierte en 10 J Q K A
      Carta carta = mano.front();
      mano.erase(mano.begin());
      mano.push_back(carta);

      // Y volvemos a comprobar la escalera
      escalera = std::all_of(mano.begin(),mano.end(),detectorEscaleraLambda(mano.front().GetNumero()));
    }
  }
  return escalera;
}

You can see it working here

    
answered by 18.01.2018 в 09:00
0

This option uses a std::set , taking advantage of the fact that its elements are unique and ordered.

To form a "dirty" ladder, the first step is to complete that set with the numbers of the cards, abstracting from their "sticks".

The first condition is that there are no repeated numbers.

The second condition is that if they form a ladder, they must comply with: last - first = quantity - 1;

Then:

bool es_escalera_sucia(const std::vector<int>& v)
{
    std::set<int> mano;

    for (auto& n : v) {  
        mano.insert(n % 13);
    }

    if (mano.size() != v.size())  
        return false;

    return *mano.rbegin() - *mano.begin() == v.size() - 1;
}
    
answered by 17.01.2018 в 23:18
-2

Consider changing the format of the letters. Instead of using an integer ( int ), use a pair of integers ( std::pair <int, int> ). Where the first element is the number of the card (king: 0, as: 0, 2: 2, ...) and the second is the color (spades: 0, diamonds: 1, hearts: 2 and clubs: 3 ). You can access the values of the couple by .first and .second

int carta_int;
std::pair <int, int> carta_par;
carta_par.first = carta_int % 13;
carta_par.second = carta_int / 4;

Greetings

    
answered by 17.01.2018 в 22:09