Évaluer un skat-hand

18

introduction

Skat est un jeu de cartes traditionnel allemand pour 3 joueurs. Le jeu se compose de 32 cartes: Ace, King, Queen, Jack, 10, 9, 8, 7 dans les 4 combinaisons (clubs, pique, coeurs, diamants).

À chaque tour, un joueur joue en solo tandis que les deux autres jouent contre lui. Au début d'un tour, chaque joueur reçoit 10 cartes, les 2 cartes restantes sont appelées le patin et sont placées face cachée au milieu. Le joueur solo est déterminé par une phase d'enchères. C'est la partie du jeu que vous devrez gérer dans ce défi, plus de détails à ce sujet ci-dessous.

Le joueur qui remporte la phase d'enchères devient le joueur solo. Il ramasse le patin puis laisse tomber deux cartes (qui peuvent être les mêmes, l'autre équipe ne le sait pas), choisit l'atout et le tour commence.

Un tour se compose de dix tours. Le joueur qui remporte un tour mène le suivant jusqu'à ce que toutes les cartes soient jouées. Je n'expliquerai pas les règles ici, mais sachez qu'avoir beaucoup d'atouts est bien. Si vous voulez en savoir plus sur les règles, consultez l'article Wikipedia que j'ai lié au début de cet article, mais ce n'est pas nécessaire pour ce défi.

Le défi

Vous voulez apprendre à vos deux fils à jouer au skat. Les règles ne sont pas si difficiles, alors elles s'y mettent rapidement. La seule chose qui leur donne du fil à retordre est l'enchère, calculant spécifiquement la valeur de jeu de leur main. Vous décidez donc d'écrire un petit programme qui génère la valeur de jeu maximale qu'ils peuvent miser compte tenu de leur main actuelle.

Calcul de la valeur du jeu

Chaque main a une certaine valeur de jeu. Il est déterminé par la quantité de prises séquentielles que vous avez et la combinaison que vous souhaitez choisir comme atout. Commençons par le premier facteur, les prises!

Le facteur Jack

Les crics sont toujours des atouts, et ils battent tous les autres atouts. L'ordre de force entre les quatre crics est le suivant:

  1. Jack of Clubs (le plus élevé)
  2. Jack of Spades
  3. Jack of Hearts
  4. Jack of Diamonds (le plus bas)

Dans l'explication complémentaire, je les mentionnerai avec les numéros que je leur ai attribués ici.

Vous vous souvenez qu'il y a une sorte de facteur que vous obtenez des Jacks dans votre main qui fait partie de la valeur du jeu? Génial! Voici comment l'obtenir:

Ce facteur de prise est le nombre de prises supérieures (voir l'ordre ci-dessus) dans l'ordre, plus 1. Donc, si vous avez les 4 prises, c'est 4 + 1 = 5. Si vous n'avez que les 2 premières prises, c'est 2 + 1 = 3.

Alternativement, pour rendre les choses un peu plus compliquées, le facteur Jack peut également être le nombre de premiers Jacks dans l'ordre qui vous manque , plus 1. Donc si vous manquez le premier, c'est 1 + 1 = 2. Si vous il manque les 3 premiers, c'est 3 + 1 = 4. Voici quelques exemples, en utilisant la numérotation ci-dessus:

[1, 4] -> 1 + 1 = 2
[1, 2, 4] -> 2 + 1 = 3
[2, 3, 4] -> 1 + 1 = 2
[1, 2, 3, 4] -> 4 + 1 = 5
[] -> 4 + 1 = 5

C'était le premier facteur. Voici comment vous obtenez le 2ème:

Le facteur Trump Suit

Celui-ci est beaucoup plus simple. Le 2ème facteur est déterminé par l'atout que le joueur solo choisit en utilisant la cartographie suivante:

Clubs    -> 12
Spades   -> 11
Hearts   -> 10
Diamonds ->  9

C'était facile, non?

La valeur du jeu

La valeur du jeu est le produit des deux facteurs. Vous pensez assez facile? Faux! Alors que le facteur Jack est fixe, le facteur costume ne l'est pas. Le costume que vous finissez par choisir comme atout dépend de la quantité d'atouts et de la valeur de vos cartes non-atouts dans votre main. Il serait bien trop compliqué d'expliquer à quoi ressemble une bonne main, vous utiliserez donc l'algorithme suivant:

L'algorithme Which-Trump-do-I-Pick

Vous n'êtes pas obligé de participer aux enchères. Si vous décidez que votre main est trop mauvaise pour jouer en solo, vous pouvez simplement passer. Votre main doit correspondre aux critères suivants pour être jouable:

  • Avoir au moins 6 atouts (les cartes de l'atout que vous choisissez + le nombre de valets). Si cela est possible pour plusieurs combinaisons, choisissez celle qui résulterait en plus d'atouts. S'il y a toujours une égalité, choisissez la combinaison avec la note la plus élevée donnée ci-dessus.

  • Sur les cartes non-atouts, ayez au moins 1 As.

Si votre main ne correspond pas à ces deux critères, vous réussirez. Si c'est le cas, vous afficherez la valeur de jeu calculée et le costume d'atout choisi.

Note courte: Bien sûr, c'est un algorithme très simplifié. Il faut beaucoup trop de stratégie et d'expérience pour juger une main que nous ne pourrions jamais couvrir dans un défi comme celui-ci.

Contribution

Chaque carte a un identifiant unique. La première partie est la combinaison ( C lubs, S pades, H earts, D iamonds), la deuxième partie est la valeur qui est donnée par ce mapping:

Ace -> A
King -> K
Queen -> Q
Jack -> J
10 -> 0
9 -> 9
8 -> 8
7 -> 7

Les deux parties combinées forment une seule carte. La valeur vient en premier, puis vient le costume. Vous pouvez prendre les cartes dans n'importe quel format comme vous le souhaitez.

Production

Si la main est jouable, sortez la valeur du jeu et le costume d'atout choisi (l'ordre n'a pas d'importance). Si ce n'est pas le cas, sortez "pass".

Règles

  • Comme mentionné, vous pouvez prendre l'entrée dans le format le plus pratique pour vous. Voir les exemples ci-dessous dans les cas de test.
  • L'entrée peut être fournie par des arguments de ligne de commande, des entrées utilisateur ou des arguments de fonction.
  • La sortie peut être fournie comme valeur de retour ou peut simplement être imprimée sur l'écran.
  • Les cartes en entrée ne peuvent en aucun cas être commandées. Votre programme doit pouvoir traiter toute commande de carte aléatoire.
  • Le nombre d'octets le plus bas gagne!

Cas de test

L'entrée dans les cas de test sera une liste de chaînes de 2 caractères.

1. ["JC", "JS", "JD", "AC", "KC", "9C", "AS", "7H", "QD", "8D"] -> 36 Clubs
2. ["JD", "AS", "0S", "KS", "QS", "9S", "8S", "AD", "8C", "9C"] -> 44 Spades
3. ["JH", "JD", "0S", "KS", "9C", "8C", "QH", "KH", "AD", "9D"] -> pass
4. ["JD", "AS", "KS", "QS", "0S", "9S", "8D", "7D", "0C", "QH"] -> pass

Explication:

  1. Deux crics d'affilée avec des clubs comme atout. La valeur du jeu est donc 3 x 12 = 36
  2. Trois Jacks d'affilée manquant avec Spades comme atout. La valeur du jeu est donc 4 x 11 = 44
  3. Seul un maximum de 4 atouts est possible, vous passerez donc.
  4. Six atouts avec pique mais pas d'as non-atout, vous passerez donc.

Si certaines règles ne sont pas claires, allez-y et commentez. J'ai grandi avec ce jeu, donc il m'est difficile de juger si j'ai tout décrit avec suffisamment de détails.

Et maintenant ... Happy Coding!

edit: Comme indiqué dans les commentaires (grâce à isaacg), il y a une règle qui compte les meilleurs atouts suivants après les 4 Jacks dans le "Jack-factor" afin qu'il puisse aller jusqu'à 11. Pour garder ce défi simple et pour ne pas confondre les gens, les règles que j'ai proposées à l'origine resteront telles quelles. Le facteur maximum reste donc à 5.

Denker
la source
6
Bienvenue dans Programming Puzzles & Code Golf — excellent premier défi! :)
Poignée de porte
1
Le nombre de prises droites / prises manquantes doit-il également inclure les atouts de la combinaison supérieure dans l'ordre? C'est ce que wikipedia dit ici
isaacg
@isaacg Je dois admettre que je ne connaissais pas cette règle jusqu'à présent. Merci d'avoir fait remarquer cela. J'ai fait quelques recherches et vous avez bien raison. Dans ma famille, nous ne jouons pas avec cette règle et je n'ai rencontré personne qui joue avec elle non plus. Cela n'a pas une grande pertinence, car lorsque vous avez une telle main, vous jouerez la plupart du temps Grand qui est de toute façon différent. Donc, pour ce défi, nous resterons simplement avec les règles que j'ai proposées. Je vais modifier mon message pour qu'il soit clair pour tout le monde.
Denker
1
@DenkerAffe, j'ai joué au Skat pendant de nombreuses années dans un club en Allemagne, et croyez-moi, la règle est importante, et il y a des cas où elle est extrêmement pertinente (et oui, elle est inconnue chez la plupart des joueurs non sérieux). Surtout avec le côté manquant - imaginez que vous avez l'atout K, D, 9, 8, 7 et trois A et deux 10 dans les autres couleurs. Votre Grand meurt à coup sûr, mais vous pouvez jouer à 'ohne 6' (collecter des contra) et les battre, en supposant que vous avez une idée de la position du B à partir de l'enchère. Et vous pouvez enchérir jusqu'à ce que le soleil arrive avec cette carte.
Aganju
@Aganju J'ai déjà supposé que cette règle n'était pas connue de la plupart des joueurs amateurs. Merçi pour la confirmation. Je ne doute pas que ce soit important, mais d'après mon expérience, les mains comme celle-ci sont assez rares, donc la règle n'entre pas en jeu si souvent.
Denker

Réponses:

1

Python 2, exemple d'implémentation

Puisqu'il n'y a pas encore de soumissions, j'ai noté un exemple d'implémentation en Python. Le format d'entrée est le même que dans les cas de test du défi.

Peut-être que cela vous motive à commencer, ce n'est pas si difficile :)

def gameValue(hand):
    jacks = ""
    suits = {"C" : 0, "S" : 0, "H" : 0, "D" : 0}
    # Loop through the hand, find all jacks and count the cards of each suit
    for card in hand:
        jacks += card[1] if "J" in card else ""
        suits[card[1]] += 1 if card[0] != "J" else 0

    # Map the Jacks to numbers while 1 is the highest (Clubs) then sort them ascending
    jacks =  sorted(map(lambda j: {"C" : 1, "S" : 2, "H" : 3, "D" : 4}[j], list(jacks)))

    # Sort the suits by amount. Highest amount and value is first after that
    suits = sorted(suits.items(), key = lambda suit: suit[1], reverse = True)
    trumpSuit = suits[0][0];
    # Amount of trumps is jack-count plus trumpsuit-count
    trumpCount = len(jacks) + suits[0][1];

    # Check for at least one ace that is no trump
    hasAce  = len(filter(lambda c: c[0] == "A" and c[1] != trumpSuit, hand)) >= 1

    # If the hand  is playable, calculate jack-factor and output the result, otherwise pass
    if trumpCount >= 6 and hasAce:
        # If there no jacks the factor is 5. If there are, find the first gap
        if len(jacks) > 0:
            lastJack = 0
            for jack in jacks:
                if jack - lastJack >= 2:
                    break
                lastJack = jack

            jackFactor = jacks[0] if lastJack == 0 else lastJack + 1
        else:
            jackFactor = 5

        trumpFactor = {"C" : 12, "S" : 11, "H" : 10, "D" : 9}[suits[0][0]]
        print str(trumpFactor * jackFactor) + " " + {12 : "Clubs", 11 : "Spades", 10 : "Hearts", 9 : "Diamonds"}[trumpFactor]
    else:
        print "pass"
Denker
la source
0

Java, 256 octets

h->{int i,j=1,m=0,t,n=0,a[]=new int[8];for(var c:h){t=c[1]-48;if(c[0]==74){j+=1<<t;n++;}else{m+=i=c[0]==65?1:0;a[--t+4]+=i;a[t]++;}}for(i=t=0;i<4;i++)t=a[i]<a[t]?t:i;return a[t]+n<6|m-a[t+4]<1?"p":(t+++9)*(5-(int)(Math.log(j>7?~j&7:j)/Math.log(2)))+" "+t;}

Prend entrée comme un tableau de tableaux de caractères dans le format A4, où 4est Clubs , 3est pique , 2est coeurs et 1est Diamonds . La sortie est 36 4pour une offre de 36 avec des atouts Clubs , ppour passer.

Essayez-le en ligne ici .

Version non golfée:

h -> { // lambda taking a char[][] as argument and returning a String
    int i,                // used as a loop variable and as a temporary variable
        j = 1,            // variable storing the jacks present in the hand in its four last-to-least significant bits
        m = 0,            // number of aces in the hand
        t,                // used as a temporary variable at first, later stores the trump suit
        n = 0,            // number of jacks in the hand
        a[] = new int[8]; // in the lower 4 indices, stores the number of non-jack cards present in the hand for each suit; in the higher 4 indices, stores the number of aces present in the hand for each suit (0 or 1)

    for(var c : h) {   // loop over all the cards in the hand
        t = c[1] - 48; // determine the suit of the current card; 48 is the ASCII code for '0'
        if(c[0] == 74) { // if it's a jack; 74 is the ASCII code for 'J'
            j += 1 << t; // set the corresponding bit
            n++;         // and increment the total number of jacks
        } else {                             // if it's not a jack
            m += (i = (c[0] == 65 ? 1 : 0)); // increment the total number of aces if it's an ace (65 is the ASCII code for 'A')
            a[ --t + 4] += i;                // increment the number of aces for this suit if it's an ace
            a[t]++;                          // increment the number of non-jack cards for this suit
        }
    }

    for(i = t = 0; i < 4; i++)     // loop over the suits ...
        t = (a[i] < a[t]) ? t : i; // ... and find the one with the most cards, giving priority to higher-valued suits in case of a tie

    return (a[t] + n < 6) |                                             // if there are less than 6 trump cards
           (m - a[t + 4] < 1) ?                                         // or less than 1 non-trump ace
           "p"                                                          // return "p" to pass on the hand
           :                                                            // else return
           ((t++ + 9) *                                                 // the value of the trump suit (and increment the trump suit for output later)
           (5 - (int) (Math.log((j > 7) ? (~j & 7) : j) / Math.log(2))) // times the jack factor
           + " " + t);                                                  // followed by the trump suit
}
OOBalance
la source
0

C, 235 octets

f(char*h){int i,j=1,m=0,t,n=0,a[8]={0};for(;*h;h+=2){t=h[1]-48;if(*h-74){m+=i=*h==65;a[--t+4]+=i;a[t]++;}else{j+=1<<t;n++;}}for(i=t=0;i<4;i++)t=a[i]<a[t]?t:i;printf(a[t]+n<6|m-a[t+4]<1?"p":"%d %d",(t+9)*(5-(int)log2(j>7?~j&7:j)),t+1);}

Port de ma réponse Java .

Essayez-le en ligne ici .

Prend entrée comme un tableau de caractères dans le format A4, où 4est Clubs , 3est pique , 2est coeurs et 1est Diamonds . La sortie est 36 4pour une offre de 36 avec des atouts Clubs , ppour passer.

Version non golfée:

f(char* h) { // function taking an array of characters as argument (and implicitly returning an unused int)
    int i,          // used as a loop variable and as a temporary variable
        j = 1,      // variable storing the jacks present in the hand in its four last-to-least significant bits
        m = 0,      // number of aces in the hand
        t,          // used as a temporary variable at first, later stores the trump suit
        n = 0,      // number of jacks in the hand
        a[8] = {0}; // in the lower 4 indices, stores the number of non-jack cards present in the hand for each suit; in the higher 4 indices, stores the number of aces present in the hand for each suit (0 or 1); partially initialized to zero, the compiler will do the rest

    for(; *h; h += 2) { // loop over all the cards in the hand
        t = h[1] - 48;  // determine the suit of the current card; 48 is the ASCII code for '0'
        if(*h - 74) {              // if it's not a jack; 74 is the ASCII code for 'J'
            m += (i = (*h == 65)); // increment the total number of aces if it's an ace (65 is the ASCII code for 'A')
            a[ --t + 4] += i;      // increment the number of aces for this suit if it's an ace
            a[t]++;                // increment the number of non-jack cards for this suit
        } else {         // if it's a jack
            j += 1 << t; // set the corresponding bit
            n++;         // and increment the total number of jacks
        }
    }

    for(i = t = 0; i < 4; i++)   // loop over the suits ...
        t = a[i] < a[t] ? t : i; // ... and find the one with the most cards, giving priority to higher-valued suits in case of a tie

    printf( (a[t] + n) < 6 |                             // if there are less than 6 trump cards
            (m - a[t + 4] < 1) ?                         // or less than 1 non-trump ace
            "p" : "%d %d",                               // print "p" to pass on the hand, else print two numbers
            (t + 9) *                                    // first the value of the trump suit ...
            (5 - (int) log2((j > 7) ? (~j & 7) : j)),    // ... times the jack factor,
            t + 1                                     ); // followed by the trump suit
}
OOBalance
la source
226 octets
plafond du