Afin d'améliorer les résultats obtenus, au lieu de considérer une lettre à la fois, nous allons travailler sur des groupes de lettres. Dans un premier temps, nous allons travailler avec des triplets de lettres (ou de caractères). Dans une chaîne de Markov, on appelle ces triplets des "3-grammes" (on parle de n-gramme pour des groupes de n lettres).

À faire vous-même 4.1

Analysez et testez le code suivant :


var tabMots;
var chaineMots="";
var objNgramme={};
function preload(){
	tabMots=loadStrings("liste_mots.txt");
}
function setup(){
	noCanvas;
	for (i=0; i<tabMots.length;i++){
		chaineMots=chaineMots+tabMots[i]+" ";
	}
	for (i=0;i<chaineMots.length;i++){
		var ngramme=chaineMots.substring(i,i+3);
		if (!objNgramme[ngramme]){
			objNgramme[ngramme]=[]
			objNgramme[ngramme].push(chaineMots.charAt(i+3));
		}
		else {
			objNgramme[ngramme].push(chaineMots.charAt(i+3));
		}
	}
	createP ('Le 3-gramme "aba" est suivi par les lettres suivantes :');
	createP(objNgramme["aba"]);
	createP ('Le 3-gramme " di" est suivi par les lettres suivantes :');
	createP(objNgramme[" di"]);
}
			

Vous devriez obtenir ceci :

Pas beaucoup de nouveautés dans le code ci-dessus :

Pour la chaîne de caractère chaineMots="a à abaissa" nous obtiendrons l'objet suivant :


objNgramme={"a à":[" "]," à ":["a"],"à a":["b"]," ab":["a"],"aba":["i"],"bai":["s"],"ais":["s"],"iss":["a"],"ssa":"","sa":""}
			

À faire vous-même 4.2

Modifiez le programme du "À faire vous-même 4.1" afin d'obtenir le tableau des caractères qui suivent le 3-gramme "bai"


À faire vous-même 4.3

Testez et analysez le programme ci-dessous


var tabMots;
var chaineMots="";
var objNgramme={};
function preload(){
	tabMots=loadStrings("liste_mots.txt");
}
function setup(){
	noCanvas;
	var bouton=createButton("Cliquez ici")
	bouton.mousePressed(creationMot)
	for (i=0; i<tabMots.length;i++){
		chaineMots=chaineMots+tabMots[i]+" ";
	}
	for (i=0;i<chaineMots.length;i++){
		var ngramme=chaineMots.substring(i,i+3)
		if (!objNgramme[ngramme]){
			objNgramme[ngramme]=[]
			objNgramme[ngramme].push(chaineMots.charAt(i+3));
		}
		else {
			objNgramme[ngramme].push(chaineMots.charAt(i+3));
		}
	}
}
function draw(){}
function creationMot(){
	var ngrammCourant="aba";
	var possible=objNgramme[ngrammCourant];
	var prochain=random(possible)
	var resultat=ngrammCourant+prochain;
	createP(resultat)
}
			

Rien de nouveau par rapport à l'activité 3, nous créons un mot de 4 lettres qui commence par le 3-gramme "aba".


Vous devriez obtenir ceci :

À faire vous-même 4.4

Modifiez le programme du "À faire vous-même 4.3" afin d'obtenir un mot de 4 lettres commençant par "adi"


À faire vous-même 4.5

Testez et analysez le programme suivant :


var tabMots;
var chaineMots="";
var objNgramme={};
var ordre=3;
function preload(){
	tabMots=loadStrings("liste_mots.txt");
}
function setup(){
	noCanvas;
	var bouton=createButton("Cliquez ici")
	bouton.mousePressed(creationMot)
	for (i=0; i<tabMots.length;i++){
		chaineMots=chaineMots+tabMots[i]+" ";
	}
	for (i=0;i<chaineMots.length;i++){
		var ngramme=chaineMots.substring(i,i+ordre)
		if (!objNgramme[ngramme]){
			objNgramme[ngramme]=[]
			objNgramme[ngramme].push(chaineMots.charAt(i+ordre));
		}
		else {
			objNgramme[ngramme].push(chaineMots.charAt(i+ordre));
		}
	}
}
function draw(){}
function creationMot(){
	var ngrammCourant="adi";
	var resultat=ngrammCourant
	for (i=0;i<10;i++){
		var possible=objNgramme[ngrammCourant];
		var prochain=random(possible);
		if (prochain==" "){
			break;
		}
		resultat=resultat+prochain;
		ngrammCourant=resultat.substring(resultat.length-ordre,resultat.length);
	}
	createP(resultat)
}
			

Dans le code ci-dessus nous créons de mots, commençant par "adi", et d'au maximum 10 lettres.

le break permet de stopper la boucle si le caractère tiré au sort est un espace (afin d'éviter des "mots à trou")

Nous avons aussi introduit la variable "ordre" qui donne l'ordre du n-gramme (ici nous avons toujours des 3-grammes).

La ligne ngrammCourant=resultat.substring(resultat.length-ordre,resultat.length); permet de sélectionner le dernier n-gramme du mot en cours de construction.


Vous devriez obtenir ceci :

À faire vous-même 4.6

Modifiez le programme vu dans le "À faire vous-même 4.5" afin que les mots générés commencent tous par "da".

Vous devriez obtenir ceci :


Pour l'instant, nous sommes obligés d'indiquer le n-gramme qui commencera le mot (var ngrammCourant="adi"; dans le "À faire vous-même 4.5"). Nous allons maintenant choisir ce premier n-gramme par tirage au sort.

À faire vous-même 4.7

Testez et analysez le programme suivant :


var tabMots;
var chaineMots="";
var objNgramme={};
var debut=[];
var ordre=3;
var nbreLettreMax=10;
function preload(){
	tabMots=loadStrings("liste_mots.txt");
}
function setup(){
	noCanvas;
	bouton=createButton("Cliquez ici");
	bouton.mousePressed(creationMot);
	for (i=0;i<tabMots.length;i++){
		var lettres=tabMots[i].substring(0,ordre);
		if (lettres.length==ordre){
			debut.push(lettres);
		}
	}
	for (i=0; i<tabMots.length;i++){
		chaineMots=chaineMots+tabMots[i]+" ";
	}
	for (i=0;i<chaineMots.length;i++){
		var ngramme=chaineMots.substring(i,i+ordre)
		if (!objNgramme[ngramme]){
			objNgramme[ngramme]=[]
			objNgramme[ngramme].push(chaineMots.charAt(i+ordre));
		}
		else {
			objNgramme[ngramme].push(chaineMots.charAt(i+ordre));
		}
	}
}
function draw(){}
function creationMot(){
	var ngrammCourant=random(debut);
	var resultat=ngrammCourant
	for (i=0;i<nbreLettreMax;i++){
		var possible=objNgramme[ngrammCourant];
		var prochain=random(possible);
		if (prochain==" "){
			break;
		}
		resultat=resultat+prochain;
		ngrammCourant=resultat.substring(resultat.length-ordre,resultat.length);
	}
	createP(resultat)
}
			

Vous devriez obtenir ceci :

La seule nouveauté, la boucle "for" :


	for (i=0;i<tabMots.length;i++){
		var lettres=tabMots[i].substring(0,ordre);
		if (lettres.length==ordre){
			debut.push(lettres);
		}
	}
			

Cette boucle permet de compléter le tableau "debut" avec les 3-gramme que l'on trouve à chaque début de mot (s'il existe).

Il ne reste plus ensuite qu'à tirer au sort un de ces 3-grammes var ngrammCourant=random(debut); et le tour est joué...


Vous pouvez constater que la situation s'est bien améliorée (même si tout n'est pas encore parfait...)

À faire vous-même 4.8

Modifiez le code du "À faire vous-même 4.8" afin d'avoir des 2-grammes ou des 4-grammes à la place des 3-grammes, constatez-vous une différence ?


Pour terminer, nous allons utiliser un autre fichier texte, tiré de l'oeuvre de Gustave Flaubert, 3 contes.

À faire vous-même 4.9

Téléchargez le fichier flaubert.txt (clic droit "Enregistrer sous"). Une fois téléchargé, placez ce fichier dans le même répertoire que "script.js"


À faire vous-même 4.10

En vous inspirant de ce qui a été fait précédemment, écrivez un programme qui permettra de générer un texte aléatoire d'environ 200 caractères (la chaîne de Markov utilisée pour construire ce texte devra s'appuyer sur le texte de Flaubert). N'hésitez pas à tester différents paramètres afin d'essayer d'améliorer le résultat final.

Vous devriez obtenir ceci :