Simulation à analyser

L’auteur de ce sujet a trouvé une solution à son problème.

Reprise du dernier message de la page précédente

Ce qui peut être intéressant pour augmenter la certitude dans ton résultat, c'est d'utiliser une autre méthode pour vérification, par exemple avec un tableur à la Excel. Si tes deux méthodes donnent des résultats différents, tu peux être sûr qu'au moins une des deux est fausse ! Si tu as envie de faire un tirage sur 10 millions d'essais, mieux vaut avoir un programme bien testé, parce que Excel ne te sera pas d'une grande aide.

+1 -0
Auteur du sujet

Oui tout à fait Aabu j'ai tenté de faire un excel, mais c'est pas mieux :(

J'ai tenté cette formule : =DECALER($L$7;9*LIGNE()+4;0) ET SI(L7=L8=L9;"Jackpot";SI(L7=L8 OU L7=L9 OU L8=L9;"Gain";"Perte")) Mais ça ne lui plait pas…

J'ai mis mes valeurs en :

L7 / L8 / L9 / Rien / L10 / L11 / L12 / Rien / … Donc je lui demande de décaler à chaque fois pour sauter l'espace, mais je ne sais pas si le "et" lui plaît ou non ?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
jackpot_bool = False
jackpot = 0
gain = 0
perte = 0

Fichier = open("test2.txt", "r")

lignes = Fichier.readlines()

for i in range (1,39996,4):
    if((lignes[i-1] == lignes[i]) and (lignes[i-1] == lignes[i+1])):
        print("Jackpot")
        jackpot += 1
        jackpot_bool = True

    elif((jackpot_bool == False) and (lignes[i-1] == lignes[i]) or (lignes[i] == lignes[i+1]) or (lignes[i-1] == lignes[i+1])):
        print("Gain")
        gain += 1
    else:
        print("Perte")
        perte+= 1

print(int(jackpot))
print(int(gain))
print(int(perte))

Fichier.close()

Sinon voici le code, j'ai 9999 simulations et il m'en affiche bien 9999, et les probabilités sont très proches de celles théoriques, alors sans certitude je dirai que ça fonctionne.

Édité par Dr@zielux

+0 -0

Cette réponse a aidé l’auteur du sujet

Bon a part ta ligne 23 qui peut être viré, je ne vois plus de bugs. Maintenant est ce que tu as du temps, et la motivation, pour qu'on te guide vers un code plus propre et plus pythonic ?

+0 -0

Ton code serait beaucoup plus simple si le fichier était mieux formaté, avec par exemple à chaque ligne le résultat des trois rouleaux. Il ne devrait pas être dur de modifier ton programme de simulation pour faire ça. Alternativement, awk fait ça très bien :

1
$ awk  '$1=$1'  RS='\n\n' OFS=', ' <numero_roues >numero_roues_bis

La répétition est la base de l’enseignement.  — ☮ ♡

+1 -0
Auteur du sujet

Je connaissais pas awk, j'en ai profité pour aller voir un petit peu le fonctionnement, je pourrais m'en resservir à l'occasion :) Mais la simulation elle était en c++, je n'avais pas encore regardé le python à l'époque (à l'époque c'était pas très vieux, c'était il y a 3 mois). Je pense cependant que le code c++ est beaucoup plus "propre" que mon petit code python. J'en profite pour mettre le code de la simulation, si certains détails pourraient être améliorer :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Prototype de Machine à sous fonctionnel
// Crée le 18/11/14 par Romain pour le TPE
// Modifié le 21/11/2014

using namespace std;

#include <iostream>
#include <ctime>
#include <math.h>
#include <cstdlib>
#include <fstream>

/* Déclaration d'une classe machine à sous contenant toutes les
variables utilisées lors de l'exécution du programme */

class machineASous
{
    private:

        int wheelA;
        int wheelB;
        int wheelC;
        double payOut;
        double moneyInMachine;
        //double gameCost;
        double moneyPaid;

    public:

        machineASous();
        bool displayMenu(void);
        bool pullHandle(void);
        double calculatePayout();
        void displaySpinResults();
        int Random(int, int);
};

int main(void)
{

    machineASous mySlot;

    bool ok = true;
    while (ok)
    {
    ok = mySlot.displayMenu();
    };

    return 0;

}

//Affiche le menu
bool machineASous::displayMenu(void)
{
    // Menu proposé au joueur
    //Permet de jouer ou de quitter le jeu

      char choice = 'Z';

      bool continueGame = true;

      cout << "\n\n(J)ouer : \t (Q)uitter : \n";
      cin >> choice;

      switch (choice)
      {
            case 'j':
            case 'J':
                if (pullHandle())
                {
                    cout << endl << endl << endl;
                    displaySpinResults();
                    cout << "Argent : " << calculatePayout() << " euros";
                }
                break;

            case 'q':
            case 'Q':
                continueGame = false;
                break;
      }

      return continueGame;
}

machineASous::machineASous ()
{

    srand((int) time(0));
    moneyInMachine = 100;
    moneyPaid     = 0;
    payOut       = 0;
    wheelA       = 0;
    wheelB       = 0;
    wheelC       = 0;
    //gameCost     = 0;
}

void machineASous::displaySpinResults()
{
    // Fonction permettant le calcul des valeurs des roues
    // Ainsi que l'affichage des résultat des trois roues

    ofstream flux_NWheel_Arduino("G:/TPE/Numeros_Roues.txt");
    int n;
    for(n = 1; n < 10000; n++)
    {
        wheelA = Random(1,9);
        wheelB = Random(1,9);
        wheelC = Random(1,9);

        //Ecriture des résultats obtenus sur les rouleaux dans un fichier .txt
        if(flux_NWheel_Arduino)
        {
        flux_NWheel_Arduino << wheelA << endl;
        flux_NWheel_Arduino << wheelB << endl;
        flux_NWheel_Arduino << wheelC << endl << endl;
        }
        else
        {
        cout << "ERREUR: Impossible d'ouvrir le fichier." << endl;
        }
    }


    cout << "[" << wheelA << "] "
         << "[" << wheelB << "] "
         << "[" << wheelC << "] \n\n";
}

double machineASous::calculatePayout()
{
    //Fonction permettant de jouer
    //renvoie le gain (ou la perte) en fin de fonction

    int jackPot = 500;
    int gain = 10;
    int perte = -10;

    //On détermine ici si le joueur a gagné le jackpot, ou sinon si il a gagné, ou si il a perdu.
    if (wheelA == wheelB && wheelA == wheelC)
    {
        cout << "JACKPOT! " << jackPot << endl;
        moneyInMachine += jackPot;
    }
    else if (wheelA == wheelB || wheelA == wheelC || wheelB == wheelC)
    {
        cout << "Vous avez gagne " << gain << endl;
        moneyInMachine += gain;
    }
    else if (wheelA != wheelB && wheelB != wheelC && wheelA != wheelC)
    {
        cout << "Vous avez perdu " << perte << endl;
        moneyInMachine += perte;
    }

    return moneyInMachine;
}

bool machineASous::pullHandle(void)
{
    //Fonction renvoyant une valeur booléenne (soit 1 soit 0) en fin de fonction
    //Cette valeur correspond à l'état du jeu : 1 le jeu continue, 0 le jeu s'arrtête

    if (moneyInMachine >= 10)
    {
        moneyInMachine -= moneyPaid;
        cout << "Vous avez " << moneyInMachine << endl;
    return true;
    }

    else if (moneyInMachine <= 10)
    {
        cout << "Vous n'avez plus d'argent" << endl;
    }
    return false;
}

//Initilisation de la fonction random
int machineASous::Random(int lowerLimit, int upperLimit)
{
    return 1 + rand() % (upperLimit - lowerLimit + 1);
}

Je vais tenter de mettre les résultats en ligne.

+0 -0

Cette réponse a aidé l’auteur du sujet

Ok commençons :

Déjà l'ouverture du fichier, tu ne le ferme qu'à la fin alors que tu lis tout le contenu dès le début. Pour éviter les problèmes, il est aussi conseiller d'utiliser un context manager (au cas où il y a des erreurs dans le code qui lève une exception.

Je remplacerais donc tes lignes 6-8 et 27 par :

1
2
with open("test2.txt", "r") as Fichier:
    lignes = Fichier.readlines()

Si tu as besoin de tester un autre fichier, il serait bien que le nom soit dans une variable en début de fichier :

1
2
3
4
NOM_FICHIER = "test2.txt

with open(NOM_FICHIER, "r") as fichier:
    lignes = fichier.readlines()

Ensuite, chaque ligne est un nombre, il est donc mieux de le convertir en entier plutot que de comparer des chaines de caractères. Par contre on ne peut pas convertir les lignes vides donc on va les enlever

1
2
3
4
5
6
7
NOM_FICHIER = "test2.txt

with open(NOM_FICHIER, "r") as fichier:
    lignes = fichier.readlines()

# On convertit chaque lignes en entier, en enlevant les eventuels espaces autour et en ignorant les lignes vides
list_elements = [int(l.strip()) for f in lignes if len(lignes.strip()) > 0]

Maintenant on a une liste contenant des entiers et on doit prendre les éléments 3 par 3 pour les comparer. Donc on va regrouper les éléments 3 par 3.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
NOM_FICHIER = "test2.txt

with open(NOM_FICHIER, "r") as fichier:
    lignes = fichier.readlines()

list_elements = [int(l.strip()) for f in lignes if len(lignes.strip()) > 0]

# list_elements[0::3] représente tous les élements prit 3 par 3 en partant de 0
# list_elements[1::3] représente tous les élements prit 3 par 3 en partant de 1
# list_elements[2::3] représente tous les élements prit 3 par 3 en partant de 2
# zip prend un élément de chaque list à la fois et les regroupes
i_triplet = zip(list_elements[0::3], list_elements[1::3], list_elements[2::3])

Enfin il faut compter si il y a 3, 2 ou aucun éléments égaux. Pour cela je te propose de convertir chacun des triplet en un set. Un set ne va garder qu'un seul élément de chaque type qu'il voit. Donc si les éléments sont tous différents, il aura une taille de 3, si il y en a deux pareils, il aura une taille de 2 et si ils sont tous égaux il n'y en aura qu'un. Pour convertir les triplets en set, et compter le nombre dans chaque :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
NOM_FICHIER = "test2.txt

with open(NOM_FICHIER, "r") as fichier:
    lignes = fichier.readlines()

list_elements = [int(l.strip()) for f in lignes if len(lignes.strip()) > 0]
i_triplet = zip(list_elements[0::3], list_elements[1::3], list_elements[2::3])

# conversion en set
i_set = map(set, i_triplet)
# comptage du nombre d'éléments dans chaque set
i_lset = map(len, i_set)

Enfin ce que tu veux c'est savoir combien il y a de set de 1, 2 ou 3 éléments. Pour cela la bibliothèque standard propose un objet counter qui fait ça pour toi :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from collections import Counter

NOM_FICHIER = "test2.txt

with open(NOM_FICHIER, "r") as fichier:
    lignes = fichier.readlines()

list_elements = [int(l.strip()) for f in lignes if len(lignes.strip()) > 0]
i_triplet = zip(list_elements[0::3], list_elements[1::3], list_elements[2::3])
i_set = map(set, i_triplet)
i_lset = map(len, i_set)

# On compte les éléments
count = Counter(i_lset)

Il ne reste plus qu'a afficher le résultat :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from collections import Counter

NOM_FICHIER = "test2.txt

with open(NOM_FICHIER, "r") as fichier:
    lignes = fichier.readlines()

list_elements = [int(l.strip()) for f in lignes if len(lignes.strip()) > 0]
i_triplet = zip(list_elements[0::3], list_elements[1::3], list_elements[2::3])
i_set = map(set, i_triplet)
i_lset = map(len, i_set)

count = Counter(i_lset)

print("Jackpot :", count[1])  # Un jackpot = plus qu'un element dans chaque set
print("Gain :", count[2])  # Un Gain = plus que deux elements dans chaque set
print("Perte :", count[3])  # Une perte = 3 elements dans chaque set

Voila il y a probablement encore mieux mais c'est déjà plus propre ! N'hésite pas si tu as des questions !

+3 -0
Auteur du sujet

Merci beaucoup pour tes corrections très complètes :) J'ai encore beaucoup de choses à voir puisque la majorité des mots me sont inconnus pour l'instant comme lstrip, lset, … Du coup je vais prendre le temps ligne par ligne et aller découvrir ces mots ^^ je reviendra avec un peu de recul si jamais j'ai des questions ou encore un soucis. Encore merci Kje d'avoir pris le temps de m'aider, bonne journée.

+0 -0

Cette réponse a aidé l’auteur du sujet

strip est une méthode des chaines de caractères qui va enlever les espaces et caractères blanc autour du contenu.

Par exemple :

1
2
a = "  toto   "
b = a.strip()

à la fin, b ne contiendra que "toto".

Les set c'est un ensemble, au sens mathematique du terme. Il ne garde qu'un seul élément de tout ce que tu lui donne. Donc tu peux t'en servir pour compter le nombre d'éléments différent dans une liste.

+0 -0

Cette réponse a aidé l’auteur du sujet

Pour changer le formatage, il suffit de modifier ainsi ton programme C++ :

114
115
116
117
118
//Ecriture des résultats obtenus sur les rouleaux dans un fichier .txt
        if(flux_NWheel_Arduino)
        {
        flux_NWheel_Arduino << wheelA <<", "<< wheelB ", "<< wheelC << endl;
        }

Il est alors possible de lire ligne par ligne.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
jackpot = 0
win = 0
loss = 0
total = 0

with open('numero_roues.txt', 'r') as f:
    for line in f:
        nb_diff = len(set(map(int, line.split(','))))
        jackpot += nb_diff == 1
        win += nb_diff == 2
        loss += nb_diff == 3
        total += 1

assert(total == jackpot + win + loss)

WIDTH = 20
num_width = len(str(total))
fmt = '{:.<'+str(WIDTH-num_width)+'}{:.>'+str(num_width)+'}'
print fmt.format('jackpot', jackpot)
print fmt.format('win', win)
print fmt.format('loss', loss)
print '-'*WIDTH
print fmt.format('total', total)

En dehors de la partie d’affichage ou je me suis un peu amusé, la difficulté est la ligne 8 qui compte le nombre de nombres différents dans une ligne. Mais comme l’idée est exactement la même du code de Kje, je ne la détaille pas.

Édité par simbilou

La répétition est la base de l’enseignement.  — ☮ ♡

+0 -0

Cette réponse a aidé l’auteur du sujet

Lu'!

Quelques commentaires au sujet du code C++ :

D'abord remplacer math.h par cmath.

Pour l'aléatoire, header <random>, ça évitera les limitations de srand/rand.

Le mot-clé "const" n'est pas optionnel, il doit être présent chaque fois que c'est possible.

1
2
3
4
bool ok = true;
while (ok){
  ok = mySlot.displayMenu();
};

aisément remplacé par :

1
while(mySlot.displayMenu());

displayMenu a d'ailleurs un nom très mal choisi car elle ne fait pas qu'afficher le menu, loin de là.

Pas de pré-déclaration non nécessaire :

1
2
3
int n;
for(n = 1; n < 10000; n++)
//...
1
2
for(int n = 1; n < 10000; n++)
//...

Quand on ouvre un fichier, on vérifie qu'il a bien été ouvert juste après ouverture, et on ne vérifie qu'une fois (on lance une exception s'il n'est pas ouvert), pas à chaque qu'on va faire une écriture dedans.

Ciao.

Édité par Ksass`Peuk

First : Always RTFM - "Tout devrait être rendu aussi simple que possible, mais pas plus." A.Einstein [Tutoriel Frama-C WP]

+1 -0
Auteur du sujet

Bonsoir à tous, je reviens après un long moment mais j'avais dit qu'avec le recul je reviendrai ^^

J'ai donc repris le code de Kje et étudié un petit peu les différents éléments du code, que je comprend sans grande difficulté maintenant, mis à part la ligne 8 qu'il fallait changer, elle ne fonctionnait pas :P

Je me suis rappelé de ce que disait Aabu sur l'intérêt de tester avec 2 méthodes différentes, et donc j'ai testé avec l'ancien et le nouveau code. Surtout qu'au final, il s'est avéré que l'ancien code ne fonctionnait pas, une fois que j'ai rajouté les mathématiques avec l'intervalle de confiance, je me suis rendu compte qu'on était très loin de ce que j'aurais du avoir.

Pour rappel l'ancien code (qui ne fonctionne pas bien donc ^^) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
jackpot_bool = False
jackpot = 0
gain = 0
perte = 0

Fichier = open("NR2.txt", "r")

lignes = Fichier.readlines()

for i in range (1,39996,4):
    if((lignes[i-1] == lignes[i]) and (lignes[i-1] == lignes[i+1])):
        #print("Jackpot")
        jackpot += 1
        jackpot_bool = True

    elif((jackpot_bool == False) and (lignes[i-1] == lignes[i]) or (lignes[i] == lignes[i+1]) or (lignes[i-1] == lignes[i+1])):
        #print("Gain")
        gain += 1
    else:
        #print("Perte")
        perte+= 1


print(int(jackpot))
print(int(gain))
print(int(perte))

Fichier.close()

et le nouveau :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from collections import Counter

nom_Fichier = "NR2.txt"

with open(nom_Fichier, "r") as fichier:
    lignes = fichier.readlines()

list_elements = [int(f.strip()) for f in lignes if len(f.strip()) > 0]
i_triplet = zip(list_elements[0::3], list_elements[1::3], list_elements[2::3])
i_set = map(set, i_triplet)
i_nombre_element_set = map(len, i_set)

count = Counter(i_nombre_element_set)

print("Jackpot : ", count[1])  # Un jackpot = 1 element dans chaque set
print("Gain : ", count[2])  # Un gain = 2 elements dans chaque set
print("Perte : ", count[3])  # Une perte = 3 elements dans chaque set

J'ai bien sur pris le même fichier texte de résultat pour tester les 2 codes.

Avec l'ancien code j'obtiens :

122 jackpot 1996 gains 7881 pertes

Avec le nouveau :

122 jackpot 2962 gains 6915 pertes

Et l'intervalle de confiance, à 95%, me donne ceci :

jackpot : 121 à 125 gains : 2954 à 2971 pertes : 6914 à 6922

On constate bien que le second code se situe bien dans l'intervalle de confiance, mais pourtant je ne vois aucun soucis dans le premier code ?

Alors ma question est simple, d’où vient cette grosse erreur ?

Bonne soirée à tous :)

Édité par Dr@zielux

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte