Foros - Stratos

Stratos => General => Mensaje iniciado por: Kabila en 23 de Agosto de 2011, 11:46:44 AM

Título: algoritmo de calculo de manos
Publicado por: Kabila en 23 de Agosto de 2011, 11:46:44 AM
Buenos dias.

Teniendo 7 naipes en la mano, calcular la mejor jugada. Solo se pueden hacer escaleras (cartas contiguas del mismo palo de 3 a 7 cartas) y cartas del mismo valor y diferente o igual palo (si hay mas de de una baraja)

algoritmo para calcular cual seria la mejor jugada posible

saludos
Título: Re: algoritmo de calculo de manos
Publicado por: Vicente en 23 de Agosto de 2011, 12:11:20 PM
Mmm, hay algo que no entiendo porque el problema parece trivial.

Es decir, si tu sabes los puntos que vale la escalera de tamaño N y los puntos que vale el tener X cartas iguales, simplemente buscas ambas posibilidades. Vamos, son como mucho 5 posibles escaleras y 6 posibles repeticiones (creo), buscas una detras de otra y listo.

Asi que seguro que algo me he perdido.
Título: Re: algoritmo de calculo de manos
Publicado por: blau en 23 de Agosto de 2011, 12:17:53 PM
Supongo que hablas de jugar al chinchon, y que se trata de determinar:

1. Si coges una carta de la baraja
2. Si coges la carta descartada del jugador anterior

y en todo caso que carta descartas para coger alguna de las anteriores...  

y para hacerlo bien habría que tener en cuenta las cartas que se han ido descartando que están en el montón de descarte y que de momento no van a salir, al menos hasta que se acabe el monton de la baraja y las que habiendo sido descartadas han sido rescatadas por otros jugadores...

¿es esto así?
Título: Re: algoritmo de calculo de manos
Publicado por: Kabila en 23 de Agosto de 2011, 04:48:06 PM
No es tan trivial.

Es para el juego chinchon. Cuando alguien cierra, un algoritmo que encuentre la mejor jugada de cada jugador (de momento no incluyo comodin porque sino se dispara)

Tengo unsistema hecho que funciona aunque con comodin falla en jugadas muy puntuales. Pero me gustaria hacer algo mas consistente.

saludos
Título: Re: algoritmo de calculo de manos
Publicado por: Warchief en 23 de Agosto de 2011, 09:11:28 PM
Joer, se me ocurren un monton de formas. La que mas me gusta es:


// Asumo barajas de 12 cartas y 4 palos (puede haber mas de una baraja)
int CartasDelColega[4][12];

// Cada vez que le das una carta
CartasDelColega[ palo ][ valor ] ++;

// Cada vez que se la quitas
CartasDelColega[ palo ][ valor ] --;


Repeticiones:

FOR c = 0 a 11 // cartas
 FOR p = 0 a 3 // palos
   RepC += CartasDelColega[ p ][ c ];
 Si RepC es mejor que MejorRepC, tenemos mejor repeticion
MejorRepCFinal = MejorRepC + NumeroDeComodines


Escaleras

FOR p = 0 a 3 // palos
 escalera = 0
 FOR c = 0 a 11 // cartas
  Si CartasDelColega[ p ][ c ]  != 0
   escalera++
  else
  {
    if ( escalera > mejorEscalera )
        mejorEscalera = escalera
    escalera = 0
  }

// para el rey
if ( escalera > mejorEscalera )
  mejorEscalera = escalera



Creo que es lo suficientemente rapido como para que puedas hacer:
(para N comodines que tengas, combinar)

for p 0 a 3
 for c 0 a 11
   AnyadirComodin( p, c )
   CalcularEscaleras()
   QuitarComodin( p, c )


Si no, el bucle de escaleras se vuelve un poco mas complejo, pero mas optimo, mediante reutilizacion de comodines.
No he querido seguir ahi porque no se si puedes tener solo 1 comodin o varios, pero no es excesivamente complejo.
Título: Re: algoritmo de calculo de manos
Publicado por: Warchief en 23 de Agosto de 2011, 09:19:28 PM
Un par de notas:

1) Si el As puede valer como 13, puedes hacer:
int CartasDelColega[4][13]; // y contarlo en 1 y 13 al anyadir un as. No afecta a las repeticiones y las escaleras funcionaran.

2) Porque asumo que no se pueden hacer escaleras ciclicas.
Si se puede, el bucle cambia un poco, para guardar la escalera de As a N, y la de M a Rey, y sumarlas (si hay As y Rey.)

3) Para optimizar comodines, al anyadir uno:
Si cartas[p][c] ya es != 0, no hace falta probarlo, no afecta a las escaleras
Si cartas[p][c-1] == 0 && cartas[p][c+1] == 0, no hace falta probarlo, no afecta a las escaleras
Título: Re: algoritmo de calculo de manos
Publicado por: Makaimura en 24 de Agosto de 2011, 12:42:22 AM
Que lios os traéis los programadores hacer Suters con el udk y dejaos de cosas raras.
Título: Re: algoritmo de calculo de manos
Publicado por: Eskema en 24 de Agosto de 2011, 01:03:42 PM
Cita de: makaimura en 24 de Agosto de 2011, 12:42:22 AM
Que lios os traéis los programadores hacer Suters con el udk y dejaos de cosas raras.



+++masuno!!!!!  :D
Título: Re: algoritmo de calculo de manos
Publicado por: Kabila en 24 de Agosto de 2011, 06:10:48 PM
Hola Warchief

No vas muy desencaminado pero en realidad no es eso.

Suponte esta mano de cartas  [102,103,104,105,205,305,402]

el tio cierra con 2 puntos de resto... las cartas funciona los cientos son oros,copas,espadas y bastos y los restos son el valor

El algoritmo deberia encontrar algo como   [[101,103,104],[105,205,305],[402]] o sea una escalera, un trio y sobra un dos

PArece sencillo pero un algoritmo eficiente que encuentre cualquier convinacion y cuando se complica con un comodin no lo es tanto
Título: Re: algoritmo de calculo de manos
Publicado por: Vicente en 24 de Agosto de 2011, 06:23:29 PM
Esto, el ejemplo no esta mal? No es una escalera de 4 cartas y un trio?
Título: Re: algoritmo de calculo de manos
Publicado por: Warchief en 24 de Agosto de 2011, 07:17:08 PM
Cita de: Vicente en 24 de Agosto de 2011, 06:23:29 PM
Esto, el ejemplo no esta mal? No es una escalera de 4 cartas y un trio?

Es un typo,  [[102,103,104],[105,205,305],[402]]
En cualquier caso 402 no se puede usar para la escalera del 100 porque es de otro palo.

@Kabila
Un problema interesante. Mi primer intento (o segundo) seria probar todas las combinaciones por fuerza bruta, guardando la que deje menos puntos abiertos. Para usar los comodines, como dije, poner el comodin en cada una de las posibles cartas por palo, teniendo en cuenta las posibles optimizaciones:
+ Solo afecta escaleras si hay carta de valor adyacente en el mismo palo
+ Solo afecta a repeticiones si el valor escogido esta repetido dos veces exactamente o puede formar escalera en esa posicion
| - (ya que permite liberar una carta que podemos usar para la escalera, como el 105 en tu ejemplo)

Ahora no puedo pensarlo mas,  pero a ver si encuentro tiempo estos dias. Parece divertido de resolver :)
Título: Re: algoritmo de calculo de manos
Publicado por: Warchief en 24 de Agosto de 2011, 07:59:13 PM
+ Cuantos comodines hay en la(s) baraja(s)? Son barajas de 50 cartas?
+ Si te toca mas de uno puedes combinarlos en distintos juegos? (uno para escalera otro para trio?)
+ Se puede usar el as tras el rey?
Título: Re: algoritmo de calculo de manos
Publicado por: blau en 24 de Agosto de 2011, 10:53:46 PM
Cita de: Warchief en 24 de Agosto de 2011, 07:59:13 PM
+ Cuantos comodines hay en la(s) baraja(s)? Son barajas de 50 cartas?
Normalmente dos, 50 = 48+2

Cita de: Warchief en 24 de Agosto de 2011, 07:59:13 PM+ Si te toca mas de uno puedes combinarlos en distintos juegos? (uno para escalera otro para trio?)
Claro

Cita de: Warchief en 24 de Agosto de 2011, 07:59:13 PM
+ Se puede usar el as tras el rey?
No

Yo estuve la otra tarde montando el algoritmo, intentando buscar todos las posibles soluciones parciales y luego elegir de ellas las mejores que no compartan cartas... consegui la parte de los grupos con comodines o sin ellos, pero el tema de las escaleras se me complico bastante...  ^_^'


Título: Re: algoritmo de calculo de manos
Publicado por: Warchief en 24 de Agosto de 2011, 11:19:34 PM
Cita de: blau en 24 de Agosto de 2011, 10:53:46 PM
Cita de: Warchief en 24 de Agosto de 2011, 07:59:13 PM
+ Cuantos comodines hay en la(s) baraja(s)? Son barajas de 50 cartas?
Normalmente dos, 50 = 48+2

Cita de: Warchief en 24 de Agosto de 2011, 07:59:13 PM+ Si te toca mas de uno puedes combinarlos en distintos juegos? (uno para escalera otro para trio?)
Claro

Cita de: Warchief en 24 de Agosto de 2011, 07:59:13 PM
+ Se puede usar el as tras el rey?
No

Yo estuve la otra tarde montando el algoritmo, intentando buscar todos las posibles soluciones parciales y luego elegir de ellas las mejores que no compartan cartas... consegui la parte de los grupos con comodines o sin ellos, pero el tema de las escaleras se me complico bastante...  ^_^'





Si se juega con mas de una baraja, te pueden tocar 3 comodines o solo se meten 2 comodines en total?
Título: Re: algoritmo de calculo de manos
Publicado por: blau en 24 de Agosto de 2011, 11:51:55 PM
Yo he jugado con 2 barajas y 4 comodines... pero para estar seguros habria que buscar en la norma une correspondiente.  :D
Título: Re: algoritmo de calculo de manos
Publicado por: Warchief en 25 de Agosto de 2011, 02:05:28 AM
Si te tocan mas de dos, te los comes con patatas entonces?

Citar
http://es.wikipedia.org/wiki/Chinch%C3%B3n_%28juego_de_naipes%29
Las combinaciones de cartas que pueden formarse son:
    Escalera: tres o más cartas del mismo palo consecutivas, con un solo comodín.
    Pie o trío: tres o cuatro cartas del mismo número, con un solo comodín.
    Chinchón: siete cartas consecutivas, del mismo palo.
Título: Re: algoritmo de calculo de manos
Publicado por: blau en 25 de Agosto de 2011, 10:42:27 AM
Siempre te puedes descartar una carta en tu turno... :)
Título: Re: algoritmo de calculo de manos
Publicado por: Warchief en 25 de Agosto de 2011, 12:33:13 PM
Me refiero a qué pasa cuando te quedas con 3 comodines en tu mano y cierran.
Creo que ya tengo la versión sin comodines funcionando; añadir comodines me parece que será sencillo con los casos interesantes.
Título: Re: algoritmo de calculo de manos
Publicado por: Warchief en 25 de Agosto de 2011, 01:34:18 PM
Me voy a dormir que ya ni veo si los resultados son buenos. Mañana comodines y limpiar código.
Uhm, debido a una optimización, falla si hay repetidos en escalera. Mañana quito la optimización.
Título: Re: algoritmo de calculo de manos
Publicado por: Warchief en 25 de Agosto de 2011, 10:57:39 PM
Perfecto, he modificado la representacion de datos para no tener que quitar la optimizacion y voila.
Para meter multiples comodines se me ocurren varias formas en la implementacion que tengo, pero creo que volver a la idea de Vicente de las permutaciones es mas sencillo. No creo que siga ya implementando porque consume bastante tiempo, pero ha sido divertido.


*******************************************************
MANO     {102, 103, 104, 105, 205, 305, 402}
Ordenada {102, 103, 104, 105, 205, 305, 402}
Mejor Jugada:
  | - Escalera = {102, 103, 104}
  | - Match x3 = {105, 205, 305}
  | - Libres   = {402}
  | + Score = 2

*******************************************************
MANO     {102, 202, 302, 105, 205, 305, 405}
Ordenada {102, 105, 202, 205, 302, 305, 405}
Mejor Jugada:
  | - Match x3 = {102, 202, 302}
  | - Match x4 = {105, 205, 305, 405}
  | + Score = 0

*******************************************************
MANO     {102, 103, 104, 105, 103, 102, 202}
Ordenada {102, 102, 103, 103, 104, 105, 202}
Mejor Jugada:
  | - Escalera = {103, 104, 105}
  | - Match x3 = {102, 202, 102}
  | - Libres   = {103}
  | + Score = 3

*******************************************************
MANO     {306, 402, 305, 403, 307, 404, 401}
Ordenada {305, 306, 307, 401, 402, 403, 404}
Mejor Jugada:
  | - Escalera = {305, 306, 307}
  | - Escalera = {401, 402, 403, 404}
  | + Score = 0
Título: Re: algoritmo de calculo de manos
Publicado por: Warchief en 25 de Agosto de 2011, 11:04:15 PM
Por cierto, el algoritmo ha quedado bastante sencillo, aunque se puede reordenar un poco para simplificar BuscarEscalera (hace el mismo check en dos path distintos).


  // Find
  //   Ordenar
  //   BuscarEscalera( 0 )

  // BuscarEscalera( IDX )
  //   FOR n = 3 a CartasRestantes( IDX )
  //     SI HayEscalera( IDX, n )    -- hay escalera en el indice IDX con longitud n
  //       UsarCartas( IDX, n )      -- marcar las cartas como usadas en la escalera que empieza en IDX y con longitud n
  //       SI QuedanCartas           -- quedan cartas tras UsarCartas
  //         BuscarEscalera()        -- buscar escaleras en las cartas restantes
  //       SI NO
  //         BuscarPies()            -- buscar entre las cartas que nos dejamos atras sin meter en escaleras
  //   SI HayCartasPorMirar          -- quedan cartas que no hemos explorado (donde empezar escaleras)
  //     BuscarEscalera( IDX + 1 )   -- avanzar a la siguiente
  //   SI NO
  //     BuscarPies()                -- no hay mas escaleras, buscar pies entre las cartas que hemos dejado atras

  // BuscarPies( IDX )
  //   SI HayRepeticion( IDX )       -- se puede hacer un pie con la carta en IDX
  //     UsarCartas( IDX )           -- marcar como usadas las cartas con el mismo valor
  //     BuscarPies()                -- buscar mas pies entre las restantes
  //   SI NO
  //     SI HayCartasPorMirar        -- quedan cartas que no hemos explorado (valores que aun puede formar pies)
  //       BuscarPies( IDX + 1 )     -- avanzar a la siguiente
  //     SI NO
  //       CalcularPuntuacion        -- devolver el valor las cartas que han quedado libres
Título: Re:algoritmo de calculo de manos
Publicado por: Warchief en 25 de Abril de 2013, 01:04:11 AM
Hace unos días un estudiante me pidió el código de mi algoritmo, así que lo pondre aquí. No creo que en 2013 puedas engañar a un profesor con código bajado de Internet, así que puede servir como referencia pero no creo que para presentar.

Obviamente el código no está comentado, ni refactorizado, pero ahí va.
http://pastebin.com/gbDcatwn

Lo que puedes obtener: dada una mano definida por cartas XYY, siendo X el palo (eg: 1 = Espadas, 2 = Oros..), y siendo YY el valor de la carta (eg: 01 = As, 02 = 2, ... 12 = Rey)

        Mano m;
        m.AddCard( 102 );
        m.AddCard( 103 );
        m.AddCard( 104 );
        m.AddCard( 105 );
        m.AddCard( 205 );
        m.AddCard( 305 );
        m.AddCard( 402 );


Encuentra la mejor jugada (para cerrar o para contar puntos):

*******************************************************
MANO     {102, 103, 104, 105, 205, 305, 402}
Ordenada {102, 103, 104, 105, 205, 305, 402}
Mejor Jugada:
  | - Escalera = {102, 103, 104}
  | - Match x3 = {105, 205, 305}
  | - Libres   = {402}
  | + Score = 2


Al final no añadí comodines porque me cansé, pero no sería muy difícil hacer una version no optimizada seleccionando valores para los comodines que puedan cambiar la puntuación (adyacentes a otras cartas o de mismo valor que las presentes) :)

Por si PasteBin no funciona:

// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <cmath>
#include <vector>
#include <list>
#include <cassert>
#include <cstdarg>
#include <algorithm>

#define VERBOSE 0

typedef int INT;
typedef unsigned int  UINT;
typedef unsigned long ULONG;

//  todo quitar push invertido (no es necesario)

struct _Log
{
    void Print( const char* format, ... )
    {
#if VERBOSE
        for( INT i=0; i<NUMTABS; ++i ) { printf("  "); }
#endif
        va_list args;
        va_start( args, format );
        vprintf( format, args );
        va_end( args );
    }
    void Push()
    {
        ++NUMTABS;
    }
    void Pop() {
        --NUMTABS;
        assert( NUMTABS >= 0 );
    }
private:
    INT NUMTABS;
} Log;

struct ScoreTrack
{
    ScoreTrack() { Reset(); }

    enum
    {
        TOKEN_START = 0
        , ESCALERA
        , MATCH3 = 3
        , MATCH4
        , MATCH5
        , MATCH6
        , MATCH7
        , FREE
        , TOKEN_END
    };

    void PushEscalera()
    {
        Combinacion.push_back( ESCALERA );
    }
    void PushMatch( UINT Reps )
    {
        assert( Reps >= MATCH3 && Reps <= MATCH7 );
        Combinacion.push_back( Reps );
    }
    void PushFree()
    {
        Combinacion.push_back( FREE );
    }
    void PushVal( UINT v )
    {
while ( v > 500 ) { v -= 400; }
        Combinacion.push_back( v );   
    }
    bool IsBackToken() const
    {
        UINT Val = Combinacion.back();
        return ( Val > TOKEN_START && Val < TOKEN_END );
    }
    void Pop()
    {
        assert( Combinacion.size() > 0 && !IsBackToken() );
        do
        {
            Combinacion.pop_back();
        } while( !IsBackToken() );
        Combinacion.pop_back();
    }
    ULONG GetScore() const
    {
        return Score;
    }
    bool IsEmpty()
    {
        return Combinacion.empty();
    }
    void Reset()
    {
        Score = 666;
        Combinacion.clear();
    }
    void Print()
    {
        Log.Print( " Mejor Jugada:\n" );
        for( UINT i=0; i<Combinacion.size(); ++i )
        {
            if ( Combinacion[i] == ESCALERA )
            {
                printf( "  | - Escalera = {" );
            }
            else if ( Combinacion[i] >= MATCH3 && Combinacion[i] <= MATCH7 )
            {
                printf( "  | - Match x%d = {", Combinacion[i] );

                // Porque hago push invertido
                for ( UINT j = i + Combinacion[i]; j > i ; --j )
                {                   
                    if ( j == i+1 )
                    {
                        printf( "%d}\n", Combinacion[j] );
                    }
                    else
                    {
                        printf( "%d, ", Combinacion[j] );
                    }                   
                }
                i = i + Combinacion[i];
            }
            else if ( Combinacion[i] == FREE )
            {
                printf( "  | - Libres   = {" );
            }
            else
            {
                UINT Next = i+1;
                if ( Next >= Combinacion.size() || ( Combinacion[Next] < TOKEN_END ) )
                {
                    printf( "%d}\n", Combinacion[i] );
                }
                else
                {
                    printf( "%d, ", Combinacion[i] );
                }
            }
        }
        printf( "  | + Score = %lu\n", Score );       
        //Log.Print( "- - - - - - - - - \n\n" );

    }

    ULONG Score;
private:
    std::vector<UINT> Combinacion;
};
ScoreTrack CurrentScore;
ScoreTrack BestScore;

class Mano
{
private:
    typedef std::vector<UINT> Container;   
    Container Cards;
    Container UsedCards;

public:
    void AddCard( UINT c )
    {
        Cards.push_back( c );
        assert( Cards.size() <= 7 );
    }   
    void Use( UINT first, UINT count )
    {
        assert( count <= ( Cards.size() - first ) );       
        for( UINT i = first ; i < (first+count); ++i )
        {
            UsedCards.push_back( Cards[i] );
            CurrentScore.PushVal( Cards[i] );
        }
        Cards.erase( Cards.begin() + first, Cards.begin() + first + count );
    }
    void Restore( UINT count )
    {
        assert( count <= UsedCards.size() );
        for( UINT i = 0; i < count; ++i )
        {
            AddCard( UsedCards[UsedCards.size() - i - 1] );
        }
        CurrentScore.Pop();
        UsedCards.erase( UsedCards.end() - count, UsedCards.end() );
        std::sort( Cards.begin(), Cards.end() ); // podria optimizarse
    }
    void RemoveCardByVal( UINT c )
    {
        Container::iterator match = std::find( Cards.begin(), Cards.end(), c );
        assert( match != Cards.end() );
        Cards.erase( match );
    }
    void RemoveCardByIndex( UINT i )
    {
        assert( i < Cards.size() );
        Cards.erase( Cards.begin() + i );
    }

    bool HayEscalera( UINT index, UINT n ) const
    {
        assert( n > 2 && n <= Cards.size() );
        return ( Cards[index+n-1] - Cards[index] == (n-1) );
    }

    UINT CardsLeft( UINT curIdx ) const
    {
        assert( curIdx <= Cards.size() );
        return Cards.size() - curIdx;
    }
    bool HayNext( UINT curIdx ) const
    {
        return (curIdx+1) < Cards.size();
    }
    UINT Valor( UINT curIdx ) const
    {
        assert( curIdx < Cards.size() );
        return UINT( Cards[curIdx] % 100 );
    }

    void Print() const
    {
        PrintFrom( 0, Cards.size() );
    }
    void PrintFrom( UINT first, UINT count ) const
    {
        assert( first >= 0 && count <= ( Cards.size() - first ) );
        printf("{");
        for( UINT i = first ; i < (first+count); ++i )
        {
            if ( i != first )
            {
                printf(", ");
            }
            printf( "%u", Cards[i] );
        }
        printf("}\n");
    }

void CleanDups()
{
for ( UINT i=0; i < Cards.size(); ++i )
{
for ( UINT j=i+1; j < Cards.size(); ++j )
{
if ( Cards[i] == Cards[j] )
{
Cards[j] += 400;
}
}
}
}

void RestoreDups()
{
for ( UINT i=0; i < Cards.size(); ++i )
{
while ( Cards[i] > 500 )
{
Cards[i] -= 400;
}
}
}

    void FindBestScore();

private:
    void Buscar( UINT curIdx );
    void Match( UINT curIdx );
    ULONG CloseVal() const;

};


ULONG Mano::CloseVal() const
{
    ULONG Val = 0;
    for ( UINT i = 0; i < Cards.size(); ++i )
    {
        Val += Valor( i );
    }
    return Val;
}

void Mano::Match( UINT curIdx )
{
#if VERBOSE
    Log.Print("Match: ");
    PrintFrom( curIdx, CardsLeft( curIdx ) );
#endif

    if ( CardsLeft( curIdx ) >= 3 )
    {
        UINT CardsLeftTotal = CardsLeft( curIdx );
        UINT Val = Valor( curIdx );
        UINT Reps = 1;
        for ( UINT i = curIdx + 1; i < curIdx + CardsLeftTotal; ++i )
        {
            if ( Valor( i ) == Val )
            {
                ++Reps;
            }
        }

        if ( Reps >= 3 )
        {

#if VERBOSE
            Log.Print( "Match x%d = {", Reps );
            UINT NumRep = 1;
            for ( UINT i = curIdx; i < curIdx + CardsLeftTotal; ++i )
            {
                if ( Valor( i ) == Val )
                {
                    if ( NumRep == Reps )
                    {
                        printf( "%d}\n", Cards[i] );
                        break;
                    }
                    else
                    {
                        printf( "%d, ", Cards[i] );
                    }
                    ++NumRep;
                }
            }
#endif

            CurrentScore.PushMatch( Reps );

            Log.Push();
            for ( INT i = curIdx+CardsLeftTotal-1; i >= (INT)curIdx; --i )
            {
                if ( Valor( (UINT)i ) == Val )
                {
                    Use( i, 1 );
                }
            }

            Match( curIdx );

            Log.Pop();
            Restore( Reps );
        }
        else if ( HayNext( curIdx ) )
        {
            Match ( curIdx + 1 );
        }
    }
    else
    {
        CurrentScore.Score = CloseVal();
        if ( CurrentScore.Score < BestScore.Score )
        {
            BestScore = CurrentScore;

            // Add libres
            if ( UINT FreeCount = CardsLeft(0) )
            {
                BestScore.PushFree();
                for( UINT i=0; i<FreeCount; ++i )
                {
                    BestScore.PushVal( Cards[i] );
                }
            }
        }

#if VERBOSE
        Log.Print( "Libres   = " );
        Print();
        Log.Print( " + New Score = %lu\n",  CloseVal() );
        Log.Print( "- - - - - - - - - \n\n" );
#endif

    }

}

void Mano::Buscar( UINT curIdx )
{
    assert( curIdx < Cards.size() );

#if VERBOSE
    Log.Print("Buscar: ");
    PrintFrom( curIdx, CardsLeft( curIdx ) );
#endif

    // Buscar escaleras de todos los tamanyos
    for ( UINT n = CardsLeft( curIdx ); n >= 3; --n )
    {
        if ( HayEscalera( curIdx, n ) )
        {
#if VERBOSE
            Log.Print( "Escalera = " );
            PrintFrom( curIdx, n );
#endif
            CurrentScore.PushEscalera();

            // Considerar dicha escalera
            Log.Push();
            Use( curIdx, n );
   
            if ( CardsLeft( curIdx ) > 0 )
            {
                Buscar( curIdx );
            }
            else
            {
                Match( 0 );
            }
                       
            Restore( n );
            Log.Pop();
        }
    }

    // Si quedan cartas que no se han probado
    if ( HayNext( curIdx ) )
    {
        Buscar( curIdx+1 );
    }
    else
    {
        // Si no, es hora de matchear repes
        Match( 0 );
    }
}

void Mano::FindBestScore()
{
    std::sort( Cards.begin(), Cards.end() );
    printf( " Ordenada " );
    Print();

CleanDups();
std::sort( Cards.begin(), Cards.end() );
//printf( " Hacked   " );
//Print();

    CurrentScore.Reset();
    BestScore.Reset();
    Buscar( 0 );
    BestScore.Print();   

RestoreDups();
std::sort( Cards.begin(), Cards.end() );
//printf( " Ordenada " );
//Print();
}


int main(int argc, char* argv[])
{
    {
        Mano m;
        m.AddCard( 102 );
        m.AddCard( 103 );
        m.AddCard( 104 );
        m.AddCard( 105 );
        m.AddCard( 205 );
        m.AddCard( 305 );
        m.AddCard( 402 );
        printf( "*******************************************************\n" );
        printf( " MANO     " );
        m.Print();
        //printf( "*******************************************************\n" );
        m.FindBestScore();
        printf("\n");
    }

    if ( 1 )
    {
        Mano m;
        m.AddCard( 102 );
        m.AddCard( 202 );
        m.AddCard( 302 );
        m.AddCard( 105 );
        m.AddCard( 205 );
        m.AddCard( 305 );
        m.AddCard( 405 );
        printf( "*******************************************************\n" );
        printf( " MANO     " );       
        m.Print();
        //printf( "*******************************************************\n" );
        m.FindBestScore();
        printf("\n");
    }

    if ( 1 )
    {
        Mano m;
        m.AddCard( 102 );
        m.AddCard( 103 );
        m.AddCard( 104 );
        m.AddCard( 105 );
m.AddCard( 103 );
m.AddCard( 102 );
        m.AddCard( 202 );
        printf( "*******************************************************\n" );
        printf( " MANO     " );               
        m.Print();
        //printf( "*******************************************************\n" );
        m.FindBestScore();
        printf("\n");
    }

    if ( 1 )
    {
        Mano m;
        m.AddCard( 306 );
        m.AddCard( 402 );
        m.AddCard( 305 );
        m.AddCard( 403 );
        m.AddCard( 307 );
        m.AddCard( 404 );
        m.AddCard( 401 );
        printf( "*******************************************************\n" );
        printf( " MANO     " );               
        m.Print();
        //printf( "*******************************************************\n" );
        m.FindBestScore();
        printf("\n");
    }

    return 0;
}
Título: Re:algoritmo de calculo de manos
Publicado por: angel en 27 de Abril de 2013, 05:06:37 PM
Hola, despues de mirar el codigo de Warchief, me puse manos a la obra a crear mi propio alogatirmo. Lo estoy haciendo en c# porque de paso me sirve para practicar para mi carrrea.

Hasta el momento, solo chequea escaleras:

- chequea cantidad de juegos en escalera.
- conserva juegos por separado.
- devuelve cantidad de cartas en escalera por juego (util para saber si hay chinchon)
- conserva internamente cartas consecutivas que no formen juego (por ejemplo 2 cartas en escalera util para IA de la pc)
- devuelve las cartas que no forman juegos (puntuacion).

Todavia tengo que depurarlo mas y aceitarlo, pero va tomando forma. El tema de los comodines ni idea, porque ahi ando medio perdido. si alguien me tira alguna idea se lo agradeceria.

en cuanto lo termine cuelgo el pseudocodigo asi cualquier puede aportar ideas.

Saludos!




Título: Re:algoritmo de calculo de manos
Publicado por: Warchief en 30 de Abril de 2013, 12:23:58 AM
Cita de: angel en 27 de Abril de 2013, 05:06:37 PM
El tema de los comodines ni idea, porque ahi ando medio perdido. si alguien me tira alguna idea se lo agradeceria.

Simplemente sustituye el comodín, bien por una carta adyacente a otra o bien del mismo número. Luego relanza la búsqueda de jugada con la nueva combinación.

Por ejemplo:

(Notación XYY, X = palo, YY = número de carta)

101 102 204 207 306 309 COM

+ Se convierte en:
101 106 204 207 306 309 101 // si hay más de una baraja
101 106 204 207 306 309 201
101 106 204 207 306 309 301
101 106 204 207 306 309 401

101 106 204 207 306 309 106 // si hay más de una baraja
101 106 204 207 306 309 206
101 106 204 207 306 309 306
101 106 204 207 306 309 406

etc. para tríos. Y...

101 106 204 207 306 309 102
101 106 204 207 306 309 105
101 106 204 207 306 309 107
101 106 204 207 306 309 203
etc. para escaleras



Si tienes múltiples comodines, lo mismo pero con combinaciones.
Título: Re:algoritmo de calculo de manos
Publicado por: angel en 30 de Abril de 2013, 01:45:47 PM
Hola Warchief, creo que lo voy asimilando jejeje....

1. Cuento cantidad de comodines en la mano.
2. copio la cantidad de comodines a una variable temporal.
3. busco escalera preguntando por carta siguiente o por comodin.
4. si efectivamente no hay carta siguiente, pero si comodin. le resto 1 a la variable temporal del comodin.

Con esto no relanzaria la busqueda, ya que simplemente el comodin entra al grupo de cartas en juego al menos hasta ese momento.

Tendria que ver como implementarlo y probarlo. El tema es preguntar si hay comodin en el mismo if de comparacion.

A ver si te parece que puede ser asi, igual voy a probarlo en cuanto pueda....


Gracias nuevamente por toda tu ayuda Warchief!

Saludos!.-

Edit:
Al parece funciona agregando los comodines de la manera que digo. Pero encontre un error en la busqueda de escaleras... cuando hay 2 juegos correlativos seguidos por una carta faltante por ejemplo: 1,2,3,4   -no hay 5-   6, 7, 8. el segundo juego no lo encuentra. no pasa si fuese asi:   1,2,3,4    -no hay 5 ni 6 -    7,8,9  asi que tengo que revisar eso.

Edit 2:
Ya funciona todo correcto las esclares + comodin (era un problema en el for). No era n tan simple, faltaban varios detalles con respecto al comodin. Quedara en 2 o 3 rutinas en total los chequeos. Si alguien le interesa seguire repontando como va todo.

Saludos!.-