LOTO: analyse et statistiques
publication: 7 mars 2023 / mis à jour 8 mars 2023
Préambule
Le jeu du LOTO est une loterie publique. Le principe de base est simple. Il consiste à tirer un certain nombre de boules, toutes numérotées de 1 à n. En FRANCE, le LOTO historique tire 6 boules, numérotées de 1 à 49. Le LOTO de l'EURO MILLION tire 5 boules numérotées de 1 à 50.
Dans la suite de cet article, nous allons nous intéresser au tirage de l'EURO MILLION.
Les programmes en FORTH sont écrits pour s'adapter aux LOTOs de chaque pays.
Les programmes ont été écrits par modules. Les codes sources complets et actualisés sont disponibles ici:
MPETREMANN11 / uEforth / lotto
Structure des modules
Le pogramme de base s'appelle main.fs. C'est ce programme qui doit être compilé par eFORTH:
include main.fs
Le fichier main.fs contient les paramètres essentiels et les appels aux différents modules.
Les chiffres du LOTO
L'idée de départ est de créer une table contenant tous les chiffres du tirage de LOTO. ces données ont été récupérées sur le site
La Française des Jeux au format CSV. Ces données ont été nettoyées pour ne garder que les chiffres de chaque tirage, en excluant
les chiffres complémentaires. Grâce à un traitement de texte (Libre Office), chaque séparateur CSV a été transformé en c,
.
Il ne reste plus qu'à garnir les données avec les mots FORTH permettant de créer la table de données euroMillion
:
\ LOTO EURO MILLION FRANCE \ from 2004-02-13 to 2023-02-24 create euroMillion 5 , \ 5 numbers per grid in EURO MILLION (FR) 0 , \ init number of grids stored - 16 bits 07 c, 23 c, 34 c, 42 c, 48 c, 21 c, 22 c, 34 c, 41 c, 49 c, 08 c, 23 c, 27 c, 42 c, 45 c, 24 c, 26 c, 38 c, 43 c, 46 c, \ ...... 07 c, 13 c, 39 c, 47 c, 50 c, 16 c, 29 c, 32 c, 36 c, 41 c,
Le fichier euroMillionFR.fs contient tous les tirages de l'EURO MILLION du 2004-02-13 au 2023-02-24.
Les définitions d'usage général
Ces définitions sont dans le fichier generalWords.fs.
La première définition qui nous intéresse est LOTTO
:
structures struct LOTTO ptr field ->nbsPerGrid \ quantity of numbers per grid ptr field ->nbgrids \ number of grids stored ptr field ->datas \ datas in array forth
La structure LOTTO permet de gérer trois pointeurs. Ces pointeurs sont utilisés pour gérer les données de la table
euroMillion
.
Pour permettre l'adaptation des données à d'autres tirages, le LOTTO américain par exemple, on va passer par une indirection en créant
le mot LOTTOdatas
:
\ The LOTTOdatas vector makes it possible to manage any type \ of grid, for example 5x50 or 6x49 or other... defer LOTTOdatas
C'est ce mot LOTTOdatas
qui va recevoir son vecteur, ici en fin de fichier euroMillionFR.fs:
' euroMillion to LOTTOdatas updateLottoDatasFields
Il sera donc facile, si vous souhaitez gérer des données de tirage du LOTO de votre pays, de créer votre propre fichier, powerballUS.fs par exemple:
\ POWERBALL USA \ from 2004-02-13 to 2023-02-24 create powerBall 5 , \ 5 numbers per grid in powerball (FR) 0 , \ init number of grids stored - 16 bits \ ...... numbers here ' powerBall to LOTTOdatas updateLottoDatasFields
Passé cette étape, les traitements des données de tirage utiliseront toujours le mot LOTTOdatas
. Exemple:
\ fetch the number of numbers in a grid : nbsPerGrid@ ( -- n ) LOTTOdatas ->nbsPerGrid @ ;
Le mot nbsPerGrid@
récupère le nombre de numéros tirés dans un tirage de LOTO.
Le mot nbgrids@
récupère le nombre de grilles compilées dans le tableau des tirages de LOTO.
Gestion des numéros dans la grille
Voyons maintenant comment accéder et gérer ces numéros dans ces grilles de tirage.
Les mots suivants sont définis dans le fichier gridsManage.fs.
Le mot getGridAddr
récupère l'adresse d'une grille et le nombre de numéros dans cette grille:
\ fetch addr and len of a grid in LOTTOdatas : getGridAddr ( n -- addr n ) nbsPerGrid@ dup >r * getLOTTOdatasAddr + r> ;
Le mot getNumber
récupère un numéreo dans une grille et dépose sur la pile ce numéro et l'adresse incrémentée de une unité.
Cette incrémentation permet de préparer l'extraction du prochain numéro:
\ fetch number from addr; leave next addr and fetched number : getNumber ( addr -- addr+1 n ) dup 1+ swap c@ ;
Le mot inGrid?
indique si le nombre n figure dans une grille de tirage:
\ search n in grid
: inGrid? { n gridPos -- fl }
0 { fl }
gridPos getGridAddr
for
aft
getNumber n =
if
-1 to fl
then
then
next
drop
fl
;
Voyons maintenant comment afficher une grille.
Affichage d'une grille de LOTO
Notre premier mot ##
va simplement mettre un chiffre au format NN. Ainsi, tous les chiffres du LOTO seront
toujours affichés sur 2 digits:
\ n in form 00..99 : ## ( n -- addr len ) base @ >r decimal <# # # #> r> base ! ;
Ensuite, nous allons définir quatre couleurs d'affichage et les mots .nWitheBlack
et .nYellowRed
qui vont afficher un chiffre sur fond coloré:
0 constant BLACK 1 constant RED 11 constant YELLOW 15 constant WHITE : .nWitheBlack ( n -- ) WHITE fg BLACK bg ## type space ; : .nYellowRed ( n -- ) YELLOW fg RED bg ## type WHITE fg BLACK bg space ;
Et pour finir, voici le mot .grid
qui affiche une grille de tirage depuis le numéro de grille:
\ display complete grid from position gridPos
: .grid { gridPos -- }
gridPos 1- nbgrids@ >=
if
FRENCH ?\ gridPos . ." hors limite"
ENGLISH ?\ gridPos . ." out of range"
exit
then
cr
NR_RANGE 0 do
i 1+ gridPos inGrid?
if
i 1+ .nYellowRed
else
i 1+ .nWitheBlack
then
space
i 1+ nbsPerGrid@ mod 0=
if
cr
then
loop
;
Dans cette copie écran, on demande à afficher la grille 44:
Statistiques du LOTO
Le principe du LOTO nous permet d'envisager certaines analyses statistiques. La première analyse statistiques venant à l'esprit, c'est tout simplement étudier la fréquence d'apparition des numéros tirés.
Fréquence de tirage des numéros
Le code complet se trouve dans le fichier numbersFrequency.fs.
On commence par définir la table frequencyTable
qui va mémoriser la fréqence de tirage de chaque numéro:
create frequencyTable NR_RANGE cell * allot
On définir ensuite le mot getFreqAddr
qui récupère l'adresse de l'item qui nous intéresse dans la table frequencyTable
:
\ get addr from frequency position : getFreqAddr { position -- addr } \ range of position: 0..NR_RANGE-1 position NR_RANGE 1- > if FRENCH ?\ position ." position " . ." hors limite pour frequencyTable" ENGLISH ?\ position ." position " . ." out of range for frequencyTable" cr exit then position cell * frequencyTable + ;
Dans ce mot getFreqAddr
, on vérifie si la position demandée n'est pas hors limite.
On définit ensuite le mot FreqAddr++
qui incrémente le contenu d'une valeur à la position demandée.
Par exemple, si la boule 17 sort, on va incrémenter la valeur de position 17 dans la table frequencyTable
.
\ increment contenu of frequency number : FreqAddr++ ( position -- ) \ range of position: 0..NR_RANGE-1 getFreqAddr 1 swap +! ;
Le mot initFrequency
remet toutes les valeurs de la table frequencyTable
à zéro:
\ reset content of frequencyTable : initFrequency ( -- ) NR_RANGE for aft 0 i 1- getFreqAddr ! then next ;
Le mot analyzeFrequency
va lire le contenu de la table pointée par LOTTOdatas. Chaque boule tirée incrémente
la position correspondante dans le tableau frequencyTable
:
\ count apparition of each number in LOTTOdatas table : analyzeFrequency ( -- ) initFrequency nbsPerGrid@ nbgrids@ * for aft i getLOTTOdatasAddr + c@ 1- FreqAddr++ then next ;
Et pour finir, on définit le mot .frequency
qui analyse et affiche la fréquence de tirage de chaque boule du LOTO:
\ display frequency of numbers distribution : .frequency ( -- ) analyzeFrequency NR_RANGE for aft NR_RANGE i - dup ## type ." :" 1- getFreqAddr @ 5 .r 6 spaces i 5 mod 0= if cr then then next ;
Toutes ces valeurs analysées en FORTH correspondent à celles données par le site de la Française des Jeux.
Comme il est assez fastidieux de lire ces valeurs pour trouver la plus grande et la plus petite, on va demander à FORTH de faire ce travail pour nous.
Numbers drawn most and least often
The word searchHighLowFrequency will search for the highest and lowest value in our frequencyTable
table.
This definition uses local values to make the program more readable on the one hand, to avoid complex stack manipulations on the other hand.
0 value LOW_NUM 0 value HIGH_NUM : searchHighLowFrequency ( -- ) 1 { lowest_num } 1 32 lshift { lowest_val } NR_RANGE { highest_num } 0 { highest_val } NR_RANGE for aft \ searches for the most frequently dialed number i getFreqAddr @ dup highest_val > if to highest_val i 1+ to highest_num else drop then \ searches for the number issued the least often i getFreqAddr @ dup lowest_val < if to lowest_val i 1+ to lowest_num else drop then then next highest_num to HIGH_NUM lowest_num to LOW_NUM ;
Pour afficher le résultat de la recherche de la plus grande et plus petite valeur de fréquence de sortie de
chaque numéro, on crée le mot .frequHighLow
qui va afficher le résultat proprement:
: .frequHighLow ( -- )
searchHighLowFrequency
cr
FRENCH ?\ ." numéro sorti le plus souvent....: "
ENGLISH ?\ ." number issued most often........: "
HIGH_NUM ## type ." ("
HIGH_NUM 1- getFreqAddr @ . ." x)"
cr
FRENCH ?\ ." numéro sorti le moins souvent...: "
ENGLISH ?\ ." number issued least often.......: "
LOW_NUM ## type ." ("
LOW_NUM 1- getFreqAddr @ . ." x)"
;
Voici le résultat de l'exécution de .frequHighLow
:
--> .frequHighLow number issued most often........: 50 (356 x) number issued least often.......: 22 (133 x)
Définition d'un interface
L'interface est la partie de code permettant un accès simple aux fonctionnalités du programme.
Notre premier mot interfaceTitle
permet d'afficher à la position x y le titre de la page d'interface:
\ interface title : interfaceTitle ( x y -- ) to _DY to _DX _DX _DY at-xy ." +-----------------------------+" 1 _DY+ _DX _DY at-xy FRENCH ?\ ." | ANALYSE CHIFFRES DU LOTO |" ENGLISH ?\ ." | LOTTO NUMBERS ANALYSIS |" 1 _DY+ _DX _DY at-xy ." +-----------------------------+" ;
Le mot interfaceOptions
affiche les options:
\ display options : interfaceOptions ( x y -- ) to _DY to _DX _DX _DY at-xy FRENCH ?\ ." D .. affiche la distribution des numeros du LOTO" ENGLISH ?\ ." D .. display frequency of LOTTO numbers distribution" 1 _DY+ _DX _DY at-xy FRENCH ?\ ." Q .. quitter" ENGLISH ?\ ." Q .. quit" 2 _DY+ 5 _DX+ _DX _DY at-xy FRENCH ?\ ." Appui touche: " ENGLISH ?\ ." Press key: " ;
Le mot interfaceActions
gère les actions selon la touche clavier activée:
\ execute options : interfaceActions ( key -- ) 2 _DY+ 0 to _DX _DX _DY at-xy case [char] D of .frequency cr .frequHighLow endof endcase ;
Et enfin, le mot interface
regroupe les précédentes définitions:
\ main interface : interface ( -- ) page begin 8 2 interfaceTitle 2 6 interfaceOptions Xkey dup [char] Q = if drop exit else interfaceActions then again ;
L'exécution de interface
affiche ceci:
+-----------------------------+ | LOTTO NUMBERS ANALYSIS | +-----------------------------+ D .. display frequency of LOTTO numbers distribution Q .. quit Press key:
L'appui sur la touche D affiche ceci:
+-----------------------------+ | LOTTO NUMBERS ANALYSIS | +-----------------------------+ D .. display frequency of LOTTO numbers distribution Q .. quit Press key: 01 : 162 02 : 150 03 : 162 04 : 163 05 : 169 06 : 158 07 : 161 08 : 145 09 : 151 10 : 171 11 : 161 12 : 166 13 : 158 14 : 164 15 : 169 16 : 152 17 : 177 18 : 137 19 : 186 20 : 168 21 : 181 22 : 133 23 : 183 24 : 161 25 : 174 26 : 176 27 : 172 28 : 157 29 : 171 30 : 165 31 : 154 32 : 150 33 : 134 34 : 155 35 : 160 36 : 149 37 : 170 38 : 177 39 : 159 40 : 147 41 : 138 42 : 182 43 : 156 44 : 179 45 : 166 46 : 136 47 : 144 48 : 153 49 : 160 50 : 534 number issued most often........: 50 (534 x) number issued least often.......: 22 (133 x)
Les définitions de la partie interface sont faciles à compléter si on rajoute d'autres traitement de données sur les numéros du LOTO.
Mais là n'est pas le but de cet article.
En passant en revue notre programme, on constate que les mots sont définis dans différents fichiers. Le contenu de chaque fichier regroupe les mots par fonctionnalités. Ceci permet un développement facile. Le contenu des différents fichier est chargé et compilé depuis le fichier main.fs.
Il est fortemùent conseillé de grouper les fichiers d'un projet dans un répertoire dédié. Dans notre exemple, ce répertoire s'appelle lotto.
Bonne programmation.
Legal: site web personnel sans commerce / personal site without seling