Skip to content
Tags

,

Histogramme cumulé de la répartition des cartes du jeu The City avec matplotlib

13 octobre 2013

The city est un jeu de cartes où chaque joueur pose des bâtiments, représentés par des cartes. Elles ont chacune un coût (compris entre 0 à 11), génère un revenu et des points de victoires. La plupart d’entre elles existent en plusieurs exemplaires. Certaines cartes possèdent aussi des symboles (fontaine, caddie et voiture) qui influencent le revenu ou les points gagnés.

Une carte du jeu

La répartition de ces symboles n’est pas uniforme comme on peut le constater sur l’histogramme suivant :
Répartition des cartes

Le graphique a été réalisé avec matplotlib, une bibilothèque python pour créer des graphiques 2D ou 3D. La façon de le réaliser sera abordée dans une seconde partie, la première étant consacrée à quelques remarques mise en évidence par le graphique.

Interprétation et limitation

Quelques faits mis en lumière par l’histogramme :

  • Plus les cartes coûtent cher, plus elles sont rares. Les cartes les plus courantes sont souvent en plusieurs exemplaires alors que les dernières sont uniques. Cependant certaines des moins onéreuses ne peuvent être joués qu’en un seul exemplaire.
  • Une stratégie Fontaine-Voiture semble plus difficile que Fontaine-Caddie ou Caddie-Voiture car le nombre de cartes ayant les deux couleurs ensemble est bien plus faible.
  • La carte Caddie la plus forte vaut 7, alors que pour les deux autres couleurs c’est 11. Plus coûteux, mais plus puissant…

Le graphique a aussi des limites :

  • La stratégie sans couleur ne semble pas pertinente alors que les Villas (sans couleur) valent 4 et ont une très bonne synergie entre elles.
  • Le graphique compte le nombre de cartes, mais certaines cartes de la moitié supérieure peuvent avoir plusieurs fois le même symboles (maximum trois). Le graphique donne donc une idée de la probabilité d’obtenir une carte avec le symbole donné, pas la probabilité du nombre de symboles obtenus.

Réalisation

L’interface de programmation ressemble à Pychart, une autre bibliothèque python pour faire des graphiques, présentée dans un article précédent. (Entre les deux, préférez matplotlib. (Oui, j’aime bien les parenthèses. (Pas vous ?)))

Par défaut, la sortie du graphique est dans une fenêtre de l’environnement de bureau. C’est pratique lorsqu’on fait des tests avec l’interpréteur python. C’est prévu pour, il existe même une option pour avoir directement matplotlib chargé au démarrage avec ipython (ipython --pylab).
Il est possible de changer la sortie au démarrage du script, à condition de le faire avant d’importer pyplot.
Pour avoir une sortie en PNG :

import matplotlib
matplotlib.use('Agg') # au début du script
from matplotlib import pyplot as plt

# ...
# plein de code malin et très lisible
# ...

plt.savefig("/tmp/thecity-histogramme.png")

Les données sont fournies dans un n-uplet représentant la distribution d’une valeur sur l’ensemble des barres. Par exemple, pour représenter la combinaison Fontaine-Voiture-Caddie (notée BVO) :

BVO = (3, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0) # répartition de la caractéristique BVO
p1 = plt.bar(index, BVO, WIDTH, color="#D70751") # représentation dans le graphique

C’est comme si on empilait les couches de données les unes au-dessus des autres. Pour les deuxièmes caractéristiques suivantes, il faut ajouter un paramètre bottom qui fournit la hauteur de départ pour la nouvelle couche.

p2 = plt.bar(index,
             BO,
             WIDTH,
             color="#D217F4",
             bottom=BVO)

Comme la hauteur sera différente pour chaque valeur, j’ai ajoutée une fonction qui fait la somme des listes pour la troisième couche et supérieures. C’est du code Python générique, donc utilisable dans n’importe quel autre contexte :

import itertools
def sum_cards(cards):
    sum_cards_by_value = lambda x, y: map(sum, itertools.izip(x, y))
    return reduce(sum_cards_by_value, cards)

Comportement :

In [4]: sum_cards([[1, 2, 3], [10, 20, 30]])
Out[4]: [11, 22, 33]

In [5]: sum_cards([[1, 2, 3], [10, 20, 30], [100, 200, 300]])
Out[5]: [111, 222, 333]

Le reste du code reste compréhensible simplement en le lisant ; il est fourni en fin de l’article.

À partir de matplotlib 1.2.0, un graphique pour des données continues est aussi disponible. Il est nommé stackplot (voir l’exemple fourni par matplotlib).

Sources

La boîte de jeu, amenée par Arthur, avec laquelle on joue dans la boîte.

Prise en main de matplotlib

Un exemple d’histogramme fourni par matplotlib

Script de génération de l’histogramme :

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

import itertools
import matplotlib
matplotlib.use('Agg')

import numpy as np

from matplotlib import pyplot as plt


BVO = (3, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0)
BO  = (0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0)
BV  = (0, 4, 2, 5, 0, 0, 0, 1, 0, 0, 0, 0)
VO  = (0, 7, 5, 0, 2, 0, 1, 0, 1, 1, 0, 0)
B   = (0, 7, 0, 4, 1, 3, 2, 1, 3, 1, 0, 1)
V   = (0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0)
O   = (0, 0, 2, 3, 3, 0, 1, 0, 1, 0, 0, 1)
no  = (0, 13, 11, 0, 8, 0, 0, 0, 0, 0, 0, 1)

WIDTH = 0.55

def max_sum():
    return max([
        BVO[i] + BO[i] + BV[i] + VO[i] + B[i] + V[i] + O[i] + no[i]
        for i
        in range(data_length())])

def data_length():
    return len(BVO)

def higher_card_cost():
    return data_length() - 1


index = np.arange(data_length())

def sum_cards(cards):
    sum_cards_by_value = lambda x, y: map(sum, itertools.izip(x, y))
    return reduce(sum_cards_by_value, cards)


p1 = plt.bar(index, BVO, WIDTH, color="#D70751")
p2 = plt.bar(index, BO, WIDTH, color="#D217F4", bottom=BVO)
p3 = plt.bar(index, BV, WIDTH, color="#0ED5D3", bottom=sum_cards([BVO, BO]))
p4 = plt.bar(index, VO, WIDTH, color="#E7F417", bottom=sum_cards([BVO, BO, BV]))
p5 = plt.bar(index, B, WIDTH, color="#0101f3", bottom=sum_cards([BVO, BO, BV, VO]))
p6 = plt.bar(index, V, WIDTH, color="#2fc62b", bottom=sum_cards([BVO, BO, BV, VO, B]))
p7 = plt.bar(index, O, WIDTH, color="#F3B439", bottom=sum_cards([BVO, BO, BV, VO, B,  V]))
p8 = plt.bar(index, no, WIDTH, color="#999999", bottom=sum_cards([BVO, BO, BV, VO, B, V, O]))


plt.ylabel(u"Quantité")
plt.xlabel(u"Coût")
plt.title("Distribution des cartes de The City")
plt.xticks(index+WIDTH/2., [str(i) for i in range(data_length())])
plt.yticks(np.arange(0, (max_sum() + 1), 10))
plt.legend((p1[0], p2[0], p3[0], p4[0], p5[0], p6[0], p7[0], p8[0]),
           ('Fontaine, Caddie, Voiture (BVO)', 'Fontaine, Voiture (BO)',"Fontaine, Caddie (BV)", "Caddie, Voiture (VO)", "Fontaine (B)", "Caddie (V)", "Voiture (O)", "Aucune couleur"))

plt.savefig("/tmp/thecity-histogramme.png")

From → Python

Laisser un commentaire

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :