Partage

Poker

Identifier une main, comparer deux mains

20 juin 2011 à 10:27:22

Bonjour

Petit exercice sympa inspiré d'un exercice du projet Euler.

Énoncé


L'exercice est à résoudre en Python et est composé des deux questions suivantes.

---------------------------------------------------------------------------------------------------
1) On vous donne au Poker une main de 5 cartes et le programme doit identifier la nature de la main parmi les neuf combinaisons possibles (quinte, carré, etc, cf. la liste ci-dessous).

2) On vous donne deux mains de 5 cartes issues d'un même jeu de 52 cartes et le programme doit dire quelle est la main qui gagne (ou s'il y a égalité, ce qui est possible). Attention, je ne donnerai pas toutes les règles de gain d'une main sur une autre, se référer à l'article correspondant de wikipedia pour les détails manquants.
---------------------------------------------------------------------------------------------------


Rappels




Au poker, chaque joueur reçoit 5 cartes qui forment ce qu'on appelle une main. Les différentes mains se répartissent en 9 combinaisons, par ordre décroissant de valeur :

1. Quinte
2. Carré
3. Full
4. Couleur
5. Suite
6. Brelan
7. Double paire
8. Paire
9. Carte haute


Attention, bien que cette règle ne soit pas universellement admise, dans le cas de cartes consécutives, l'As a une situation particulière : il peut être supérieur au Roi mais aussi représenter la carte 1 et donc être la carte la plus faible du jeu.


Pour savoir qui l'emporte de deux mains de même niveau (par exemple deux brelans), on regarde «la» carte la plus forte (voir les détails dans l'article de Wikipedia ci-dessus).

Détails



  • Vous êtes libre de noter les rangs des cartes comme vous le souhaitez. Je suggère 1 pour As, R pour Roi, 7 pour la carte 7, etc.
  • Pour les couleurs, je suggère
    p = pique, c= cœur, k = carreau, t = trèfle
  • Par conséquent, avec les notations ci-dessus, un valet de pique se notera Vp. Mais je répète, vous pouvez utiliser une notation plus adaptée à Python, par exemple un tuple ('V', 'p')
  • Il est souhaitable que ce soient des fonctions (ou à la rigueur des méthodes si vous tenez à écrire votre code avec des classes) qui exécutent chacune des taches des questions 1 et 2.
  • Pour la génération d'une main, c'est sans importance,
    • ou bien vous écrivez vous-même une main dans le code,
    • ou bien vous demandez à l'utilisateur d'entrer une main, genre
      Rp 5t Dc Rt 5c
    • ou bien vous écrivez un générateur aléatoire de mains.

    La première forme a ma préférence.
  • Dans votre solution, veuillez préciser quelle version de Python vous utilisez (tout le monde n'utilise pas la version 3 de Python !)



20 juin 2011 à 10:53:35

Salut.

Il a l'air sympa cet exo (plus difficile qu'il n'en a l'air de prime abord). :)

J'essayerai d'y consacrer un peu de temps quand j'en aurai l'occasion. On pourrait même envisager de faire évoluer ça en un assistant de jeu ou un truc un peu plus concrêt… :p
Zeste de Savoir, le site qui en a dans le citron !
20 juin 2011 à 11:04:30

oui difficile,
j'en avais fait un avec pygame, je vais essayer de le retrouver à moins qu'il ne soit sur le DD qui à grillé ... :(
...

retrouvé !!
mais je pige pas une ligne de ce que j'ai codé ( ça m'apprendra à ne pas commenter ^^ ) ... Bon ben, à refaire.
20 juin 2011 à 17:20:58

C'est si difficile que ça ? Non, franchement, c'est pas très dur à coder disons "basiquement", c'est tout juste un peu long et un peu technique.

Ce qui est certainement plus difficile c'est de connaître suffisamment Python pour optimiser le code à produire. Par exemple pour le premier exo, si on trouve un carré, a priori on n'a pas à chercher si c'est un carré de Valets ou d'autre chose. Par contre, pour le deuxième exo, il peut arriver qu'on ait besoin de savoir de quel carré il s'agit si l'autre main est aussi un carré. Donc je ne sais pas si c'est faisable, l'idée serait d'utiliser le code du premier exo, en le complétant, le décorant ou je-ne-sais-quoi pour écrire le second.



Déjà, voici un code pour la première question, mais pas testé intensivement :


# -*- coding: utf-8 -*-
# python 2.7

CODES = {'11111': None, '1112': 'Paire', '122': 'Deux paires',
         '113': 'Brelan', '23': 'Full', '14': u"Carré"}


def chercherRepet(rangs):
    # Renvoie un élément de CODES
    s = set(rangs)
    mult = []
    for c in s:
        mult.append(str(rangs.count(c)))
    return ''.join(sorted(mult))


def rangs_couleurs(main):
    # renvoie
    # rangs (As, Roi, etc) de la main
    # couleurs (pique, etc) de la main
    rangs = []
    couleurs = []
    for carte in main:
        rangs.append(carte[:-1])
        couleurs.append(carte[-1])
    return (rangs, couleurs)


def estSuite(rangs):
    # examine si une liste de rangs est une suite de cartes consécutives
    rangs = set(rangs)
    for (f, v) in [('V', 11), ('D', 12), ('R', 13)]:
        if f in rangs:
            rangs.discard(f)
            rangs.add(v)
    rangs = sorted([int(r) for r in rangs])
    debut = int(rangs[0])
    return rangs == range(debut, debut + 5) or rangs == [1, 10, 11, 12,
            13]


def valeur(main):
    # examine ce que vaut la main (une quinte, un carré, etc)
    (rangs, couleurs) = rangs_couleurs(main)
    resultat = CODES[chercherRepet(rangs)]
    if resultat:
        return resultat
    else:
        suite = estSuite(rangs)
        if len(set(couleurs)) == 1:
            if suite:
                return 'Quinte flush'
            else:
                return 'Couleur'
        elif suite:
            return 'Suite'
        else:
            return 'Carte Haute'


test=[
    ["8c","7c","6c","5c","4c"],
    ["1c","Rc","Dc","Vc","10c"],
    ["4p","3p","1p","5p","2p"],
    ['Rp','Rc','Rt','Rk','3p'], 
    ['1p','1c','1t','1k','3k'],
    ['Rp','Rc','Rt','3t','3p'],
    ['Rk','10k','8k','4k','3k'],
    ['8t','7p','6p','5k','4k'],
    ['Rp','Rk','Rt','Dp','5t'],
    ['Rp','Rt','Dt','8t','8k'],
    ['8t','8k','Rp','Dp','5t'],
    ['10t','10k','Rp','Dp','5t'],
    ['Rp','Dp','8c','6k','5t']
    ]

for main in test:
    r = ''
    for c in main:
        r += '%3s ' % c
    print r + ' : %s' % valeur(main)


[Les exemples viennent de Wikipedia cité dans mon énoncé]

8c  7c  6c  5c  4c  : Quinte flush
 1c  Rc  Dc  Vc 10c  : Quinte flush
 4p  3p  1p  5p  2p  : Quinte flush
 Rp  Rc  Rt  Rk  3p  : Carré
 1p  1c  1t  1k  3k  : Carré
 Rp  Rc  Rt  3t  3p  : Full
 Rk 10k  8k  4k  3k  : Couleur
 8t  7p  6p  5k  4k  : Suite
 Rp  Rk  Rt  Dp  5t  : Brelan
 Rp  Rt  Dt  8t  8k  : Deux paires
 8t  8k  Rp  Dp  5t  : Paire
10t 10k  Rp  Dp  5t  : Paire
 Rp  Dp  8c  6k  5t  : Carte Haute



EDIT : pour la comparaison de deux mains, c'est pas très dur en soi mais il y a de quoi s'amuser avec Python en créant une classe Poker et implémenter les méthodes spéciales __le__ et __lt__ .
20 juin 2011 à 17:42:35

Disons que ce n'est pas "difficile" en soi à coder de façon basique (la problématique est simple), mais pour ce genre d'exo, je pense que le plus intéressant est de trouver une solution élégante et concise, ce qui n'est pas forcément évident.
Zeste de Savoir, le site qui en a dans le citron !
21 juin 2011 à 0:29:01

python 2

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Main(object):
    
    force = {(1,1,1,1,1):'CARTE',
             (2,1,1,1):'PAIRE',
             (2,2,1):'DEUX PAIRES',
             (3,1,1):'BRELAN',
             (3,1,2,0):'SUITE',
             (3,1,2,1):'SUITE',
             (3,1,2,2):'COULEUR',
             (3,2):'FULL',
             (4,1):'CARRE',
             (5,0):'QUINTE FLUSH',
             (5,1):'QUINTE FLUSH'}
    
    def __init__(self,cartes):
        valeur,couleur = zip(*cartes)
        self.set = sorted([(valeur.count(v),v)for v in set(valeur)],reverse=1)
        self.force,_ = zip(*self.set)
        if self.force == (1,1,1,1,1):
            C = len(set(couleur)) == 1 # teste si c'est une couleur
            S = max(valeur)-min(valeur) == 4 # teste si c'est une suite
            spe = sorted(valeur) == [2,3,4,5,14] # teste si c'est une suite à hauteur 5
            if not C:
                if spe or S: self.force = (3,1,2)+((0,) if spe else (1,))
            elif spe or S: self.force = (5,)+((0,) if spe else (1,))
            else: self.force = (3,1,2,2)
    
    def __repr__(self):
        # retourne le nom de la Main
        return Main.force[self.force]

    def win(self,other):
        #Main.win(other) ==> Bool
        #retourne True si Main l'emporte sur other
        return (self.set > other.set) if self.force == other.force else (self.force > other.force)

VAL = ('','','2','3','4','5','6','7','8','9','10','VALET','DAME','ROI','AS')
COL = ('COEUR','CARREAU','PIQUE','TREFLE')

test=[
    [(8,0),(7,0),(6,0),(5,0),(4,0)],
    [(14,0),(13,0),(12,0),(11,0),(10,0)],
    [(4,2),(3,2),(14,2),(5,2),(2,2)],
    [(13,2),(13,0),(13,3),(13,1),(3,2)], 
    [(14,2),(14,0),(14,3),(14,1),(3,1)],
    [(13,2),(13,0),(13,3),(3,3),(3,2)],
    [(13,1),(10,1),(8,1),(4,1),(3,1)],
    [(8,3),(7,2),(6,2),(5,1),(4,1)],
    [(13,2),(13,1),(13,3),(12,2),(5,3)],
    [(13,2),(13,3),(12,3),(8,3),(8,1)],
    [(8,3),(8,1),(13,2),(12,2),(5,3)],
    [(10,3),(10,1),(13,2),(12,2),(5,3)],
    [(13,2),(12,2),(8,0),(6,1),(5,3)]
    ]

for m in test:
    for v,c in m: print VAL[v],COL[c],' ',
    print ': ',Main(m)


8 COEUR   7 COEUR   6 COEUR   5 COEUR   4 COEUR   :  QUINTE FLUSH
AS COEUR   ROI COEUR   DAME COEUR   VALET COEUR   10 COEUR   :  QUINTE FLUSH
4 PIQUE   3 PIQUE   AS PIQUE   5 PIQUE   2 PIQUE   :  QUINTE FLUSH
ROI PIQUE   ROI COEUR   ROI TREFLE   ROI CARREAU   3 PIQUE   :  CARRE
AS PIQUE   AS COEUR   AS TREFLE   AS CARREAU   3 CARREAU   :  CARRE
ROI PIQUE   ROI COEUR   ROI TREFLE   3 TREFLE   3 PIQUE   :  FULL
ROI CARREAU   10 CARREAU   8 CARREAU   4 CARREAU   3 CARREAU   :  COULEUR
8 TREFLE   7 PIQUE   6 PIQUE   5 CARREAU   4 CARREAU   :  SUITE
ROI PIQUE   ROI CARREAU   ROI TREFLE   DAME PIQUE   5 TREFLE   :  BRELAN
ROI PIQUE   ROI TREFLE   DAME TREFLE   8 TREFLE   8 CARREAU   :  DEUX PAIRES
8 TREFLE   8 CARREAU   ROI PIQUE   DAME PIQUE   5 TREFLE   :  PAIRE
10 TREFLE   10 CARREAU   ROI PIQUE   DAME PIQUE   5 TREFLE   :  PAIRE
ROI PIQUE   DAME PIQUE   8 COEUR   6 CARREAU   5 TREFLE   :  CARTE
21 juin 2011 à 1:01:22

Oh, du Java.
Bon, j'avais pas très envie de le faire en Python, donc j'avais commencé en OCaml et puis j'ai arrêté parce que j'avais autre chose à faire, et comme je rajais j'ai supprimé, bref, j'explique vite fait : l'idée cool était une fonction qui était une sorte de groupby améliorée. Elle prenait une liste et renvoyait la liste des listes d'éléments dont l'image par une certaine fonction était identique. À partir de ça, j'identifiais très facilement la couleur, et en regroupant par valeurs et en regardant les longueurs des listes je pouvais aussi identifier les combinaisons.

Ensuite, étant donnée une main, je trouvais la combinaison qu'elle représentait et je triais les cartes selon l'ordre de comparaison (en cas d'égalité) : la liste de listes précédente était très utile pour ça, avec reduce et map on le fait en une ligne pour chaque cas.
Ensuite, il suffit de parcourir linéairement les listes jusqu'à ce qu'on arrive sur une inégalité.
21 juin 2011 à 1:45:36

Citation : josmiley


#!/usr/bin/env python
# -*- coding: utf-8 -*-

   force = {(1,1,1,1,1):'CARTE',
             (2,1,1,1):'PAIRE',
             (2,2,1):'DEUX PAIRES',
             (3,1,1):'BRELAN',
             (3,1,2,0):'SUITE',
             (3,1,2,1):'SUITE',
             (3,1,2,2):'COULEUR',
             (3,2):'FULL',
             (4,1):'CARRE',
             (5,0):'QUINTE FLUSH',
             (5,1):'QUINTE FLUSH'}
    
    def __init__(self,cartes):
        valeur,couleur = zip(*cartes)
        self.set = sorted([(valeur.count(v),v)for v in set(valeur)],reverse=1)
        self.force,_ = zip(*self.set)
        if self.force == (1,1,1,1,1):
            C = len(set(couleur)) == 1
            S = max(valeur)-min(valeur) == 4
            spe = sorted(valeur) == [2,3,4,5,14]
            if not C:
                if spe or S: self.force = (3,1,2)+((0,) if spe else (1,))
            elif spe or S: self.force = (5,)+((0,) if spe else (1,))
            else: self.force = (3,1,2,2)
    
    def __repr__(self):
        # retourne le nom de la Main
        return Main.force[self.force]

    def win(self,other):
        #Main.win(other) ==> Bool
        #retourne True si Main l'emporte sur other
        return (self.set > other.set) if self.force == other.force else (self.force > other.force)




Désolé mais je n'aime pas trop cette façon de coder : on ne voit pas du tout l'algorithme (peu de découpage), le codage en début de classe est peu compréhensible. C'est certes concis mais pas lisible (enfin, c'est mon point de vue).


Voici mon code pour la question 2. Pas testé intensément, serais pas étonné qu'il subsiste des erreurs. Je n'en suis pas totalement content car j'utilise deux fois la fonction main_triee. On pourrait toutefois y remédier facilement en créant une classe Main (ou Hand plutôt, ce serait moins confusant) et puis tant qu'on y est les méthodes spéciales qui vont bien, mais bon, je trouve que c'est juste de la déco ici (modulo ma redondance de code).


# -*- coding: utf-8 -*-
# python 2.7

ORDRE = ['Carte Haute', 'Paire', 'Deux paires', 'Brelan', 'Suite',
         'Couleur', 'Full', u"Carré", 'Quinte flush']

POSITION = dict([(v, i) for (i, v) in enumerate(ORDRE)])  # genre POSITION['Suite']=4

# Pour les combinaisons avec des cartes répétées
CODES = {'11111': None, '2111': ORDRE[1], '221': ORDRE[2],
         '311': ORDRE[3], '32': ORDRE[6], '41': ORDRE[7]}

# Convertir les cartes en entiers de 2 à 14 (l'As)
CONV = dict([(str(i), i) for i in range(1, 11)] + zip('VDR1', range(11,
            15)))


def main_triee(rangs):
    # trie une main en commençant par les répétitions
    # les plus nombreuses
    s = set(rangs)
    mult = []
    for c in s:
        mult.append((rangs.count(c), CONV[c]))

    def comp(x, y):
        (m1, v1, m2, v2) = x + y
        if m1 != m2:
            return -cmp(m1, m2)
        else:
            return cmp(v1, v2)

    return sorted(mult, cmp=comp)


def rangs_couleurs(main):
    # renvoie
    # rangs (As, Roi, etc) de la main
    # couleurs (pique, etc) de la main
    rangs = []
    couleurs = []
    for carte in main:
        rangs.append(carte[:-1])
        couleurs.append(carte[-1])
    return (rangs, couleurs)


def estSuite(rangs):
    # examine si une liste de rangs est une suite de cartes consécutives
    rangs = set(rangs)
    for (f, v) in [('V', 11), ('D', 12), ('R', 13)]:
        if f in rangs:
            rangs.discard(f)
            rangs.add(v)
    rangs = sorted([int(r) for r in rangs])
    debut = int(rangs[0])
    return rangs == range(debut, debut + 5) or rangs == [1, 10, 11, 12,
            13]


def valeur(main):
    # examine ce que vaut la main (une quinte, un carré, etc)
    (rangs, couleurs) = rangs_couleurs(main)
    codeRepet = ''.join([str(m) for (m, _) in main_triee(rangs)])
    comb_repet = CODES[codeRepet]
    if comb_repet:
        return comb_repet
    else:
        suite = estSuite(rangs)
        if len(set(couleurs)) == 1:
            if suite:
                return ORDRE[8]
            else:
                return ORDRE[5]
        elif suite:
            return ORDRE[4]
        else:
            return ORDRE[0]


def gagnant(main1, main2):
    # Renvoie la main gagnante (ou les deux en cas d'égalité)
    # Si les deux mains sont des combinaisons distinctes (carré vs brelan par exemple)
    # on sait qui gagne.
    # Sinon, il faut traiter les cas de mains de même combinaison (brelan vs brelan par exemple)
    # et il suffit de comparer les mains triées.
    (v1, v2) = (valeur(main1), valeur(main2))
    if v1 != v2:
        return main2 if POSITION[v1] < POSITION[v2] else main1
    else:
        (rangs1, _) = rangs_couleurs(main1)
        (rangs2, _) = rangs_couleurs(main2)
        (mt1, mt2) = (main_triee(rangs1), main_triee(rangs2))
        if mt1 != mt2:
            return main2 if mt1 < mt2 else main1
        else:
            return (main1, main2)

test=[
    (["4c","Rp","6t","1k","3p"],["2c","Rk","1t","5c","4p"]),# mains quelconques
    (["4c","Rp","2t","4k","3p"],["4p","Rk","1t","4t","5p"]),# paire vs paire
    (["4c","Rp","Rt","4k","3p"],["Rc","Rk","1t","4t","5p"]),# paires vs paire
    (["4c","Rp","Rt","4k","3p"],["4p","Rk","Rc","2t","4t"]),# paires vs paires
    (["4c","Rp","Rt","4k","3p"],["4p","Rk","Rc","1t","4t"]),# paires vs paires
    (["4c","Rp","Rt","4k","1p"],["4p","Rk","Rc","1t","4t"]),# paires vs paires
    (["4c","1p","1t","4k","3p"],["Rc","Rk","Rt","4t","5p"]),# paires vs brelan
    (["1c","1p","1t","4k","3p"],["Rc","Rk","Rt","4t","5p"]),# brelan vs brelan
    (["1c","1p","1t","4k","3p"],["Rc","Rk","Rt","4t","4p"]),# brelan vs full
    (["1c","1p","1t","3k","3p"],["Rc","Rk","Rt","4t","4p"]),# full vs full
    (["2c","2p","2t","3k","3p"],["Rc","Rk","Rt","4t","4p"]),# full vs full
    (["2c","2p","2t","3k","3p"],["3c","5k","Vt","Dt","6p"]),# full vs qualconque
    (["2c","2p","2t","3k","3p"],["1c","1k","1t","1k","6p"]),# full vs carre
    (["2c","3c","5c","9c","Rc"],["1c","1k","1t","1k","6p"]),# couleur vs carre
    (["2c","3c","5c","9c","Rc"],["1t","1k","1p","5k","7p"]),# couleur vs brelan
    (["4p","6k","9p","Vk","Dp"],["2c","3c","5c","9c","Rc"]),# suite vs couleur
    (["4p","6k","9p","Vk","Dp"],["1t","1k","1p","5k","7p"]),# suite vs brelan  
    (["1c","1k","1t","1p","6p"],["2c","3c","4c","5c","6c"]),# carre vs quinte
    (["7p","6p","3p","4p","5p"],["2c","3c","4c","5c","6c"]),# quinte vs quinte 
    ]


for (main1, main2) in test:
    print main1, main2, gagnant(main1, main2)








Citation : Zerda


Bon, j'avais pas très envie de le faire en Python, donc j'avais commencé en OCaml et puis j'ai arrêté parce que j'avais autre chose à faire, et comme je rajais j'ai supprimé, BLA BLA ...




In code we trust !!!
21 juin 2011 à 1:46:41

Hé ben non, j'ai pas envie de recommencer. De toute façon c'était du Caml.
14 juillet 2011 à 1:14:43

Bonsoir,

Je n'oserai pas vous montrer mon script, il est pas très joli et codé dans un style plutôt fonctionnel.

A la base : 3 fonctions pour déterminer la figure, on retrouve un peu la structure de josmiley:

  • La première fonction intervient uniquement sur la valeur des cartes (et non la couleur):
    Avec un dictionnaire et la méthode .get(), chaque figure renvoie une valeur correspondante :
    Ainsi :
    "Vrac" renvoie (1,1,1,1,1)
    "Paire" renvoie (2,1,1,1) etc...
    De cette manière, je détecte les paires, doubles, brelan, full, carré et autre.
  • La deuxième fonction, un peu semblable à la première agit sur la couleur(et pas la valeur des cartes).
    Là, c'est quand même plus simple, le résultat est binaire : toute les cartes sont de la même couleur, ou non.
  • La dernière teste la séquence : est-ce égal à un range()? Idem que précédemment, le résultat est binaire.

A partir de là, et en fonction des résultats obtenus, on détermine quelle est la figure en main (stocké dans un tuple).

Pour comparer enfin avec une main adverse, il faut que je décrypte, c'est un bazar immonde.
Dans les grandes lignes, j'ai créé une liste de tuple de référence contenant (le dictionnaire, le booléen de couleur, le booléen de séquence) dans l'ordre croissant de force.

Le tuple de ma main est comparé avec le tuple de la main adverse en cherchant l'index correspondant. En cas d'égalité, je ne sais plus comment j'ai fais.

En espérant avoir été clair.
Bonne soirée.

Edit : C'est moi ou de plus en plus de sujets traitent de problèmes du Projet Euler?
14 juillet 2011 à 1:47:31

@vapula
ça à l'air compliqué dis donc ^^

class Main(object):
    
    force = {(1,1,1,1,1):'CARTE',
             (2,1,1,1):'PAIRE',
             (2,2,1):'DEUX PAIRES',
             (3,1,1):'BRELAN',
             (3,1,2,0):'SUITE',
             (3,1,2,1):'SUITE',
             (3,1,2,2):'COULEUR',
             (3,2):'FULL',
             (4,1):'CARRE',
             (5,0):'QUINTE FLUSH',
             (5,1):'QUINTE FLUSH'}
    
    def __init__(self,cartes):
        valeur,couleur = zip(*cartes)
        self.set = sorted([(valeur.count(v),v)for v in set(valeur)],reverse=1)
        self.force,_ = zip(*self.set)
        if self.force == (1,1,1,1,1):
            C = len(set(couleur)) == 1 # teste si c'est une couleur
            S = max(valeur)-min(valeur) == 4 # teste si c'est une suite
            spe = sorted(valeur) == [2,3,4,5,14] # teste si c'est une suite à hauteur 5
            if not C:
                if spe or S: self.force = (3,1,2)+((0,) if spe else (1,))
            elif spe or S: self.force = (5,)+((0,) if spe else (1,))
            else: self.force = (3,1,2,2)


prenons par exemple cette Main:
ROI PIQUE ROI CARREAU ROI TREFLE DAME PIQUE 5 TREFLE

on a donc:
Main.set = (3,roi),(1,dame),(1,5)

en zippant on obtiend:
Main.force = (3,1,1) ==> brelan
_ = (roi,dame,5)

pour comparer 2 Main (simples comparaisons de tuples)
on compare les forces
si elles sont égales alors on compare les set
s 'ils sont égaux ceux sont les mêmes mains.

les lignes 19 à 26 servent seulement à gérer les cas particuliers:
-les suites
-les couleurs
-l'As vaut 1 ou 14
14 juillet 2011 à 11:36:27

Citation : josmiley


self.set = sorted([(valeur.count(v),v)for v in set(valeur)],reverse=1)




Tiens, genre de code qui m'interpelle. Au sorted près, tu cherches donc les multiplicités des éléments d'une liste. Or, en appelant count sur chaque élément, la complexité devient quadratique (en effet, tout appel à count oblige le parcours de toute la liste, cf. l'implémentation de count dans listobject.c). Je répète, ça n'a pas d'impact ici car les données sont petites et je pense que dans d'autres circonstances tu l'aurais écrit différemment mais juste une petite expérimentation :


from random import randrange

t=[randrange(10) for _ in range(50000)]
print(dict([(x, t.count(x)) for x in t]))


$ time python multiplicite_jos.py 
{0: 4968, 1: 4886, 2: 5027, 3: 5115, 4: 4925, 5: 5026, 6: 4929, 7: 4974, 8: 5090, 9: 5060}

real    0m55.037s
user    0m55.007s
sys     0m0.004s


alors qu'une telle recherche devrait prendre quelques ms si codé comme il faut.
14 juillet 2011 à 12:25:08

@candide
effectivement j'aurai pû utiliser un dictionnaire ...

d={}.fromkeys(valeur,0)
for v in valeur: d[v] += 1
self.set = zip(d.values(),d.keys())
14 juillet 2011 à 16:42:48

Au passage, il n'y a que deux millions six cent mille mains possibles donc il est facile de faire des statistiques. J'ai repris le code de josmiley. On retrouve les statistiques connues, cf ICI.



#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Main(object):
    
    force = {(1,1,1,1,1):'CARTE',
             (2,1,1,1):'PAIRE',
             (2,2,1):'DEUX PAIRES',
             (3,1,1):'BRELAN',
             (3,1,2,0):'SUITE',
             (3,1,2,1):'SUITE',
             (3,1,2,2):'COULEUR',
             (3,2):'FULL',
             (4,1):'CARRE',
             (5,0):'QUINTE FLUSH',
             (5,1):'QUINTE FLUSH'}
    
    def __init__(self,cartes):
        valeur,couleur = zip(*cartes)
        self.set = sorted([(valeur.count(v),v)for v in set(valeur)],reverse=1)
        self.force,_ = zip(*self.set)
        if self.force == (1,1,1,1,1):
            C = len(set(couleur)) == 1 # teste si c'est une couleur
            S = max(valeur)-min(valeur) == 4 # teste si c'est une suite
            spe = sorted(valeur) == [2,3,4,5,14] # teste si c'est une suite à hauteur 5
            if not C:
                if spe or S: self.force = (3,1,2)+((0,) if spe else (1,))
            elif spe or S: self.force = (5,)+((0,) if spe else (1,))
            else: self.force = (3,1,2,2)
    
    def __repr__(self):
        # retourne le nom de la Main
        return Main.force[self.force]

    def win(self,other):
        #Main.win(other) ==> Bool
        #retourne True si Main l'emporte sur other
        return (self.set > other.set) if self.force == other.force else (self.force > other.force)



N=52
jeu=[(fig,col) for fig in range(2,15) for col in range(0,4)]

mains=[]
for a in range(N):
    for b in range(a+1,N):
        for c in range(b+1,N):
            for d in range(c+1,N):
                for e in range(d+1,N):
                    mains.append([jeu[a], jeu[b], jeu[c],jeu[d],jeu[e]])

print len(mains)

resultat= dict.fromkeys([    
'CARTE',
'PAIRE',
'DEUX PAIRES',
'BRELAN',
'SUITE',
'COULEUR',
'FULL',
'CARRE',
'QUINTE FLUSH'    
 ],0)   

for main in mains:
    m=Main(main)
    resultat[Main.force[m.force]]+=1

print resultat


2598960
{'FULL': 3744, 'CARRE': 624, 'COULEUR': 5108, 'DEUX PAIRES': 123552, 'BRELAN': 54912, 'SUITE': 10200, 'PAIRE': 1098240, 'QUINTE FLUSH': 40, 'CARTE': 1302540}
14 juillet 2011 à 20:37:10

Citation : candide

Petit exercice sympa inspiré d'un exercice du projet Euler.


Oui, l'exo est effectivement sympa :) . Je l'ai fait en C++ il y a quelque temps, j'essaierai de le refaire en Python si je trouve le temps.

Citation : candide

Attention, dans le cas de cartes consécutives, l'As a une situation particulière : il peut être devant le Roi mais aussi avant la carte 2.


Cette règle semble ne pas être communément admise.

Citation : Wikipédia

L'as peut cependant aussi être utilisé comme carte de valeur 1, si cette convention est acceptée à la table, permettant ainsi de former des suites de type As, 2, 3, 4, 5.


Je m'étais posé la question en codant pour l'exo de Project Euler, car il m'a semblé d’après la lecture du problème que cette règle n'est pas prise en compte (en tout cas, la réponse est correcte sans cette règle; avec cette règle, je n'en sais rien). Mais bon, ça ajoute un légère difficulté en plus, alors pourquoi pas ?
14 juillet 2011 à 22:56:57

Citation : yoch

Je l'ai fait en C++ il y a quelque temps, j'essaierai de le refaire en Python si je trouve le temps.



Effectivement, cette question aurait sa place tant sur le forum Python que sur le forum C ou C++. Je ne sais pas quelle pourrait être la bonne pratique d'annonce :
-- se limiter à poster sur le forum Autres langages, outils et approches avec le risque de ne pas être lu par ceux qui ne le fréquenteraient pas
-- poster dans chaque forum (C, C++, C#, Java, Python)
-- annoncer sur chaque forum et demander à chacun de répondre uniquement sur Autres langages, outils et approches
-- autre ?

Citation : yoch


Citation : candide

Attention, dans le cas de cartes consécutives, l'As a une situation particulière : il peut être devant le Roi mais aussi avant la carte 2.


Cette règle semble ne pas être communément admise.



Effectivement et d'ailleurs j'ignorais cette pratique mais je l'ai proposé pour éviter les ambiguïtés (et c'est vrai que ça rajoute une petite difficulté intéressante). Je vais reformuler mon énoncé.


Citation : yoch


Je m'étais posé la question en codant pour l'exo de Project Euler, car il m'a semblé d’après la lecture du problème que cette règle n'est pas prise en compte



L'énoncé dit

Citation : Project Euler


The cards are valued in the order:
2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.



Ils auraient pu ajouter une phrase du genre "In spite of being marked 1, an Ace never counts as one".
Je regrette qu'un nombre non négligeable d'énoncés du project Euler restent si peu clairs en première lecture, deuxième lecture voire en dixième lecture. Qu'on n'écrive pas un énoncé clair du premier coup, je l'admets volontiers mais qu'on n'arrive pas à l'améliorer en tenant compte des expériences des utilisateurs me rend beaucoup moins tolérant. Hélas, cette pratique de l'énoncé non immédiatement compréhensible est assez fréquente.

14 juillet 2011 à 23:19:28

Citation : candide

Effectivement, cette question aurait sa place tant sur le forum Python que sur le forum C ou C++. Je ne sais pas quelle pourrait être la bonne pratique d'annonce :
-- se limiter à poster sur le forum Autres langages, outils et approches avec le risque de ne pas être lu par ceux qui ne le fréquenteraient pas
-- poster dans chaque forum (C, C++, C#, Java, Python)
-- annoncer sur chaque forum et demander à chacun de répondre uniquement sur Autres langages, outils et approches
-- autre ?


Ça fait longtemps que je pense qu'il devrait y avoir un forum dédié à l'algo. Pour l'instant, une des solutions habituelles est de poster dans le forum autres langages, mais je n'aime pas trop, car ça manque de visibilité.
De toutes manières, ton choix de poster dans le forum de ton langage préféré se justifie amplement. :)

Citation : candide

Je regrette qu'un nombre non négligeable d'énoncés du project Euler restent si peu clairs en première lecture, deuxième lecture voire en dixième lecture. Qu'on n'écrive pas un énoncé clair du premier coup, je l'admets volontiers mais qu'on n'arrive pas à l'améliorer en tenant compte des expériences des utilisateurs me rend beaucoup moins tolérant. Hélas, cette pratique de l'énoncé non immédiatement compréhensible est assez fréquente.


Je connais ton coté perfectionniste. ;) Personnellement, je trouve que le Project Euler est largement au dessus des certains autres sites d'exo à ce niveau. Dans plusieurs cas les exos ont été reformulés, et la qualité des énoncés est globalement assez élevée.

Bon, trêve de discours, et place au code.

J'ai codé un peu à l'arrache, et bon, c'est ma première classe en Python, aussi ne tapez pas trop fort svp. :-°
Aussi, je n'implémente pas la suite {1,2,3,4,5}.

from collections import namedtuple

Card = namedtuple('Card', 'color value')

Values = {'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9,'J':10,'Q':11,'K':12,'A':13}
HandName = {1:'Card', 2:'Pair', 3:'TwoPairs', 4:'Three', 5:'Straight', 6:'Flush', 7:'Full', 8:'Four', 9:'StraightFlush', 10:'RoyalFlush'}
Levels = {(1,1,1,1,1):1, (2,1,1,1):2, (2,2,1):3, (3,1,1):4, (3,2):7, (4,1):8}

class PokerHand:

    def __init__(self, cards):
        cards.sort(key=lambda c: Values[c.value])
        flush = len(set([c.color for c in cards])) == 1
        straight = Values[cards[0].value] + 4 == Values[cards[4].value]
        nvals={}
        for c in cards:
            if c.value not in nvals: nvals[c.value]=1
            else: nvals[c.value]+=1
        self.cards = sorted(cards, key=lambda c: nvals[c.value], reverse=True)
        if straight and flush:
            self.level = (10 if self.cards[4]=='A' else 9) 
        elif flush:
            self.level = 6
        elif straight:
            self.level = 5
        else:
            self.level = Levels[tuple(sorted(nvals.values(), reverse=True))]

    def name(self):
        return HandName[self.level]

    def __lt__(self, other):
        if self.level != other.level:
            return self.level < other.level
        for i in range(0,5):
            if Values[self.cards[i]] != Values[other.cards[i]]:
                return Values[self.cards[i]] < Values[other.cards[i]]
        return False

    def __gt__(self, other):
        if self.level != other.level:
            return self.level > other.level
        for i in range(0,5):
            if Values[self.cards[i]] != Values[other.cards[i]]:
                return Values[self.cards[i]] > Values[other.cards[i]]
        return False

    def __eq__(self, other):
        if self.level != other.level:
            return False
        for i in range(0,5):
            if Values[self.cards[i]] != Values[other.cards[i]]:
                return False
        return True

    def __repr__(self):
        ret = ''
        for i in range(0,5): ret += self.cards[i].color + self.cards[i].value + ' '
        return ret

main1 = PokerHand([Card('D','5'),Card('D','7'),Card('C','5'),Card('H','K'),Card('S','J')])
main2 = PokerHand([Card('H','4'),Card('D','J'),Card('S','8'),Card('S','5'),Card('C','6')])

print(main1.name(), ';', main2.name())
print(main1, '<' if main1 < main2 else '>' if main1 > main2 else '=', main2)


EDIT : le code a très peu à voir avec mon code C++ original, j'ai trouvé l’écriture en Python beaucoup plus agréable, je dois avouer...

EDIT2 : Amélioration de certaines méthodes :
def __lt__(self, other):
        if self.level != other.level:
            return self.level < other.level
        else:
            return [Values[c.value] for c in self.cards] < [Values[c.value] for c in other.cards]

    def __gt__(self, other):
        if self.level != other.level:
            return self.level > other.level
        else:
            return [Values[c.value] for c in self.cards] > [Values[c.value] for c in other.cards]

    def __eq__(self, other):
        if self.level != other.level:
            return False
        else:
            return [Values[c.value] for c in self.cards] == [Values[c.value] for c in other.cards]

    def __repr__(self):
        return ' '.join([c.color + c.value for c in self.cards])
15 juillet 2011 à 2:05:32

@Yoch:
Si, c'est vraiment ta première classe en python, chapeau!
Le seul truc que moi(pas plus avancé en python que toi), je trouve dommage c'est l'utilisation d'un range dans les for(pour parcourir une liste).

Cet exo je l'ai fait en C(il y a un peu plus d'un an), mais de manière bourrin(vraiment bourrin).
En voyant vos code, je vois que je suis passé à coté de quelque chose. :-°
Pour dire que même si je ne propose rien, je suis très intéressé par les réponses, et j'imagine que pas mal de personnes sont dans le même cas.

Sinon, je trouve aussi que cet exercice manque de visibilité.(et finalement oui, beaucoup d'exos pourraient être communs à tous les langages).

Pour la qualité des énoncés du Euler Project je rejoins Yoch, je trouve qu'ils sont tout de même à l'écoute des critiques.

Zeste de Savoir, le site qui en a dans le citron !
15 juillet 2011 à 2:42:37

Citation : GurneyH

@Yoch:
Si, c'est vraiment ta première classe en python, chapeau!


C'est bien ma première classe, mais je code quand même souvent en Python ces derniers temps.

Citation : GurneyH

Le seul truc que moi(pas plus avancé en python que toi), je trouve dommage c'est l'utilisation d'un range dans les for(pour parcourir une liste).


Oui, je m'en suis rendu compte.

Sinon, je viens de me rendre compte que mon code contient des erreurs, dont une importante qui demande de tout revoir sérieusement. :-°
15 juillet 2011 à 23:56:23

une tite modif qui affiche des cartes à la place de texte ...
dl l'image, copiez le code et cliquez sur la fenêtre pour passer à la main suivante.
Image utilisateur
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pygame import *
font.init()

scr = display.set_mode((600,123))
font = font.Font(None,16)

class Main(list,object):
    
    tile_set = image.load('cards.png')
    valeur = ('','','2','3','4','5','6','7','8','9','10','VALET','DAME','ROI','AS')
    couleur = ('TREFLE','CARREAU','COEUR','PIQUE')
    
    force = {(1,1,1,1,1):'CARTE',
             (2,1,1,1):'PAIRE',
             (2,2,1):'DEUX PAIRES',
             (3,1,1):'BRELAN',
             (3,1,2,0):'SUITE',
             (3,1,2,1):'SUITE',
             (3,1,2,2):'COULEUR',
             (3,2):'FULL',
             (4,1):'CARRE',
             (5,0):'QUINTE FLUSH',
             (5,1):'QUINTE FLUSH'}

    def __init__(self,cartes):
        valeur,couleur = zip(*cartes)
        self.extend(sorted(cartes,key=lambda v:(valeur.count(v),v),reverse=1)) # tri les cartes
        self.force = tuple(sorted([valeur.count(v)for v in set(valeur)],reverse=1)) # donne une representation de la main
        if self.force == (1,1,1,1,1): # gestion des cas particuliers
            C = len(set(couleur)) == 1 # teste si c'est une couleur
            S = max(valeur)-min(valeur) == 4 # teste si c'est une suite
            spe = sorted(valeur) == [2,3,4,5,14] # teste si c'est une suite à hauteur 5
            if C: self.force = (5,0) if spe else (5,1) if S else (3,1,2,2) # et ...
            else: self.force = (3,1,2,0) if spe else (3,1,2,1) if S else self.force # rectification si besoin
        if not self.force[-1]: self.append(self.pop(0)) # retification du tri si besoin (si l'AS vaut 1)

    def win(self,otherMain):
        #Main.win(other) ==> Bool
        #retourne True si Main l'emporte sur other
        return (self > otherMain) if self.force == otherMain.force else (self.force > otherMain.force)
    
    def __repr__(self):
        # retourne le nom de la Main
        return Main.force[self.force]
    
    def get_images(self):
        # retourne une liste des images des cartes de la main
        return [Main.tile_set.subsurface(((v-1)*79,c*123,79,123))for v,c in self]



    

test=[
    [(8,0),(7,0),(6,0),(5,0),(4,0)],
    [(14,0),(13,0),(12,0),(11,0),(10,0)],
    [(4,2),(3,2),(14,2),(5,2),(2,2)],
    [(13,2),(13,0),(13,3),(13,1),(3,2)], 
    [(14,2),(14,0),(14,3),(14,1),(3,1)],
    [(13,2),(13,0),(13,3),(3,3),(3,2)],
    [(13,1),(10,1),(8,1),(4,1),(3,1)],
    [(8,3),(7,2),(6,2),(5,1),(4,1)],
    [(13,2),(13,1),(13,3),(12,2),(5,3)],
    [(13,2),(13,3),(12,3),(8,3),(8,1)],
    [(8,3),(8,1),(13,2),(12,2),(5,3)],
    [(10,3),(10,1),(13,2),(12,2),(5,3)],
    [(13,2),(12,2),(8,0),(6,1),(5,3)]
    ]

for m in test:
    m = Main(m)
    pos = 0,0
    for img in m.get_images(): pos = scr.blit(img,pos).topright
    scr.blit(font.render(repr(m),1,(255,255,255)),pos)
    display.flip()
    while event.wait().type != MOUSEBUTTONUP: pass
    scr.fill(0)
16 juillet 2011 à 0:02:13

Sympa Josmiley, mais ça implique qu'on dispose de "cards.png", non? :-°

Et qu'il faut avoir pygame d'installée. ;)

edit:j'ai rien dit >_<
Zeste de Savoir, le site qui en a dans le citron !
16 juillet 2011 à 0:11:34

Citation : GurneyH

Sympa Josmiley, mais ça implique qu'on dispose de "cards.png", non? :-°

Et qu'il faut avoir pygame d'installée. ;)



les cartes ... c'est pas un screenshot ... c'est l'image à télécharger.
et qui n'a pas pygame sur sa bécane... ? je pose la question ^^
16 juillet 2011 à 0:14:39

Scuse pour les cartes. :-°

Pour pygame par contre, faut voir. ;) Mais ça coute rien de préciser.
Zeste de Savoir, le site qui en a dans le citron !
16 juillet 2011 à 21:06:31

Bonjour,

Code corrigé, en fait non, c'est pratiquement un nouveau code :p :

from collections import namedtuple
from functools import cmp_to_key

Card = namedtuple('Card', 'color value')

Values = {'2':1,'3':2,'4':3,'5':4,'6':5,'7':6,'8':7,'9':8,'T':9,'J':10,'Q':11,'K':12,'A':13}
HandName = {1:'Card', 2:'Pair', 3:'TwoPairs', 4:'Three', 5:'Straight', 6:'Flush', 7:'Full', 8:'Four', 9:'StraightFlush', 10:'RoyalFlush'}
Levels = {(1,1,1,1,1):1, (2,1,1,1):2, (2,2,1):3, (3,1,1):4, (3,2):7, (4,1):8}

class PokerHand:

    def __init__(self, cards):
        # determine la force de la main
        nvals={}.fromkeys([c.value for c in cards], 0)
        for c in cards:
            nvals[c.value]+=1
        values = sorted(set([Values[c.value] for c in cards]))
        flush = len(set([c.color for c in cards])) == 1
        straight = (len(values)==5) and (values[0]+4 == values[4])
        if straight and flush:
            self.level = (10 if values[4]==Values['A'] else 9) 
        elif flush:
            self.level = 6
        elif straight:
            self.level = 5
        else:
            self.level = Levels[tuple(sorted(nvals.values(), reverse=True))]
        # classe les cartes
        def cmp_fn(a,b):
            if nvals[a.value] < nvals[b.value]: return -1
            elif nvals[a.value] > nvals[b.value]: return 1
            elif Values[a.value] < Values[b.value]: return -1
            elif Values[a.value] > Values[b.value]: return 1
            else: return 0
        self.cards = sorted(cards, key=cmp_to_key(cmp_fn), reverse=True)

    def name(self):
        return HandName[self.level]

    def __lt__(self, other):
        if self.level != other.level:
            return self.level < other.level
        else:
            return [Values[c.value] for c in self.cards] < [Values[c.value] for c in other.cards]

    def __gt__(self, other):
        if self.level != other.level:
            return self.level > other.level
        else:
            return [Values[c.value] for c in self.cards] > [Values[c.value] for c in other.cards]

    def __eq__(self, other):
        if self.level != other.level:
            return False
        else:
            return [Values[c.value] for c in self.cards] == [Values[c.value] for c in other.cards]

    def __repr__(self):
        return ' '.join([c.color + c.value for c in self.cards])


Je suis assez déçu des perfs, je me rends compte qu'en cherchant à écrire de façon claire et en même temps concise, on risque de perdre en démarche algorithmique.
16 juillet 2011 à 21:27:01

Je vois que ce qui prend le + de place dans ton code c'est la redéfinition des opérateurs.

Sinon, en effet c'est vraiment concis. :-°
Hum, a propos ça donne la bonne réponse pour l'exercice du project Euler?
edit:perso j'ai triché, j'avais une main en moins en trop ou en plus d'attribuée.
J'ai testé un cran en dessus ou un cran en dessous et par chance c'est passé. :-°
Zeste de Savoir, le site qui en a dans le citron !
16 juillet 2011 à 22:20:00

Citation : GurneyH

Je vois que ce qui prend le + de place dans ton code c'est la redéfinition des opérateurs.

Sinon, en effet c'est vraiment concis. :-°


Non, ce que j'ai cherché à rendre vraiment court, c'est le __init__, mais je n'y suis pas arrivé...

Citation : GurneyH

Hum, a propos ça donne la bonne réponse pour l'exercice du project Euler?


Oui. :) Je viens de tester avec ce code :

counter=0
infile = open('poker.txt','r')

line = infile.readline()
while line != str():
    args = line.split(' ')
    mainA, mainB = PokerHand(tuple(Card(b,a) for a,b in zip(*zip(*args[:5])))), PokerHand(tuple(Card(b,a) for a,b in zip(*zip(*args[5:]))))
    if mainA > mainB: counter+=1
    line = infile.readline()

infile.close()
print(counter)


Citation : GurneyH

edit:perso j'ai triché, j'avais une main en moins en trop ou en plus d'attribuée.
J'ai testé un cran en dessus ou un cran en dessous et par chance c'est passé. :-°


Perso, lorsque j'ai testé mon code C++, j'ai mis un temps fou à comprendre que je lisais une ligne de trop, ce qui faussait mon résultat d'un point. :-°

Sinon c'est marrant, je me retrouve avec des habitudes que j'ai volontairement écartées en C, dans le sens ou mon code est absolument immonde (one-liners illisibles [ligne 7]). A croire que c'est une pratique de débutant...
Plus sérieusement, j’espère que le langage Python n'encourage pas trop ces pratiques.
16 juillet 2011 à 22:39:19

J'ai l'impression que bien que python soit "très propre", il y a une mode du on-liner dégueulasse qui pèse sur la communauté. :-°
Zeste de Savoir, le site qui en a dans le citron !
Anonyme
16 juillet 2011 à 23:34:32

Citation

J'ai l'impression que bien que python soit "très propre", il y a une mode du on-liner dégueulasse qui pèse sur la communauté.



Tu fais bien de préciser dégueulasse, car le on-liner n'est censé être utile que pour une bonne lisibilité et compréhension du lecteur.

Hors quand je vois ça

mainA, mainB = PokerHand(tuple(Card(b,a) for a,b in zip(*zip(*args[:5])))), PokerHand(tuple(Card(b,a) for a,b in zip(*zip(*args[5:]))))


Je me dis que ce code devrait rester personnel, et ne devrait pas être montré à des lecteurs potentiels.

Un code concis n'est pas forcément plus lisible et avec le code de yoch on en voit la preuve.

C'est montrer du code pour montrer du code, il n'y a même pas de commentaires.

il y a du values mélangé à du Values, mélangé à du value, enfin bref le seul à pouvoir comprendre ce code est son concepteur.

Citation

Plus sérieusement, j’espère que le langage Python n'encourage pas trop ces pratiques.



chercher zen of python sur google ou en faisant

import this


Mais c'est des recommandations qui peuvent être faites dans tous les autres langages.

Citation

Je suis assez déçu des perfs, je me rends compte qu'en cherchant à écrire de façon claire et en même temps concise, on risque de perdre en démarche algorithmique.



Si tu veux des performances, faut retourner au C ou C++ car il n'y a aucune chance de pouvoir faire mieux en python, même pour un codeur C++ pitoyable.

Le seul code que je vois compréhensif c'est celui de Candide et on comprend bien la démarche, pas besoin de commentaires, mais il en a mis.

17 juillet 2011 à 0:57:29

Citation : fred1599


Je me dis que ce code devrait rester personnel, et ne devrait pas être montré à des lecteurs potentiels.
...
Le seul code que je vois compréhensif c'est celui de Candide et on comprend bien la démarche, pas besoin de commentaires, mais il en a mis.



perso je trouve le code de Candide trop long, alors que celui de yoch est certe maladroit mais plus dans ma vision des choses.
comme quoi, les goûts et les codeurs ...

Poker

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
  • Editeur
  • Markdown