Partage
  • Partager sur Facebook
  • Partager sur Twitter

Poker

Identifier une main, comparer deux mains

17 juillet 2011 à 1:36:45

Moi perso j'y vais plus doucement car, au moins candide et Yoch montrent du code (et pas que sur le forum python.) :-°

Alors après comme dis Josmiley, les goûts et les codeurs.
Mais perso, je préfère largement voir des gens qui se mouillent, quitte à prendre des remarques...

On voit plus souvent l'inverse. (Zerda ?) :-°
  • Partager sur Facebook
  • Partager sur Twitter
Zeste de Savoir, le site qui en a dans le citron !
17 juillet 2011 à 9:53:15

@ fred1599:
Tu me juge quelque peu sévèrement. Je rappelle que je suis encore au stade "débutant" en Python, donc je n'ai forcément pas encore de bonnes pratiques "pythoniques".

L'ennui est que lorsque l'on débute dans un langage (particulièrement si on sait déjà coder par ailleurs), on essaie dans la mesure du possible de coller au style/philosophie de ce langage, pour produire du code idiomatique. On cherche alors à s'inspirer d'anciennes habitudes, de codes existants lus sur internet ou la doc, etc. Le mix entre anciennes pratiques (inadaptées) / mauvais exemples suivis / connaissance incomplète du nouveau langage / etc. peut conduire à des aberrations, comme par exemple une démarche algorithmique lourde, du code repoussant, etc.

C'est un fait : on voit souvent du code illisible chez les débutants qui pensent être passé au niveau "supérieur" (et ce, dans maints langages). Peut-être est ce dû à un mauvais exemple ? Peut-être aussi cherchent-ils à connaitre les limites du langage ? ou autre (que sais-je) ?

Sinon, il y a plusieurs manière d'évaluer du beau code, et cela dépends beaucoup de son emploi. Un code destiné à servir et être maintenu doit être plus simple, plus commenté, même au prix d'une plus grande longueur. Un code de TP n'a pas les mêmes contraintes, il sert surtout à apprendre pour soi, et on peut alors se permettre plus de liberté, à mon sens.

Citation : fred1599

chercher zen of python sur google ou en faisant
Mais c'est des recommandations qui peuvent être faites dans tous les autres langages.


Merci pour l'info. :)
<chicaneur> "There should be one-- and preferably only one --obvious way to do it.". C'est très rare qu'il n'y ait qu'un moyen de le faire. Et je ne vois pas en quoi c'est préférable. </chicaneur>

Citation : fred1599

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.


Non, tu ne m'a pas compris : je parle des perfs de mon code Python, qui sont assez pitoyables par rapport à ce qu'on pourrait faire en s'appliquant. Car oui, je me suis appliqué sur des points de syntaxe et de concision, et ça a complétement tué le coté algo, ce que j'ai déploré.
<hs> Et puis détrompe toi, un codeur même relativement bon en C/C++ peut faire infiniment moins bien qu'un très bon code Python, tu n'as qu'a faire un tour sur les forums de project Euler pour t'en assurer. </hs>
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
17 juillet 2011 à 10:26:45

Citation

Tu me juge quelque peu sévèrement. Je rappelle que je suis encore au stade "débutant" en Python, donc je n'ai forcément pas encore de bonnes pratiques "pythoniques".



Attention ce n'est pas un jugement, et si je devais juger je dirais que tu as les bonnes pratiques, mais tu ne les appliquent pas ;) Mais je ne me permettrais pas un jugement juste une constatation.

Citation

L'ennui est que lorsque l'on débute dans un langage (particulièrement si on sait déjà coder par ailleurs), on essaie dans la mesure du possible de coller au style/philosophie de ce langage, pour produire du code idiomatique. On cherche alors à s'inspirer d'anciennes habitudes, de codes existants lus sur internet ou la doc, etc. Le mix entre anciennes pratiques (inadaptées) / mauvais exemples suivis / connaissance incomplète du nouveau langage / etc. peut conduire à des aberrations, comme par exemple une démarche algorithmique lourde, du code repoussant, etc.



Encore une fois, tu mets cela sur le compte du débutant, tu maîtrises mieux que moi python, tu as des connaissances nettement plus avancées en C/C++ et ton expérience dans tous ces langages font que tes codes au contraire doivent être clairs et compréhensifs. Ce n'est pas une question de pouvoir mais de vouloir.

Ne me dis pas qu'on peut faire compliqué et pas simple?

Citation

Sinon, il y a plusieurs manière d'évaluer du beau code, et cela dépends beaucoup de son emploi. Un code destiné à servir et être maintenu doit être plus simple, plus commenté, même au prix d'une plus grande longueur. Un code de TP n'a pas les mêmes contraintes, il sert surtout à apprendre pour soi, et on peut alors se permettre plus de liberté, à mon sens.



On est d'accord c'est un code personnel qui reste pédagogique que pour celui qui le conçoit et non pour ceux qui le lisent.

Citation

Merci pour l'info. :)
<chicaneur> "There should be one-- and preferably only one --obvious way to do it.". C'est très rare qu'il n'y ait qu'un moyen de le faire. Et je ne vois pas en quoi c'est préférable. </chicaneur>



C'est en effet un des abus du concepteur python, je suis d'accord, cependant d'autres conseils (pas tous) sont eux applicables dans la conception d'un code.

Citation

Non, tu ne m'a pas compris : je parle des perfs de mon code Python, qui sont assez pitoyables par rapport à ce qu'on pourrait faire en s'appliquant. Car oui, je me suis appliqué sur des points de syntaxe et de concision, et ça a complétement tué le coté algo, ce que j'ai déploré.
<hs>



En fait si j'avais bien compris :)

Beaucoup de fois on a pu démontrer que malgré un très bon algorithme on arrive pas à la hauteur de l'utilisation des fonctions standards python.

Citation

Et puis détrompe toi, un codeur même relativement bon en C/C++ peut faire infiniment moins bien qu'un très bon code Python, tu n'as qu'a faire un tour sur les forums de project Euler pour t'en assurer.



En étant pitoyable en C/C++ j'ai toujours fait mieux niveau perf que mes fonctions python, maintenant encore une fois tu es plus expérimenté que moi et je veux bien te croire.

Citation : josmiley

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 ...



Plus long, oui! Mais en quoi son code est moins lisible? Il utilise vraiment la simplicité dans son code, peut-être aussi pour garder je pense un caractère pédagogique.

  • Partager sur Facebook
  • Partager sur Twitter
17 juillet 2011 à 11:58:14

Citation : fred1599


Plus long, oui! Mais en quoi son code est moins lisible? Il utilise vraiment la simplicité dans son code, peut-être aussi pour garder je pense un caractère pédagogique.



j'ai jamais dit qu'il n'était pas lisible ... je dis juste trop long en fonction de ce qu'il est sensé faire, à mon goût.
Mais c'est sûr qu'en lisant juste le nom des fonctions le code se comprend aisément.
Personnellement je préfère les codes courts, même s'il faut les décortiquer un peu, et chercher l'astuce utilisée pour grapiller des lignes.(ben oui j'aime bien le byte-crunching :p )

quelques modifs de la class Main qui permettent de ne pas surcharger les opérateurs de comparaison:

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')
    force = {(1,1,1,1,1):'0_CARTE',
             (2,1,1,1):'1_PAIRE',
             (2,2,1):'2_DEUX PAIRES',
             (3,1,1):'3_BRELAN',
             (3,2):'6_FULL',
             (4,1):'7_CARRE'}
             
    def __init__(self,cartes):
        valeur,couleur = zip(*cartes)
        self.extend(sorted(cartes,key=lambda (v,_):(valeur.count(v),v,_),reverse=1)) # tri les cartes
        nom = Main.force[tuple(sorted([valeur.count(v)for v in set(valeur)],reverse=1))] # donne le nom de la main
        if nom == '0_CARTE': # gestion des cas particuliers
            estCouleur = len(set(couleur)) == 1 # teste si c'est une couleur
            estHauteur5 = sorted(valeur) == [2,3,4,5,14] # teste si c'est une suite à hauteur 5
            estSuite = (max(valeur)-min(valeur) == 4) or estHauteur5 # teste si c'est une suite
            if estCouleur: nom = '8_QUINTE FLUSH' if estSuite else '5_COULEUR'
            elif estSuite: nom = '4_SUITE'
            if estHauteur5: self.append(self.pop(0)) # retification du tri si l'AS vaut 1
        self.insert(0,nom)

    @property
    def name(self):
        return self[0][2:]
    
    def __repr__(self):
        # retourne le nom de la Main
        return self.name
    
    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[1:]]

# *************************************************************************************

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)]
    ]

test = [Main(m) for m in test]
for m in sorted(test):
    pos = 0,0
    for img in m.get_images(): pos = scr.blit(img,pos).topright
    scr.blit(font.render(m.name,1,(255,255,255)),pos)
    display.flip()

    while event.wait().type != MOUSEBUTTONUP: pass
    scr.fill(0)
  • Partager sur Facebook
  • Partager sur Twitter
17 juillet 2011 à 13:04:41

Citation : fred1599

Encore une fois, tu mets cela sur le compte du débutant, tu maîtrises mieux que moi python, tu as des connaissances nettement plus avancées en C/C++ et ton expérience dans tous ces langages font que tes codes au contraire doivent être clairs et compréhensifs. Ce n'est pas une question de pouvoir mais de vouloir.

Ne me dis pas qu'on peut faire compliqué et pas simple?


Sincèrement, je pense avoir beaucoup moins d’expérience que toi en Python. J'essaie de compenser en me servant de mon expérience avec d'autres langages (pas nécessairement une "bonne idée", je dirais plutôt un cheminement quasi-automatique), et en me servant des diverses documentations/exemples à ma disposition.

Effectivement, je pourrais très facilement écrire de façon plus simple/claire, mais j'ai une crainte (assez forte): c'est de passer en quelque sorte à coté du langage. Donc j'essaie avec mon maigre bagage d'utiliser toute l'expressivité que le langage met à ma disposition, et je me retrouve avec un code plutôt infect :-° (ou non :) ).

Fondamentalement, je me range aujourd’hui plutôt du coté de la clarté que du coté de la concision poussée à l’extrême dans les langages que je maitrise (en C par exemple, on se retrouve vite à faire des suppositions sur le comportement du compilateur, etc.). Mais cela reflète tout un cheminement, certaines expériences (dev à plusieurs, etc.), que je ne peux que difficilement transcrire dans un contexte tout nouveau comme Python. Car oui, il y a (et y aura) toujours un sacrifice à faire quelque part: sacrifier la concision à la performance, sacrifier l'expressivité à la lisibilité, sacrifier la simplicité à la ré-usabilité, etc., et cela implique des choix qui ne seront pas nécessairement les mêmes selon le langage utilisé et l'objectif visé.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
17 juillet 2011 à 14:22:59

j'ai jamais dit qu'il n'était pas lisible ...


Je me suis mal exprimé, je voulais clairement dire, long mais lisible!

Citation

Sincèrement, je pense avoir beaucoup moins d’expérience que toi en Python. J'essaie de compenser en me servant de mon expérience avec d'autres langages (pas nécessairement une "bonne idée", je dirais plutôt un cheminement quasi-automatique), et en me servant des diverses documentations/exemples à ma disposition.



Peut-être (ou non :) ) écrire du on-liner aussi facilement est pour moi preuve d'expérience dans le langage. Je n'ai rien contre ton code, seulement si on reste dans un caractère pédagogique (TP ou exercice), il est préférable que ton code soit lisible par tous. Ce que je regrette c'est surtout un manque de commentaires sur des points assez pointus comme tes on-liners par exemple.

En C (voir C++, mais beaucoup plus rare) tu vas souvent réinventer la roue, alors que python va te proposer une pléthore de fonctions pour contourner ou éviter le plus possible un nombre incalculable de lignes de code.

En outre programmeur n'est pas mon métier je n'ai juste qu'une vue externe de l'iceberg, une vue dont je me suis fais des bases (bonnes ou mauvaises) seul et peut-être maladroitement.

yoch, je lis souvent tes codes C qui sont pour moi très souvent formateur, et j'étais surpris étant un vrai débutant en C et C++ de comprendre tes codes et d'avoir des difficultés dans la lecture d'un code python fait par le même codeur, car niveau algorithme en ce qui me concerne tu es un modèle :)

  • Partager sur Facebook
  • Partager sur Twitter
17 juillet 2011 à 14:48:28

Citation : fred1599

En outre programmeur n'est pas mon métier je n'ai juste qu'une vue externe de l'iceberg, une vue dont je me suis fais des bases (bonnes ou mauvaises) seul et peut-être maladroitement.


Ce n'est pas mon métier non plus :) . Une simple passion...

Citation : fred1599

yoch, je lis souvent tes codes C qui sont pour moi très souvent formateur, et j'étais surpris étant un vrai débutant en C et C++ de comprendre tes codes et d'avoir des difficultés dans la lecture d'un code python fait par le même codeur, car niveau algorithme en ce qui me concerne tu es un modèle :)


Merci pour le compliment. Cela prouve justement que l’expérience dans un langage donné compte pour beaucoup, s'il fallait le prouver. ;)
________

Bon, pour revenir au sujet initial (avant que candide ne nous tire les oreilles ^^ ), voici mon dernier code remanié, avec un poil plus de commentaires, et un petit hack de rien du tout [ligne 32] qui me permet d'améliorer mes perfs. Pour une plus grande clarté, j'ai remplacé value par fig (pas trouvé l'équivalent anglais) :

from collections import namedtuple

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

CardsValues = { f:v for f,v in zip('23456789TJQKA',range(2,15)) }
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):
        figures,colors = zip(*[(c.fig,c.color) for c in cards])
        # teste si c'est une couleur
        flush = len(set(colors)) == 1
        # teste si c'est une suite
        values = sorted([CardsValues[fig] for fig in set(figures)])
        straight = (len(values)==5) and (values[0]+4 == values[4])
        # calcule le nombre d'occurences de chaque figure
        nvals=dict().fromkeys(figures, 0)
        for f in figures:
            nvals[f]+=1
        # determine la force de la main
        if straight and flush:
            self.level = (10 if values[4]==CardsValues['A'] else 9) 
        elif flush:
            self.level = 6
        elif straight:
            self.level = 5
        else:
            self.level = Levels[tuple(sorted(nvals.values(), reverse=True))]
        # trie les cartes pour une comparaison eventuelle
        self.cards = sorted(cards, key=lambda c: CardsValues[c.fig]+(15*nvals[c.fig]), 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 [CardsValues[c.fig] for c in self.cards] < [CardsValues[c.fig] for c in other.cards]

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

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

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


PS: Question bête, pourquoi certains ici disent 'on-liner' ? Il me semble que l'on dit 'one-liner', non ? Quelque chose m'a échappé ?
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
17 juillet 2011 à 15:31:11

Citation

Question bête, pourquoi certains ici disent 'on-liner' ? Il me semble que l'on dit 'one-liner', non ? Quelque chose m'a échappé ?



C'est bien one je te rassure ;)

Citation

voici mon dernier code remanié, avec un poil plus de commentaires, et un petit hack de rien du tout [ligne 32] qui me permet d'améliorer mes perfs. Pour une plus grande clarté, j'ai remplacé value par fig (pas trouvé l'équivalent anglais) :



C'est déjà nettement mieux car avec les commentaires on comprend tout de suite où tu veux en venir.

Je vais analyser ton code

Voilà une amélioration avec la fonction count() qui normalement devrait être plus rapide

nvals=dict().fromkeys(figures, 0)
        for f in figures:
            nvals[f]+=1


On pourrait faire

nvals = {}
for i in set(figures):
    nvals[i] = figures.count(i)


non?

Tu pourrais donner un exemple d'initialisation de ta classe, qui je pense doit être en rapport avec ton tuple nommé?
  • Partager sur Facebook
  • Partager sur Twitter
17 juillet 2011 à 17:38:20

Citation : fred1599

Voilà une amélioration avec la fonction count() qui normalement devrait être plus rapide

nvals=dict().fromkeys(figures, 0)
        for f in figures:
            nvals[f]+=1



On pourrait faire

nvals = {}
for i in set(figures):
    nvals[i] = figures.count(i)



non?


Non, ce n'est pas plus rapide, à cause du coût de count(), cf. ce post ci-dessus (en plus du temps pour construire le set, enfin bon, on pourrait garder le set utilisé un peu plus haut). En revanche, ça pourrait permettre d'économiser des lignes :p , comme ceci :
nvals = { k:figures.count(k) for k in set(figures) }


Citation : fred1599

Tu pourrais donner un exemple d'initialisation de ta classe, qui je pense doit être en rapport avec ton tuple nommé?



On peut soit initialiser un tuple nommé en nommant expressément les champs du tuple (l'ordre ne compte alors pas), soit implicitement en passant les paramètres au constructeur dans le bon ordre. Cf. ici et (construction implicite).

L'emploi d'un tuple nommé est ici purement cosmétique, afin de pouvoir écrire c.fig et c.color, au lieu de c[0] et c[1]...
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
17 juillet 2011 à 20:57:40

Citation

Non, ce n'est pas plus rapide, à cause du coût de count(), cf. ce post ci-dessus (en plus du temps pour construire le set, enfin bon, on pourrait garder le set utilisé un peu plus haut). En revanche, ça pourrait permettre d'économiser des lignes :p , comme ceci :



count est plus rapide qu'un compteur, ça doit être la fonction set qui doit être plus lente, donc fromkeys en effet est adapté.

nvals = dict.fromkeys(figure, 0)
for k in nvals:
    nvals[k] = figure.count(k)


Sinon j'ai mieux encore, je pense que tu vas apprécier :)

from collections import Counter
nvals = Counter(figure)
  • Partager sur Facebook
  • Partager sur Twitter
17 juillet 2011 à 21:23:01

j'ai réduit la taille de l' __init__, bien sûr c'est illisible ...

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

class Main(list,object):
    
    valeur = ('','AS','2','3','4','5','6','7','8','9','10','VALET','DAME','ROI','AS')
    couleur = ('TREFLE','CARREAU','COEUR','PIQUE')
    force = {(1,1,1,1,1):'0_CARTE',(1,1,1,2):'1_PAIRE',(1,2,2):'2_DEUX PAIRES',
             (1,1,3):'3_BRELAN',(2,3):'6_FULL',(1,4):'7_CARRE'}
             
    def __init__(self,cartes):
        valeur,couleur = zip(*sorted(cartes))
        if valeur == (2,3,4,5,14): valeur = (1,2,3,4,5)
        estSuite = (valeur[4]-valeur[0] == 4)
        if len(set(couleur)) == 1: self.append('8_QUINTE FLUSH' if estSuite else '5_COULEUR')
        else: self.append('4_SUITE' if estSuite else Main.force[tuple(sorted([valeur.count(v)for v in set(valeur)]))])
        self.hand = sorted(cartes,key=lambda (v,c):(valeur.count(v),v,c),reverse=1)
        self.extend(zip(*self.hand)[0])
        self.name = self[0][2:]
        self.alpha_hand = [(Main.valeur[v],Main.couleur[c]) for v,c in self.hand]

# *************************************************************************************

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)]
    ]

test = [Main(m) for m in test]
for m in sorted(test):
    print m.alpha_hand,' : '+m.name

[('ROI', 'COEUR'), ('DAME', 'COEUR'), ('8', 'TREFLE'), ('6', 'CARREAU'), ('5', 'PIQUE')]  : CARTE
[('8', 'PIQUE'), ('8', 'CARREAU'), ('ROI', 'COEUR'), ('DAME', 'COEUR'), ('5', 'PIQUE')]  : PAIRE
[('10', 'PIQUE'), ('10', 'CARREAU'), ('ROI', 'COEUR'), ('DAME', 'COEUR'), ('5', 'PIQUE')]  : PAIRE
[('ROI', 'PIQUE'), ('ROI', 'COEUR'), ('8', 'PIQUE'), ('8', 'CARREAU'), ('DAME', 'PIQUE')]  : DEUX PAIRES
[('ROI', 'PIQUE'), ('ROI', 'COEUR'), ('ROI', 'CARREAU'), ('DAME', 'COEUR'), ('5', 'PIQUE')]  : BRELAN
[('8', 'PIQUE'), ('7', 'COEUR'), ('6', 'COEUR'), ('5', 'CARREAU'), ('4', 'CARREAU')]  : SUITE
[('ROI', 'CARREAU'), ('10', 'CARREAU'), ('8', 'CARREAU'), ('4', 'CARREAU'), ('3', 'CARREAU')]  : COULEUR
[('ROI', 'PIQUE'), ('ROI', 'COEUR'), ('ROI', 'TREFLE'), ('3', 'PIQUE'), ('3', 'COEUR')]  : FULL
[('ROI', 'PIQUE'), ('ROI', 'COEUR'), ('ROI', 'CARREAU'), ('ROI', 'TREFLE'), ('3', 'COEUR')]  : CARRE
[('AS', 'PIQUE'), ('AS', 'COEUR'), ('AS', 'CARREAU'), ('AS', 'TREFLE'), ('3', 'CARREAU')]  : CARRE
[('5', 'COEUR'), ('4', 'COEUR'), ('3', 'COEUR'), ('2', 'COEUR'), ('AS', 'COEUR')]  : QUINTE FLUSH
[('8', 'TREFLE'), ('7', 'TREFLE'), ('6', 'TREFLE'), ('5', 'TREFLE'), ('4', 'TREFLE')]  : QUINTE FLUSH
[('AS', 'TREFLE'), ('ROI', 'TREFLE'), ('DAME', 'TREFLE'), ('VALET', 'TREFLE'), ('10', 'TREFLE')]  : QUINTE FLUSH

  • Partager sur Facebook
  • Partager sur Twitter
17 juillet 2011 à 21:46:01

Citation : fred1599

Sinon j'ai mieux encore, je pense que tu vas apprécier :)

from collections import Counter
nvals = Counter(figure)


Pile ce que je cherchais, merci ! :D

EDIT:
Après mesure des perfs, il s’avère que cette solution est terriblement peu performante dans le cas présent, dommage...

Je suppose toutefois qu'elle sera nettement plus efficace qu'une solution à base de count() sur de gros iterables.

L’implémentation proposée dans les sources de python 3.2 ressemble à ceci (effectivement performant, mais pas plus que ma première methode, légèrement moins on dirait) :
nvals = {}
for f in figures:
    nvals[f] = nvals.get(f,0)+1


En revanche, une compréhension ne fonctionne pas correctement ici (renvoie un seul élément de chaque figure), sans doute parce que get() ne renvoie pas la valeur attendue pendant la construction du dictionnaire :
nvals = { f:nvals.get(f,0)+1 for f in figures }


EDIT2:
Je viens de relire attentivement le post de fred1599 :

Citation

count est plus rapide qu'un compteur


Je ne crois pas. D’où tiens tu cela ?

Citation

ça doit être la fonction set qui doit être plus lente, donc fromkeys en effet est adapté.


Ça va moins vite que sans le count() chez moi.

EDIT3:
Encore une methode équivalente à Counter(), inspirée de la doc :

from collections import defaultdict

nvals = defaultdict(int)
for f in figures:
    nvals[f] += 1


Si f ne se trouve pas dans le dictionnaire, le constructeur par défaut int() est appelé, soit 0.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
19 juillet 2011 à 18:17:55

Citation

Je ne crois pas. D’où tiens tu cela ?



Cette méthode fait partie de la lib standard et donc elle est optimisée.

Je ne comprend pas pourquoi c'est plus lent, il y a un blème là :o

Contrairement à une simple incrémentation.

J'arrive pas à trouver la source de la méthode.

Citation

Encore une methode équivalente à Counter(), inspirée de la doc :



Oui je l'avais vu aussi ;)

  • Partager sur Facebook
  • Partager sur Twitter
19 juillet 2011 à 18:27:36

Citation : fred1599

Citation

Je ne crois pas. D’où tiens tu cela ?



Cette méthode fait partie de la lib standard et donc elle est optimisée.

Je ne comprend pas pourquoi c'est plus lent, il y a un blème là :o


Optimisée, c'est clair, mais cette fonction est tout de même en O(N), c'est à dire que l'on doit impérativement parcourir tout l'iterable pour compter les objets. Donc si tu appelle count() sur chaque objet, la complexité devient quadratique O(N^2), comme l'a justement fait remarquer candide.

Ici, ça n'a pas une grande influence, parce qu'il n'y a que 5 cartes, mais si tu en avais 10000, tu aurais eu des écarts astronomiques...

EDIT : et puis count() n'est pas une methode, c'est une fonction.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
19 juillet 2011 à 18:34:58

Citation

EDIT : et puis count() n'est pas une methode, c'est une fonction.



count() est appliqué sur un objet, c'est donc une méthode, si je ne me trompe pas.

Pour le reste je veux bien vous croire je n'y comprend rien aux complexités, donc je dis amen
  • Partager sur Facebook
  • Partager sur Twitter
19 juillet 2011 à 18:38:49

Citation : fred1599

count() est appliqué sur un objet, c'est donc une méthode, si je ne me trompe pas.


Non.

Une methode, c'est une fonction appartenant à un objet : objet.methode()

Une fonction peut très bien être appelée sur un objet : fonction(objet)
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
19 juillet 2011 à 18:43:33

liste = [1, 1, 5, 9, 3, 1]
print(liste.count(1))


Edit : Et je rajoute une référence

Citation

The list data type has some more methods. Here are all of the methods of list objects:



La méthode count() est dans la liste

;)
  • Partager sur Facebook
  • Partager sur Twitter
19 juillet 2011 à 18:57:57

dans cet exercice on s'en tape d'utiliser count() ou une autre méthode pour gratter des millisecondes? non?
  • Partager sur Facebook
  • Partager sur Twitter
19 juillet 2011 à 19:40:33

Citation : fred1599

liste = [1, 1, 5, 9, 3, 1]
print(liste.count(1))

Désolé, je pensais que count() faisait partie des fonctions built-in (comme min() et max()). :honte:

Citation : josmiley

dans cet exercice on s'en tape d'utiliser count() ou une autre méthode pour gratter des millisecondes? non?


Oui, on s'en fout pas mal. La discussion avait un caractère plus global (car l'exo est fait pour s'entrainer, mais aussi pour réfléchir, comparer les diverses approches, etc.).
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
29 mai 2013 à 18:13:07



Voilà je reviens un peu tard sur le topic mais je dois me former un peu sur le python pour un boulot ( je suis plus JAVA :p ) et j'ai réalisé quelques un des tp pour 

prendre la main. Je n'ai pas tout résolu le problème du poker mais j'ai crée deux classes Cartes et JeuCartes qui permettent respectivement de créer un type carte

et de générer un jeu de 52 cartes et deux mains aléatoires.

Voici la classe Cartes :

'''
Created on 29 mai 2013

@author: jaillet-jb
'''

class Cartes(object):
    '''
    Une cartes a une couleur "string"
    Une cartes a une valeur "string"
    '''


    def __init__(self, couleur, valeur):
        if couleur != "co" and couleur != "p" and couleur != "ca" and couleur !="t" :
            print(couleur)
            print("Couleur incorrecte")
        else :
            self.couleur = couleur
        if valeur not in "1023456789rvd" :
            print("Valeur incorrecte.")
        else :    
            if valeur in "1023456789" :
                a = int(valeur)
                if a > 10 or a == 0:
                    print("Valeur incorrecte")
                else :
                    self.valeur = valeur
            else :
                self.valeur = valeur
            
    def _get_couleur(self):
        return self.couleur
    
    def _get_valeur(self):
        return self.valeur
    
    def _set_couleur(self,couleur):
        self.couleur = couleur
        
    def _set_valeur(self,valeur):
        self.valeur = valeur
        
    def ordreCartes(self,carte):
        '''
        Renvoie 0 si les cartes sont egales
        Renvoie 1 si la premiere carte est plus grande
        Renvoie 2 si la deuxieme carte est plus grande
        '''
        if self.valeur == carte.valeur :
            print("Les deux cartes ont la meme valeur !")
            return 0
        elif self.valeur in "rvd" and carte.valeur not in "rvd" :
            self.afficherCarte()
            print("l'emporte sur ")
            carte.afficherCarte()
            return 1
        elif self.valeur not in "rvd" and carte.valeur in "rvd" :
            self.afficherCarte()
            print("est battue par le")
            carte.afficherCarte()
            return 2
        elif self.valeur not in "rvd" and carte.valeur not in "rvd" :
            a = int(self.valeur)
            b = int(carte.valeur)
            if a < b :
                self.afficherCarte()
                print("est battue par le")
                carte.afficherCarte()
                return 2
            else :
                self.afficherCarte()
                print("l'emporte sur ")
                carte.afficherCarte()
                return 1
        else :
            if self.valeur == "v" :
                self.afficherCarte()
                print("est battue par le")
                carte.afficherCarte()
                return 2
            elif carte.valeur == "v" :
                self.afficherCarte()
                print("l'emporte sur ")
                carte.afficherCarte()
                return 1
            elif self.valeur == "r" :
                self.afficherCarte()
                print("l'emporte sur ")
                carte.afficherCarte()
                return 1
            else :
                self.afficherCarte()
                print("est battue par le")
                carte.afficherCarte()
                return 2
            
            
    def afficherCarte(self) :
        a = " "
        c = " "
        if self.couleur == "ca" :
            a = "Carreau"
        elif self.couleur == "co" :
            a = "Coeur"
        elif self.couleur == "p" :
            a = "Pique"
        else :
            a = "Trefle"
        
        if self.valeur == "v" :
            c = "Valet"
        elif self.valeur == "d" :
            c = "Dame"
        elif self.valeur == "r" :
            c = "Roi"
        elif self.valeur == "1" :
            c = "As"
        else :
            c = self.valeur
        
        print(" "+ c +" de " + a +". ")
 


La classe JeuCartes :

'''
Created on 29 mai 2013

@author: jaillet-jb
'''
from classe.Cartes import Cartes
import random

class JeuCartes(object):
    
    def __init__(self):
        self.jeu = {}
        self.mainun = {}
        self.maindeux = {}
        k = 0
        couleur = ["ca","co","t","p"]
        valeur = ["1","2","3","4","5","6","7","8","9","10","v","d","r"]
        for i in valeur :
            for j in couleur :
                a = str(k)
                cartes = Cartes(j,i)
                self.jeu[a] = cartes
                k += 1
        
    def afficherJeu(self):
        i = 0
        while i < len(self.jeu) :
            i = str(i)
            self.jeu[i].afficherCarte()
            i = int(i)
            i += 1
    def afficherMain(self):
        i = 0
        print("Premiere main : ")
        while i < len(self.mainun) :
            i = str(i)
            self.mainun[i].afficherCarte()
            i = int(i)
            i += 1
        i = 0
        print("Deuxieme main : ")
        while i < len(self.mainun) :
            i = str(i)
            self.maindeux[i].afficherCarte()
            i = int(i)
            i += 1
        
    def genererMain(self):
        jeutemp = {}
        jeutemp = self.jeu
        i = 0
        while i < 5 :
            k = random.randrange(52)
            k = str(k)
            if k in jeutemp.keys() :
                self.mainun[str(i)] = jeutemp[k]
                del jeutemp[k]
                i += 1
        i = 0
        while i < 5 : 
            k = random.randrange(52)
            k = str(k)
            if k in jeutemp.keys() :
                self.maindeux[str(i)] = jeutemp[k]
                del jeutemp[k]
                i += 1



Et enfin un exemple d'appel :

'''
Created on 29 mai 2013

@author: jaillet-jb
'''
from classe.Cartes import Cartes
from classe.JeuCartes import JeuCartes

j = JeuCartes()
j.genererMain()
j.afficherMain()

Une fois le jeu de cartes créer, vous appelez le méthode genererMain() autant de fois que vous voulez pour générer des mains aléatoires ( sans problème de doublons

evidemment :p )

Exemple de compilation :

Premiere main :
 10 de Pique.
 Valet de Carreau.
 3 de Coeur.
 9 de Coeur.
 2 de Coeur.
Deuxieme main :
 4 de Trefle.
 Valet de Coeur.
 4 de Coeur.
 3 de Pique.
 4 de Carreau.

Voilà, c'est plus pour donner un p'tit truc pour ensuite faire grandir la classe ( nombre de main générer, jeux de cartes différents ) ou pour tester vos code

de poker sur des mains générées aléatoirement.

Cordialement

Besta

-
Edité par Anonyme 29 mai 2013 à 18:18:43

  • Partager sur Facebook
  • Partager sur Twitter

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