Surtout que quand j'ai voulu faire mon malin, j'avais une erreur que je n'ai jamais trouvée, mais qui s'est corrigée d'elle-même en remplaçant des chiffres par des trucs lisibles.
Comme quoi coder propre, contrairement à la rumeur, ben c'est utile même pour soi-même aujourd'hui.
Voilà, avec ça on corrige des bugs, et on supprime plein de commentaires devenus inutiles aussi :
Comme ça on peut comparer le HandType entre deux mains, et le plus grand est plus fort.
L'autre étape c'est de renommer les cartes pour pouvoir comparer deux mains du même type :
Et pour l'exercice 2, on initialise les données (hands2) tout pareil sauf qu'on fait : str.maketrans("TJQKA", "a0cde") comme ça le Joker a une valeur plus petite que les autres cartes lors de la comparaison. Et en plus on va pouvoir bosser avec la même classe Hand, et compter les Jokers, donc les "0", et comme il n'y en a pas dans les données transformées pour l'exercice 1, ça va fonctionner pour les deux !
Maintenant notre classe Hand peut être initialisée avec les données : hand et bid, et on la décore pour pouvoir ordonner directement une liste de mains. Le cached_property permet de s'assurer qu'on ne recalculera jamais deux fois le score d'une main lors de l'exécution (an pratique ça divise le temps d'exécution par 2 environ, ça aurait pu être bien pire...). On utilise une frozen dataclass parce qu'on ne modifie pas une main, là aussi c'est de l'optimisation qui peut s'avérer déterminante en cas de problème vraiment gros.
Ouaip, on simplifie en disant que deux mains sont toujours différentes, à toutes fins utiles, ça va plus vite, hein ?
Parce qu'on suppose, vu l'exercice, que toutes les mains fournies sont différentes, sinon le calcul final donnera un résultat différent (sauf si elles ont le même « bid », auquel cas osef).
De plus cut -d\ -f1 < 07.input | sort -u | wc -l; wc -l 07.input nous retourne 1000 lignes pour chaque, on a donc bien des mains uniques dans les données en entrée.
En pratique on ne gagne rien, avec la cached_property sur le score, de toute façon on va calculer le score une seule fois par main, et ça coûte pas lourd comme comparaisons. Mais là aussi c'est lié finalement à la toute petite quantité de données.
Bref, il ne nous reste plus qu'à résoudre, avec la fonction sorted() qui va faire tout le boulot à notre place, magique !
Et enfin, voilà le code de la méthode Hand.score, là où on se rend compte que tous les magiciens ont leur « trucs ». Je ne sais pas si j'aurais pu faire plus « intelligent », mais c'est assez clair je pense.
@cached_propertydefscore(self):cards=set(self.hand)# all kind of cards in handnb=len(cards)# number of different cards, including jokersjokers=self.hand.count("0")# number of jokers in handifnb==5:# abcde, abcd*returnHandType.OnePairifjokerselseHandType.HighCardifnb==4:# aabcd, aabc*, **abcreturnHandType.ThreeOfAKindifjokerselseHandType.OnePairifnb==3:# aaabc, aabbc, aaab*, aabb*, aa**c, ***bccards.discard("0")# Jokers are already countedcard=cards.pop()# draw a non-joker cardc=self.hand.count(card)ifc==2:# aabbc, aabb*, aa**creturn[HandType.TwoPairs,HandType.FullHouse,HandType.FourOfAKind][jokers]ifc==3:# aaabc, aaab*returnHandType.FourOfAKindifjokerselseHandType.ThreeOfAKind# non-joker card U is unique: aaabU, aabbU, aaaU*, aa**U, ***bUcard=cards.pop()ifself.hand.count(card)==2:# aabbU, aa**UreturnHandType.FourOfAKindifjokerselseHandType.TwoPairs# aaabU, aaaU*, ***bUreturnHandType.FourOfAKindifjokerselseHandType.ThreeOfAKindifnb==2:# aaa**, ***aa, aaaa*, ****aifjokers:# whatever, jokers makes it Five of a kindreturnHandType.FiveOfAKindcard=cards.pop()ifself.hand.count(card)in(2,3):# aaabbreturnHandType.FullHouse# aaaabreturnHandType.FourOfAKindreturnHandType.FiveOfAKind
Et voilà :)
Et une fois n'est pas coutume : PyPy est largement moins efficace que Python là-dessus, on passe de 70 à 370 millisecondes, même avec les 150ms de démarrage de PyPy, c'est amplement trois fois moins bon pour l'exécution en elle-même.
Dans tous les cas : pas de quoi faire chauffer la pièce à coups de CPU.
# Moi, aujourd'hui, je modélise tout propre tout joli !
Posté par Yth (Mastodon) . En réponse au message Advent of Code 2023, day 7. Évalué à 2.
Surtout que quand j'ai voulu faire mon malin, j'avais une erreur que je n'ai jamais trouvée, mais qui s'est corrigée d'elle-même en remplaçant des chiffres par des trucs lisibles.
Comme quoi coder propre, contrairement à la rumeur, ben c'est utile même pour soi-même aujourd'hui.
Voilà, avec ça on corrige des bugs, et on supprime plein de commentaires devenus inutiles aussi :
Comme ça on peut comparer le HandType entre deux mains, et le plus grand est plus fort.
L'autre étape c'est de renommer les cartes pour pouvoir comparer deux mains du même type :
Et pour l'exercice 2, on initialise les données (hands2) tout pareil sauf qu'on fait :
str.maketrans("TJQKA", "a0cde")comme ça le Joker a une valeur plus petite que les autres cartes lors de la comparaison. Et en plus on va pouvoir bosser avec la même classe Hand, et compter les Jokers, donc les "0", et comme il n'y en a pas dans les données transformées pour l'exercice 1, ça va fonctionner pour les deux !Maintenant notre classe
Handpeut être initialisée avec les données :handetbid, et on la décore pour pouvoir ordonner directement une liste de mains. Lecached_propertypermet de s'assurer qu'on ne recalculera jamais deux fois le score d'une main lors de l'exécution (an pratique ça divise le temps d'exécution par 2 environ, ça aurait pu être bien pire...). On utilise unefrozen dataclassparce qu'on ne modifie pas une main, là aussi c'est de l'optimisation qui peut s'avérer déterminante en cas de problème vraiment gros.Ouaip, on simplifie en disant que deux mains sont toujours différentes, à toutes fins utiles, ça va plus vite, hein ?
Parce qu'on suppose, vu l'exercice, que toutes les mains fournies sont différentes, sinon le calcul final donnera un résultat différent (sauf si elles ont le même « bid », auquel cas osef).
De plus
cut -d\ -f1 < 07.input | sort -u | wc -l; wc -l 07.inputnous retourne 1000 lignes pour chaque, on a donc bien des mains uniques dans les données en entrée.En pratique on ne gagne rien, avec la cached_property sur le score, de toute façon on va calculer le score une seule fois par main, et ça coûte pas lourd comme comparaisons. Mais là aussi c'est lié finalement à la toute petite quantité de données.
Bref, il ne nous reste plus qu'à résoudre, avec la fonction
sorted()qui va faire tout le boulot à notre place, magique !Et enfin, voilà le code de la méthode
Hand.score, là où on se rend compte que tous les magiciens ont leur « trucs ». Je ne sais pas si j'aurais pu faire plus « intelligent », mais c'est assez clair je pense.Et voilà :)
Et une fois n'est pas coutume : PyPy est largement moins efficace que Python là-dessus, on passe de 70 à 370 millisecondes, même avec les 150ms de démarrage de PyPy, c'est amplement trois fois moins bon pour l'exécution en elle-même.
Dans tous les cas : pas de quoi faire chauffer la pièce à coups de CPU.