The goal is to make a word generator. The program takes a word list (typically, it may be the full dictionary of a language, or a list of names), analyses it, and then invents word that sound alike the one in the list.
There is multiple parts of the program, which is embedded in a Qt GUI. I used Qt Creator 4.9.2 (based on Qt 5.12.4, GCC 5.3.1, 64 bits).
It is all mostly in french (variable names and UI texts), sorry about that. I commented in English, I hope it's enough.
About how the program works :
Analyzing the word means noting an occurrence for each succession of character present in this word. If a succession of characters appear in multiple words, multiple occurrences are noted and hence it is more probable to generate this succession.
In the fonction.h, analysis is made by 'analyseWord' (but it only handles ASCII characters), or by another version 'QanalyseWord' using Qchar instead of char (hence any utf-8 character).
Depending on the type of analysis made, word generation is made by 'generateur' or 'Qgenerateur'
For the program itself, the main.cpp is only what's needed to launch the mainwindow ("FenetrePrincipale")
#include <QtWidgets>
#include "fenetreprincipale.h"
#include "fonctions.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
srand( static_cast<unsigned int>(time(NULL)));
/*Traduction of Qt texts to Fr*/
QString locale = QLocale::system().name().section('_', 0, 0);
QTranslator translator;
translator.load(QString("qt_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&translator);
/*end*/
FenetrePrincipale fenetre;
fenetre.show();
return app.exec();
}
FenetrePrincipale handles all the interaction of the program. It has two tabs (one for analysis, one for generating words). Its .ui file is :
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FenetrePrincipale</class>
<widget class="QMainWindow" name="FenetrePrincipale">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>702</width>
<height>539</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="windowTitle">
<string>GeMots</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="onglet_analyse">
<attribute name="title">
<string>Analyse d'une liste de mots</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="6" column="0">
<widget class="QProgressBar" name="progr_Analyse">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>15</height>
</size>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0">
<widget class="QPushButton" name="bouton_analyser">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Lancer l'analyse</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QFrame" name="frame_mode">
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="1" colspan="2">
<widget class="QRadioButton" name="radio_speciaux">
<property name="toolTip">
<string>C'est beau l'utf-8, mais c'est chiant à utiliser !</string>
</property>
<property name="text">
<string>Gère tout les caractères spéciaux</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="4" rowspan="4">
<widget class="Line" name="line_details">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_lcoh">
<property name="text">
<string>Longueur de cohérence :</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spin_lcoh">
<property name="accelerated">
<bool>true</bool>
</property>
<property name="suffix">
<string> lettres</string>
</property>
<property name="minimum">
<number>2</number>
</property>
<property name="value">
<number>3</number>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="Qualite">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Qualité</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="5">
<widget class="QLabel" name="Bof">
<property name="toolTip">
<string>Pour ce que le programme fait (lire des suites de lettres. Noter le nombre d'occurence),
cette méthode est honteusement longue</string>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(223, 177, 19);</string>
</property>
<property name="text">
<string>Bof</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QLabel" name="Parfait_2">
<property name="toolTip">
<string>C'est presque instantanné. Normal, y a vraiment pas besoin d'un supercalculateur pour faire ça</string>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(44, 161, 40);</string>
</property>
<property name="text">
<string>Parfait</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="Bof_2">
<property name="toolTip">
<string>On génère pas des mots accentués. Et en plus, ça gère pas les tirets</string>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(223, 177, 19);</string>
</property>
<property name="text">
<string>Bof</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="Minable">
<property name="toolTip">
<string>J'voulais pas faire un truc pour les anglais, moi !</string>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 0, 0);</string>
</property>
<property name="text">
<string>Minable</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLabel" name="Rapidite">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Rapidité</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="Parfait">
<property name="toolTip">
<string>Testez avec le Japonnais ! Promis, ça marche !</string>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(44, 161, 40);</string>
</property>
<property name="text">
<string>Parfait</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QLabel" name="Minable_2">
<property name="toolTip">
<string>En même temps, c'est codé avec les pieds</string>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 0, 0);</string>
</property>
<property name="text">
<string>Minable</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QRadioButton" name="radio_ignore">
<property name="toolTip">
<string>Les lettres accentuées sont supprimée par l'analyse : on regarde le mot "ttt" au lieu de "étêtât"
Il vaut donc mieux que la liste de mots originale soit sans accents</string>
</property>
<property name="text">
<string>Ignore les accents</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QRadioButton" name="radio_minable">
<property name="toolTip">
<string>Ces caractères spéciaux sont remplacé par leur valeur non-accentué :
ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÌÍÎÏìíîïÙÚÛÜùúûüÿÑñÇç
Mais ce traitement est long et nul ! Oui, mais je me suis fait chier à le coder, je vais pas le supprimer...</string>
</property>
<property name="text">
<string>Gère très mal les accents</string>
</property>
</widget>
</item>
<item row="4" column="5">
<widget class="QPushButton" name="bouton_details">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string>(+ détails)</string>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_mode">
<property name="text">
<string>Mode de traitement :</string>
</property>
</widget>
</item>
<item row="4" column="2" colspan="3">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="5" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="9" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QFrame" name="frame_choixListe">
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0" colspan="2">
<widget class="QRadioButton" name="radio_langDef">
<property name="text">
<string>Utiliser la langue par défaut (////Nom liste défaut////)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="radio_langPerso">
<property name="text">
<string>Choisir une liste de mot</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_choixLang">
<property name="text">
<string>Choix de la liste de mots à analyser :</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="bouton_selecFichier">
<property name="text">
<string>(Aucun)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="onglet_generation">
<property name="enabled">
<bool>false</bool>
</property>
<attribute name="title">
<string>Génération de mots</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_5">
<item row="4" column="1">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_tailleMots">
<property name="text">
<string>Taille max des mots</string>
</property>
</widget>
</item>
<item row="9" column="2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="10" column="2">
<widget class="QPushButton" name="bouton_trier">
<property name="text">
<string>Trier par taille</string>
</property>
</widget>
</item>
<item row="11" column="2">
<widget class="QPushButton" name="bouton_nettoyer">
<property name="text">
<string>Nettoyer</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="check_forcerTaille">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Forcer la taille des mots</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spin_tailleMax">
<property name="suffix">
<string> lettres</string>
</property>
<property name="minimum">
<number>2</number>
</property>
<property name="singleStep">
<number>2</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
<item row="0" column="3" rowspan="13">
<widget class="QTextEdit" name="text_mots"/>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spin_nbMots">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QCheckBox" name="check_troll">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Génération de mots parfaits</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_nbMots">
<property name="text">
<string>Nombre de mots</string>
</property>
</widget>
</item>
<item row="10" column="0" rowspan="2" colspan="2">
<widget class="QFrame" name="fram_resume">
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_resume_analyse">
<property name="text">
<string>Type d'analyse : //type//</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_resume_lcoh">
<property name="text">
<string>Longueur de cohérence : //lcoh//</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QPushButton" name="bouton_generer">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Inventer des mots</string>
</property>
</widget>
</item>
<item row="8" column="1">
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="7" column="1">
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Analyse utilisée :</string>
</property>
<property name="alignment">
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
</widget>
</item>
<item row="9" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>702</width>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menuMenu">
<property name="title">
<string>Menu</string>
</property>
<widget class="QMenu" name="menuQuitter">
<property name="title">
<string>Quitter</string>
</property>
<widget class="QMenu" name="menuQuitter_2">
<property name="title">
<string>Quitter</string>
</property>
<addaction name="actionNe_pas_quitter"/>
<addaction name="actionNe_pas_quitter_2"/>
<addaction name="actionNe_pas_quitter_3"/>
<addaction name="actionQuitter_3"/>
<addaction name="actionNe_pas_quitter_4"/>
</widget>
<addaction name="menuQuitter_2"/>
</widget>
<addaction name="separator"/>
<addaction name="actionUtiliser_les_valeur_actuelles_par_defaut"/>
<addaction name="separator"/>
<addaction name="menuQuitter"/>
</widget>
<widget class="QMenu" name="menuA_propos">
<property name="title">
<string>A propos</string>
</property>
<addaction name="actionAide"/>
<addaction name="action_propos_de_ce_programme"/>
</widget>
<addaction name="menuMenu"/>
<addaction name="menuA_propos"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionQuitter_3">
<property name="text">
<string>Ha oui, quitter</string>
</property>
</action>
<action name="actionNe_pas_quitter">
<property name="text">
<string>Ne pas quitter</string>
</property>
</action>
<action name="actionNe_pas_quitter_2">
<property name="text">
<string>Ne pas quitter</string>
</property>
</action>
<action name="actionNe_pas_quitter_3">
<property name="text">
<string>Ne pas quitter</string>
</property>
</action>
<action name="actionNe_pas_quitter_4">
<property name="text">
<string>Ne pas quitter</string>
</property>
</action>
<action name="actionUtiliser_les_valeur_actuelles_par_defaut">
<property name="text">
<string>Changer les valeurs par défaut</string>
</property>
</action>
<action name="actionCharger_automatiquement_la_liste_de_mot_par_d_faut">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Charger la liste par défaut au lancement</string>
</property>
</action>
<action name="actionAnalyser_la_liste_par_d_faut_au_lancement">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Analyser la liste par défaut au lancement</string>
</property>
</action>
<action name="actionAide">
<property name="text">
<string>Aide</string>
</property>
</action>
<action name="action_propos_de_ce_programme">
<property name="text">
<string>À propos de ce programme</string>
</property>
</action>
</widget>
<resources/>
<connections>
<connection>
<sender>radio_speciaux</sender>
<signal>toggled(bool)</signal>
<receiver>spin_lcoh</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>318</x>
<y>320</y>
</hint>
<hint type="destinationlabel">
<x>255</x>
<y>351</y>
</hint>
</hints>
</connection>
</connections>
</ui>
then, the .h file :
#ifndef FENETREPRINCIPALE_H
#define FENETREPRINCIPALE_H
#include <QMainWindow>
#include <QProgressBar>
#include "fonctions.h"
#include "fenaide.h"
#include "infos.h"
namespace Ui {
class FenetrePrincipale; //=Main Window
}
class FenetrePrincipale : public QMainWindow
{
Q_OBJECT
public:
explicit FenetrePrincipale(QWidget *parent = 0);
~FenetrePrincipale();
enum type_Trait {aucun, ascii, asciiplus, utf_8};
type_Trait selectedTrait();
type_Trait stringToType(QString stringType);
public slots:
//Analyses a wordlist
void on_bouton_analyser_clicked();
//Generates a word based on previously analysed wordlist
void on_bouton_generer_clicked();
//Choose path to the wordlist
void on_bouton_selecFichier_clicked();
//Adds detail on the 3 possible analyses
void on_bouton_details_clicked();
//Removes all generated words
void on_bouton_nettoyer_clicked();
//Sort generated words by lenght
void on_bouton_trier_clicked();
//Menu icon 'Aide'
void on_actionAide_triggered();
//Menu icon 'About'
void on_action_propos_de_ce_programme_triggered();
//Change the default values of the Analyse tab to the current values.
void on_actionUtiliser_les_valeur_actuelles_par_defaut_triggered();
// Just a test function : unckecks the box 0.4 second after it has been clicked
void on_check_troll_clicked();
void unchecking();
//Message when quitting through menu
void quit_troll();
private slots:
//Indicates if the current parameters of the 'Analyse tab' have been modified since previous analisys
void check_analyse_changed();
//Checks if the current coherence lengh have been modified since previous analisys
void on_spin_lcoh_valueChanged(int value);
//Checks if the current analysis method have been modified since previous analisys
void traitement_modifie();
//Checks if the current wordlist have been modified since previous analisys
void liste_modifie();
private:
Ui::FenetrePrincipale *ui;
// QString nomListeMotsDefaut;
QString nomListeMotsDefaut="WordLists/Mots_FR_full.txt";
double probatab[27][27][27] = {{{0}}}; //result of the analysis of the wordlist (for 'ascii' and 'ascii+')
std::map<std::vector<QChar>, std::pair<int,double>> charmap; //result of the analysis (for 'utf-8')
//Parameter of the previous analysis:
QString nomListeMots; //name of the wordlist
type_Trait analyse = aucun; //indicates what analysis has previously been done. Acun = nothing
uint lcoh; //coherence lengh of previous analyse
//Indicates if a change has been made on the 'Analysis' tab
bool listeMots_changed=false;
bool traitement_changed=false;
bool lcoh_changed=false;
QString nomListeAnalysePrecedente;
FenAide *m_FenAide;
Infos *m_Infos;
};
#endif // FENETREPRINCIPALE_H
and the .cpp file
#include <QFileDialog>
#include <QProgressBar>
#include <QTimer>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QMessageBox>
#include <QShortcut>
#include <thread>
#include "fenetreprincipale.h"
#include "ui_fenetreprincipale.h"
FenetrePrincipale::FenetrePrincipale(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::FenetrePrincipale)
{
ui->setupUi(this);
//Indication des tooltip longs
QString ListeMotsInstruction("La liste de mot doit être au format .txt, avec 1 seul mot par ligne\n"
"Si plusieurs mots par lignes, seul le premier est pris en compte");
ui->radio_langPerso->setToolTip(ListeMotsInstruction);
ui->bouton_selecFichier->setToolTip(ui->radio_langPerso->toolTip());
//Adaptation de la progressbar
ui->progr_Analyse->setAlignment(Qt::AlignCenter);
//Éléments de la statusbar
ui->statusbar->setFixedHeight(20);
ui->statusbar->showMessage("En attente de lancement...");
//Lecture du fichier des valeurs par défaut:
QFile file("WordLists/Parametres.xml");
if(file.open(QIODevice::ReadOnly)) {
QXmlStreamReader xmlReader(&file);
if(xmlReader.readNextStartElement()) {
if (xmlReader.name() == "valeursDef") {
while(xmlReader.readNextStartElement()) {
if (xmlReader.name() == "nomListe")
nomListeMotsDefaut = xmlReader.readElementText();
else if (xmlReader.name() == "modeTraitement") {
type_Trait wantedAnalyse = stringToType(xmlReader.readElementText());
if(wantedAnalyse==ascii)
ui->radio_ignore->setChecked(true);
else if(wantedAnalyse==asciiplus)
ui->radio_minable->setChecked(true);
else if(wantedAnalyse==utf_8)
ui->radio_speciaux->setChecked(true);
}
else if (xmlReader.name() == "lcoh")
ui->spin_lcoh->setValue(xmlReader.readElementText().toInt());
else if (xmlReader.name() == "nbMots")
ui->spin_nbMots->setValue(xmlReader.readElementText().toInt());
else if (xmlReader.name() == "tailleMax")
ui->spin_tailleMax->setValue(xmlReader.readElementText().toInt());
else
xmlReader.skipCurrentElement();
}
}
xmlReader.skipCurrentElement();
}
}
else{
ui->statusbar->showMessage("Problème lors de la lecture des valeurs par défaut");
}
//Indication de la liste par défaut
QFileInfo fi(nomListeMotsDefaut);
QString textLangDef = "Utiliser la langue par défaut ("+fi.fileName()+")";
ui->radio_langDef->setText(textLangDef);
//Efface tous les éléments affiché par le bouton "détail"
ui->Bof->setVisible(false);
ui->Bof_2->setVisible(false);
ui->Minable->setVisible(false);
ui->Minable_2->setVisible(false);
ui->Parfait->setVisible(false);
ui->Parfait_2->setVisible(false);
ui->Qualite->setVisible(false);
ui->Rapidite->setVisible(false);
ui->line_details->setVisible(false);
//Selectionne l'onglet de départ
ui->tabWidget->setCurrentIndex(0);
//Connexion signal/slot pour detection changement
QObject::connect(ui->radio_ignore, SIGNAL(clicked()), this, SLOT(traitement_modifie()));
QObject::connect(ui->radio_minable, SIGNAL(clicked()), this, SLOT(traitement_modifie()));
QObject::connect(ui->radio_speciaux, SIGNAL(clicked()), this, SLOT(traitement_modifie()));
QObject::connect(ui->radio_langDef, SIGNAL(clicked()), this, SLOT(liste_modifie()));
QObject::connect(ui->radio_langPerso, SIGNAL(clicked()), this, SLOT(liste_modifie()));
QObject::connect(ui->bouton_selecFichier, SIGNAL(clicked()), this, SLOT(liste_modifie()));
//Raccourci clavier
//new QShortcut(QKeySequence(Qt::Key_Return || Qt::Key_Enter), this, SLOT(on_bouton_generer_clicked()));
//Quitter via le menu
QObject::connect(ui->actionQuitter_3, SIGNAL(triggered()), this, SLOT(quit_troll()));
}
FenetrePrincipale::~FenetrePrincipale()
{
delete ui;
}
FenetrePrincipale::type_Trait FenetrePrincipale::selectedTrait() {
if(ui->radio_ignore->isChecked())
return ascii;
else if(ui->radio_minable->isChecked())
return asciiplus;
else if(ui->radio_speciaux->isChecked())
return utf_8;
else
return aucun;
}
FenetrePrincipale::type_Trait FenetrePrincipale::stringToType(QString stringType) {
if (stringType == "ascii")
return FenetrePrincipale::ascii;
else if (stringType == "asciiplus")
return FenetrePrincipale::asciiplus;
else if (stringType == "utf_8")
return FenetrePrincipale::utf_8;
else
return FenetrePrincipale::aucun;
}
void FenetrePrincipale::on_bouton_analyser_clicked() {
ui->centralwidget->setCursor(Qt::WaitCursor);
ui->onglet_analyse->setEnabled(false);
ui->progr_Analyse->setValue(0); //inutile.
ui->statusbar->setToolTip("");
int avRecup(5), avAnal(90), avProbatab(5); //doit sommer a 100. Avancement (%) de chaque étape
charmap.clear();
//Partie 1 : Récupération de la liste de mots
ui->statusbar->showMessage("Récupération de la liste de mots...");
//Choix liste mot (selon valeur radio)
if (ui->radio_langDef->isChecked()) {
nomListeMots = nomListeMotsDefaut;
}
else if (ui->radio_langPerso->isChecked()) {
QFileInfo fi(nomListeMots);
if (fi.fileName() != ui->bouton_selecFichier->text()) {
ui->statusbar->showMessage("Problème sur le nom de la liste de mot. Veuillez reselectionner un liste de mot");
ui->onglet_analyse->setEnabled(true);
ui->centralwidget->unsetCursor();
return;
}
} //vérification qu'on ne va pas refaire l'analyse par défaut
else { //Trololol inutile
ui->progr_Analyse->setValue(42);
ui->statusbar->showMessage("How did you do that ? En plus maintenant, t'as un pointeur de merde :p");
return; //Si aucun bouton coché : arrêter tout
}
//Importation liste mots
std::vector<std::string> mots;
std::vector<float> proba;
std::ifstream Liste_mots(nomListeMots.toStdString(), std::ios::in);
if(Liste_mots) {
extractWords(Liste_mots, mots, proba);
ui->progr_Analyse->setValue(avRecup);
}
else {
ui->statusbar->showMessage("Impossible de lire la liste de mots (voir ici pour plus de détails)");
ui->statusbar->setToolTip("La liste de mot suivante :\n"+nomListeMots+
"\nn'a pas pu être lue. Vérifiez qu'elle existe bien et est une liste de mots au format .txt, 1 mot par ligne");
ui->onglet_analyse->setEnabled(true);
ui->centralwidget->unsetCursor();
return;
}
ui->tabWidget->setTabIcon(0,QIcon()); //L'icone 'warning' nest retirée que si la première étape marche (pas de return dans les étape 2 et 3
//Partie 2 et 3 : Analyse liste mots / construction des proba
ui->statusbar->showMessage("Analyse de la liste de mots...");
int nb=0; //nombre de lettres traitées
//Partie 2 version A :
if(ui->radio_speciaux->isChecked()) { //Traitement moderne
lcoh = ui->spin_lcoh->value();
for(uint i=0; i<mots.size(); i++) {
QString qmot=QString::fromStdString(mots[i]);
QanalyzeWord(qmot,charmap, lcoh, nb);
if (i%500==0) { //Possibilité : 10000 (haché), 100000 (3 étapes)
ui->progr_Analyse->setValue(avRecup+i/(float)mots.size()*avAnal);
QCoreApplication::processEvents(); //permet l'actualisation du gui. Ralenti les calcul...
}
}
//Partie 3 vA : Création des proba de chaque enchaînement de lettre
ui->statusbar->showMessage("Liste de mots analysée. Analyse de l'analyse en cours...");
std::map<std::vector<QChar>, std::pair<int,double>>::iterator it = charmap.begin() , cePrDebut , cePrFin;
//cePrDebut et cePrFin sont des itérateur indiquant le début et la fin de l'enchaînement de lettre examiné actuellement
while(it!=charmap.end()) {
//pr = sous vecteur de it->first de [0] #FFBF00à [lcoh-2] : contient lcoh-1 éléments
//c'est l'enchainement de lettres précédente --> utilisé pour déterminer la proba de l'actuelle
std::vector<QChar> pr(&it->first[0], &it->first[lcoh-1]);
cePrDebut = it;
int nbtlsuiv = 0; //nb tot de lettre suivant l'enchainement 'pr[0]pr[1]...'
//1er parcours : compter occurence de chaque pr
// /!\ à l'odre des condition du while : il ne faut pas appeler it si it=end() --> vérification end en premier
while( (it!=charmap.end()) && (pr==std::vector<QChar>(&it->first[0], &it->first[lcoh-1])) ) {
//tant que l'enchainement des lettres précédentes (défini dans pr) ne change pas, on additionne le nombre d'occurence
nbtlsuiv += it->second.first; //it->second = la pair / .first -> le 'int'=nb d'occurence
it++; //passage au membre suivant
}
cePrFin = it;
//2e parcours : diviser enchainement/occurence total du pr + additionner (pour proba cumul)
//on repasse sur la partie déjà vue : de cePrDebut à cePrFin
for(std::map<std::vector<QChar>, std::pair<int,double>>::iterator repasse = cePrDebut; repasse!=cePrFin && repasse!=charmap.end(); ++repasse) {
repasse->second.second = (double)repasse->second.first / nbtlsuiv;
if (repasse != cePrDebut && repasse!=charmap.begin() )
repasse->second.second += prev(repasse)->second.second; //prev() = élément précédent
}
}
//Traitement terminé. Indication lié au traitement utf_8
analyse = utf_8;
ui->check_forcerTaille->setEnabled(false);
ui->check_forcerTaille->setToolTip("Un bug très (très) idiot empêche de forcer la taille des mots\n"
"avec la méthode gérant tous les type de caractères\n"
"Oui, désolé, j'ai eu la flemme de corriger ça");
ui->label_resume_analyse->setText("Type d'analyse : tous caractères spéciaux");
ui->label_resume_lcoh->setText("Longueur de cohérence : "+QString::number(lcoh));
}
//Patie 2 version B :
else { //Traitement à l'ancienne (radio Ignore et radio gère très mal
int lettertab[27][27][27] = {{{0}}}; //--> lettertab[2][1][3] = nombre d'occurence de "cab" ("3","1","2")
int nb=0; //nombre total de lettres traités
bool clearAccent = ui->radio_minable->isChecked(); //ascii (false) ou asciiplus (true)
for(unsigned int i=0; i<mots.size(); i++) {
nb += analyzeWord(mots[i], lettertab, clearAccent);
if (i%500==0) { //Possibilité : 10000 (haché), 100000 (3 étapes)
ui->progr_Analyse->setValue(avRecup+i/(float)mots.size()*avAnal);
QCoreApplication::processEvents(); //permet l'actualisation du gui. Ralenti les calculs...
}
}
//Partie 3 vB: Création des proba de chaque enchaînement de lettre
ui->statusbar->showMessage("Liste de mots analysée. Analyse de l'analyse en cours...");
for (uint k=0; k<27; k++) {
for (uint j=0;j<27;j++) {
int nbtlsuiv = 0; //nb tot de lettre suivant l'enchainement 'k-j'
for (uint i=0;i<27;i++) {
nbtlsuiv += lettertab[i][j][k];
}
for (uint i=0;i<27;i++) {
probatab[i][j][k] = (double)lettertab[i][j][k] / nbtlsuiv;
if(i!=0)
probatab[i][j][k] += probatab[i-1][j][k]; //Transformation en proba cumulative
}
}
}
//Traitement terminé. Indication lié au traitement ascii
if (clearAccent) {
ui->label_resume_analyse->setText("Type d'analyse : accents désaccentés");
analyse = asciiplus; }
else {
ui->label_resume_analyse->setText("Type d'analyse : sans accents");
analyse = ascii; }
//Autorise le "forcer_taille"
ui->check_forcerTaille->setEnabled(true);
ui->check_forcerTaille->setToolTip("");
lcoh=0; //pas de lcoh ici. lcoh=0 <=> traitement ascii
ui->label_resume_lcoh->setVisible(false); //cache la valeur lcoh
}
//Traitement terminé. Indications générales
ui->progr_Analyse->setValue(avRecup+avAnal+avProbatab-1);
ui->progr_Analyse->setToolTip("Non, la barre ne va pas à 100%. C'est frustrant, hein ?");
ui->onglet_generation->setEnabled(true);
ui->onglet_analyse->setEnabled(true);
ui->centralwidget->unsetCursor();
//Supprime les warning de changement
traitement_modifie();
on_spin_lcoh_valueChanged(lcoh);
QFile file(nomListeMots); QFileInfo fileinfo(file);
nomListeAnalysePrecedente=fileinfo.fileName(); //récupération du nom de la liste de mots
liste_modifie();
ui->statusbar->showMessage("Analyse terminée ! Prêt a inventer des mots !");
ui->tabWidget->setCurrentIndex(1);
}
void FenetrePrincipale::on_bouton_generer_clicked() {
ui->check_troll->setChecked(false);
if ((analyse==aucun)) {
ui->statusbar->showMessage("Vous devez analyser une liste de mots avant de générer des mots");
return; }
uint taille_max = ui->spin_tailleMax->value();
if(taille_max==0)
taille_max=100;
std::string mot;
for (int i=0; i<ui->spin_nbMots->value(); i++) {
if(analyse==utf_8)
mot = Qgenerateur(charmap,lcoh, ui->check_forcerTaille->isChecked(), taille_max);
if(analyse==ascii || analyse==asciiplus)
mot = generateur(probatab, ui->check_forcerTaille->isChecked(), taille_max);
ui->text_mots->append(QString::fromStdString(mot));
}
}
void FenetrePrincipale::on_bouton_selecFichier_clicked() {
nomListeMots = QFileDialog::getOpenFileName(this, "Selectionner une liste de mot .txt", "WordLists", "Fichier texte (*.txt)");
QFile file(nomListeMots);
QFileInfo fileinfo(file);
liste_modifie();
ui->bouton_selecFichier->setText(fileinfo.fileName());
if(ui->bouton_selecFichier->text()!="")
ui->radio_langPerso->setChecked(true);
else
ui->bouton_selecFichier->setText("(Aucun)");
}
void FenetrePrincipale::on_bouton_details_clicked() {
ui->Bof->setVisible(!ui->Bof->isVisible());
ui->Bof_2->setVisible(!ui->Bof_2->isVisible());
ui->Minable->setVisible(!ui->Minable->isVisible());
ui->Minable_2->setVisible(!ui->Minable_2->isVisible());
ui->Parfait->setVisible(!ui->Parfait->isVisible());
ui->Parfait_2->setVisible(!ui->Parfait_2->isVisible());
ui->Qualite->setVisible(!ui->Qualite->isVisible());
ui->Rapidite->setVisible(!ui->Rapidite->isVisible());
ui->line_details->setVisible(!ui->line_details->isVisible());
}
void FenetrePrincipale::on_bouton_nettoyer_clicked() {
ui->text_mots->clear();
}
void FenetrePrincipale::on_bouton_trier_clicked() {
QString text = ui->text_mots->toPlainText();
triParTaille(text);
ui->text_mots->setText(text);
}
void FenetrePrincipale::on_actionAide_triggered() {
m_FenAide = new FenAide();
m_FenAide->show();
}
void FenetrePrincipale::on_action_propos_de_ce_programme_triggered() {
m_Infos = new Infos();
m_Infos->show();
}
void FenetrePrincipale::on_actionUtiliser_les_valeur_actuelles_par_defaut_triggered() {
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "Changer valeurs par defaut",
"Voulez vous changer les valeurs par défaut du programme ?\n"
"\nLes valeurs par défaut (càd celle au lancement du programme) seront remplacées par les valeurs actuelles\n"
"Sont concernés :\n"
" - La liste de mot\n"
" - La longueur de cohérence\n"
" - Le nombre de mot à générer\n"
" - La taille maximale des mots\n",
QMessageBox::Yes|QMessageBox::No);
//TODO : mieux que ça ! Heuresement qu'il n'y a que 5 paramètres...
if (reply == QMessageBox::Yes) {
//préparation pour écriture du chemin de la liste de mot
QFile file("WordLists/Parametres.xml");
if(file.open(QIODevice::WriteOnly)) {
QXmlStreamWriter xmlWriter(&file);
xmlWriter.writeStartElement("?xml version=\"1.0\" encoding=\"utf-8\"?");
xmlWriter.writeCharacters("\n");
xmlWriter.writeStartElement("valeursDef");
xmlWriter.writeCharacters("\n\t");
xmlWriter.writeStartElement("nomListe");
if(ui->radio_langPerso->isChecked())
xmlWriter.writeCharacters(nomListeMots);
else
xmlWriter.writeCharacters(nomListeMotsDefaut);
xmlWriter.writeEndElement();
xmlWriter.writeCharacters("\n");
xmlWriter.writeComment("Le chemin peut être donné en absolu ou en relatif");
xmlWriter.writeCharacters("\n\t");
xmlWriter.writeStartElement("modeTraitement");
if(ui->radio_ignore->isChecked())
xmlWriter.writeCharacters("ascii");
else if(ui->radio_minable->isChecked())
xmlWriter.writeCharacters("asciiplus");
else if(ui->radio_speciaux->isChecked())
xmlWriter.writeCharacters("utf_8");
else
xmlWriter.writeCharacters("aucun");
xmlWriter.writeEndElement();
xmlWriter.writeCharacters("\n");
xmlWriter.writeComment("Les valeurs possible du mode de traitement sont : aucun, ascii, asciiplus et utf_8");
xmlWriter.writeCharacters("\n\t");
xmlWriter.writeStartElement("lcoh");
xmlWriter.writeCharacters(QString::number(ui->spin_lcoh->value()));
xmlWriter.writeEndElement();
xmlWriter.writeCharacters("\n\t");
xmlWriter.writeStartElement("nbMots");
xmlWriter.writeCharacters(QString::number(ui->spin_nbMots->value()));
xmlWriter.writeEndElement();
xmlWriter.writeCharacters("\n\t");
xmlWriter.writeStartElement("tailleMax");
xmlWriter.writeCharacters(QString::number(ui->spin_tailleMax->value()));
xmlWriter.writeEndElement();
xmlWriter.writeCharacters("\n");
xmlWriter.writeEndElement();
xmlWriter.writeCharacters("\n");
}
else{
ui->statusbar->showMessage("Problème lors de l'écriture des valeurs par défaut");
}
}
}
void FenetrePrincipale::on_check_troll_clicked() {
QTimer::singleShot(80, this, SLOT(unchecking()));
}
void FenetrePrincipale::unchecking() {
std::this_thread::sleep_for(std::chrono::milliseconds(400));
ui->check_troll->setChecked(false);
}
void FenetrePrincipale::quit_troll() {
QMessageBox::information(this, "Vraiment ?",
"Sinon, y avait plus simple pour quitter hein...\n"
"Pourquoi y a toujours un bouton du menu pour quitter ?\n"
"Qui l'utilse ?...");
this->close();
}
void FenetrePrincipale::check_analyse_changed() {
bool changed = listeMots_changed || traitement_changed || lcoh_changed;
if (changed && analyse!=aucun) {
QIcon p(":/icones/icons/warning.png");
ui->tabWidget->setTabIcon(0,p);
ui->statusbar->showMessage("Attention, vous devez refaire l'analyse pour que les changements soient pris en compte");
}
else {
ui->tabWidget->setTabIcon(0,QIcon());
ui->statusbar->showMessage("");
}
}
void FenetrePrincipale::on_spin_lcoh_valueChanged(int value) {
if( (analyse==type_Trait::utf_8) & ((uint)value!=lcoh) ) {
ui->spin_lcoh->setStyleSheet("background-color: #FFBF00");
lcoh_changed = true; }
else {
ui->spin_lcoh->setStyleSheet("");
lcoh_changed = false; }
check_analyse_changed();
}
void FenetrePrincipale::traitement_modifie() {
if(analyse!=aucun) {
if(selectedTrait()!=analyse) {
traitement_changed=true;
if(ui->radio_ignore->isChecked()) {
ui->radio_ignore->setStyleSheet("background-color: #FFBF00");
ui->radio_minable->setStyleSheet("");
ui->radio_speciaux->setStyleSheet(""); }
else if(ui->radio_minable->isChecked()) {
ui->radio_ignore->setStyleSheet("");
ui->radio_minable->setStyleSheet("background-color: #FFBF00");
ui->radio_speciaux->setStyleSheet(""); }
else if(ui->radio_speciaux->isChecked()) {
ui->radio_ignore->setStyleSheet("");
ui->radio_minable->setStyleSheet("");
ui->radio_speciaux->setStyleSheet("background-color: #FFBF00"); }
}
else {
traitement_changed=false;
ui->radio_ignore->setStyleSheet("");
ui->radio_minable->setStyleSheet("");
ui->radio_speciaux->setStyleSheet("");
}
}
check_analyse_changed();
}
void FenetrePrincipale::liste_modifie() {
if(analyse!=aucun) {
bool usedLangDef = (nomListeMots==nomListeMotsDefaut);
if(ui->radio_langPerso->isChecked() && usedLangDef) {
ui->radio_langDef->setStyleSheet("");
ui->radio_langPerso->setStyleSheet("background-color: #FFBF00");
listeMots_changed=true; }
else if (ui->radio_langDef->isChecked() && usedLangDef) {
ui->radio_langDef->setStyleSheet("");
ui->radio_langPerso->setStyleSheet("");
listeMots_changed=false; }
else if(ui->radio_langDef->isChecked() && !usedLangDef) {
ui->radio_langDef->setStyleSheet("background-color: #FFBF00");
ui->radio_langPerso->setStyleSheet("");
listeMots_changed=true; }
else if(ui->bouton_selecFichier->text()!=nomListeAnalysePrecedente&& !usedLangDef) {
ui->radio_langDef->setStyleSheet("");
ui->radio_langPerso->setStyleSheet("background-color: #FFBF00");
listeMots_changed=true; }
else if(ui->radio_langPerso->isChecked() && !usedLangDef ) {
ui->radio_langDef->setStyleSheet("");
ui->radio_langPerso->setStyleSheet("");
listeMots_changed=false; }
else {
ui->radio_langDef->setStyleSheet("");
ui->radio_langPerso->setStyleSheet("");
listeMots_changed=false; }
}
check_analyse_changed();
}
Addition: Default value are stored in an xml file and loaded in FenetrePrincipale constructor. This file path is "wordlist/Parametres.xml" (from executable folder).
<?xml version="1.0" encoding="utf-8"?>
<valeursDef>
<nomListe>wordlist/wordlist.txt</nomListe>
<!--Le chemin peut être donné en absolu ou en relatif-->
<modeTraitement>utf_8</modeTraitement>
<!--Les valeurs possible du mode de traitement sont : aucun, ascii, asciiplus et utf_8-->
<lcoh>3</lcoh>
<nbMots>1</nbMots>
<tailleMax>20</tailleMax>
</valeursDef>
The word analysis/generation in itself is contained in the fonction.h/.cpp files : fonction.h
#ifndef FONCTIONS
#define FONCTIONS
#include <map>
#include <vector>
#include <fstream>
#include <QString>
//Get the words listed in the wordlist (text file)
void extractWords(std::ifstream &liste, std::vector<std::string> &mots, std::vector<float> &proba);
//Remove accentuated letters (for 'analyze word')
std::string retireAccent(std::string &message);
//analyse one word and completes lettertab (of "fenetreprincipale"). ClearAccent=true handles accentuated letter by replacing them by their unaccentuated version
int analyzeWord(std::string &lemot, int lettertab[27][27][27], bool ClearAccent=false);
//analyse on word and completes the charmap (of "fenetreprincipale")
void QanalyzeWord(const QString &lemot, std::map<std::vector<QChar>, std::pair<int,double>> &charmap, uint lcoh, int &nb);
//Generates a word based on the table 'probatab'
std::string generateur(double probatab[27][27][27], bool forcedSize=false, uint maxsize=100);
//Generates a word based on the character map (charmap)
std::string Qgenerateur(std::map<std::vector<QChar>, std::pair<int,double>> &charmap, uint lcoh=3, bool forcedSize=false, uint maxsize=100);
//triParTaille : sort word displayed by size
void triParTaille(QString &liste_mots);
void Qechanger(QStringList &liste, int a, int b);
void Qquicksort(QStringList &liste, int debutR, int fin);
#endif // FONCTIONS
fonction.cpp
#include <vector>
#include <sstream>
#include <iostream>
#include "fonctions.h"
#include "fenetreprincipale.h"
//Fonction commencant par Q = fonction pour le traitement gérant tout les type de
//caratère et la longueur de cohérence (Q pour le Q de QString, le moyen le plus
//simple de gérer l'utf-8 (j'aime pas les wchar_t. C'est nul et pas pratique)
using namespace std;
void extractWords(ifstream &liste, vector<string> &mots, vector<float> &proba) {
int nb_lignes = 0; //number of lines on the wordlist
string line; //last read line
for (; getline(liste,line); nb_lignes++) {}; //Get number of lines
liste.clear();
liste.seekg(0, ios::beg); //going back to beginning of the file
getline(liste, line);
nb_lignes--; //Ignore first line
//TODO : manage comments on the file, e.g. lines beginning by //
mots.resize(nb_lignes);
proba.resize(nb_lignes);
for (int i=0; i<nb_lignes; i++) {
getline(liste, line);
string sproba;
stringstream ss;
ss << line;
ss >> mots[i] >> sproba; // get 1st word = actual word and 2nd word = occurence probability
if(sproba!="")
proba[i]=stof(sproba); //conversion to float
else //if no word probability is indicated, set it at 0
proba[i]=0;
}
liste.close();
return;
}
string retireAccent(string &message)
{
string accent("ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÌÍÎÏìíîïÙÚÛÜùúûüÿÑñÇç");
string sansAccent("AAAAAAaaaaaaOOOOOOooooooEEEEeeeeIIIIiiiiUUUUuuuuyNnCc");
int i=0,j=0,k=0,taille;
taille=message.size();
for (i=0;i<=taille;i++) {
for(j=0;j<=104;j=j+2) {
if((message[i]==accent[j])&&(message[i+1]==accent[j+1])) {
message[i]=sansAccent[j/2];
for(k=i+1;k<taille;k++) {
message[k]=message[k+1];
}
message=message.substr(0,taille-1);
taille=message.size();
}
}
}
return message;
}
int analyzeWord(string &lemot, int lettertab[27][27][27], bool ClearAccent) {
int pr1=0; //previous letter, default is nothing (0)
int pr2=0; //second-to-last letter, default is nothing (0)
int curr; //lettre actuelle
int nb=0; //nombre total de lettre traitées
for(unsigned int i=0; i<lemot.size(); i++) {
if(ClearAccent==true)
lemot=retireAccent(lemot);
curr=lemot.at(i)-96; // returns ascii code for the letter
if(curr>0 && curr <27) { //ignoring accentuated letter
lettertab[curr][pr1][pr2]++;
pr2=pr1;
pr1=curr; //current letter is now previous letter
nb++;
}
}
lettertab[0][pr1][pr2]++; //indicates the word finishes by "...."pr2""pr1"
return nb;
}
void QanalyzeWord(const QString &lemot, map<vector<QChar>, pair<int,double>> &charmap, uint lcoh, int &nb) {
vector<QChar> suiteLettres(lcoh,'\0'); //vecteur de longueur lcoh, initialisé à \0
for(int i=0; i<lemot.size(); i++) {
suiteLettres[lcoh-1]=lemot.at(i); //lcoh = suiteLettres.size()
charmap[suiteLettres].first++;
nb++;
for(uint j=0; j<lcoh-1; j++) {
suiteLettres[j]=suiteLettres[j+1];
}
}
//Indication de dernier charactère=vide
suiteLettres[lcoh-1]='\0';
charmap[suiteLettres].first++;
return;
}
string generateur (double probatab[27][27][27], bool forcedSize, uint maxsize) {
string monmot ="";
int pr1=0; //lettre précédente
int pr2=0; //avant-dernière lettre
int pot; //lettre potentielle
do {
pot=0;
double r = (double)rand() / RAND_MAX;
while (r > probatab[pot][pr1][pr2] && pot<26) {
pot++;
}
if (pot!=0){ //si pot=0 (eg. fin du mot) MAIS forcedSize, alors on ignore ce caractère
monmot += (char)(pot+96);
pr2=pr1;
pr1=pot;
}
} while ((pot!=0 || forcedSize) && monmot.size()<=maxsize); //!\ size=taille en octet=nb carac en ascii seulement
return monmot;
}
string Qgenerateur(std::map<std::vector<QChar>, pair<int,double>> &charmap, uint lcoh, bool forcedSize, uint maxsize) {
QString monmot="";
vector<QChar> cePr(lcoh-1,'\0');
vector<QChar> cePrMin, cePrMax; //debut et fin des élément de la map ayant ce Pr
cePrMin.reserve(lcoh); cePrMax.reserve(lcoh);
map<vector<QChar>, pair<int,double>>::iterator it, itLow, itHigh;
//itLow : itérateur vers le premier éléments de la map ayant ce Pr
//itHigh: itérateur vers l'élément suivant le dernier éléments de la map ayant ce Pr
do {
cePrMin=cePr; cePrMin.push_back(QChar::Null);
cePrMax=cePr; cePrMax.push_back(QChar::LastValidCodePoint);
itLow = charmap.lower_bound(cePrMin);
itHigh = charmap.upper_bound(cePrMax);
it = itLow;
double r = double(rand())/ RAND_MAX; // 0 < r < 1
while (r > it->second.second && it != itHigh) { //places iterator to the 1st caracter having a probability less than r
it++;
}
monmot += QString(it->first.back()); //append this caracter to the word
for(uint i=0; i<cePr.size()-1; i++) {
cePr[i] = cePr[i+1];
}
cePr[cePr.size()-1] = it->first.back();
} while ( (it->first.back()!='\0') && uint(monmot.size()) <= maxsize);
//TODO : implémenter le forced size
return monmot.toStdString();
}
void triParTaille(QString &liste_mots) {
QStringList splitted(liste_mots.split('\n'));
Qquicksort(splitted, 0, splitted.size()-1);
liste_mots = splitted.join("\n");
}
void Qechanger(QStringList &liste, int a, int b) {
//Fonction utilisée par le tri quicksort
QString temp = liste.at(a);
liste.replace(a, liste.at(b));
liste.replace(b,temp);
}
void Qquicksort(QStringList &liste, int debut, int fin) {
int gauche=debut-1;
int droite=fin+1;
const int pivot = liste.at(debut).size();
if(debut>=fin)
return;
while(1) {
do {droite--; } while(liste.at(droite).size() > pivot);
do gauche++; while(liste.at(gauche).size() < pivot);
if(gauche < droite)
Qechanger(liste, gauche, droite);
else break;
}
Qquicksort(liste, debut, droite);
Qquicksort(liste, droite+1, fin);
}
Now only remain an 'help' window and a 'about' window. I don't show the .ui here due to number of caraters limitation : fenaide.h
#ifndef FENAIDE_H
#define FENAIDE_H
#include <QDialog>
namespace Ui {
class FenAide; //=Help window
}
class FenAide : public QDialog
{
Q_OBJECT
public:
explicit FenAide(QWidget *parent = 0);
~FenAide();
public slots:
void on_bouton_moreInfo_clicked();
private:
Ui::FenAide *ui;
};
#endif // FENAIDE_H
fenaide.cpp
#include "fenaide.h"
#include "ui_fenaide.h"
FenAide::FenAide(QWidget *parent) :
QDialog(parent),
ui(new Ui::FenAide)
{
ui->setupUi(this);
ui->text_details->setVisible(false);
this->adjustSize();
#ifdef __linux__
this->setFixedSize(this->width(),this->height());
#elif _WIN32
//Taille de fenetre fixe. Windows seulement
setWindowFlags(Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
#else
#endif
}
FenAide::~FenAide()
{
delete ui;
}
void FenAide::on_bouton_moreInfo_clicked() {
ui->text_details->setVisible(!ui->text_details->isVisible());
this->adjustSize();
}
infos.h
#ifndef INFOS_H
#define INFOS_H
#include <QDialog>
namespace Ui {
class Infos;
}
class Infos : public QDialog
{
Q_OBJECT
public:
explicit Infos(QWidget *parent = 0);
~Infos();
private:
Ui::Infos *ui;
};
#endif // INFOS_H
infos.cpp
#include "infos.h"
#include "ui_infos.h"
Infos::Infos(QWidget *parent) :
QDialog(parent),
ui(new Ui::Infos)
{
ui->setupUi(this);
// Make window fixed size
#ifdef __linux__
this->setFixedSize(this->width(),this->height());
#elif _WIN32
setWindowFlags(Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
#else
#endif
}
Infos::~Infos()
{
delete ui;
}
The .pro file if ever it is usefull
TEMPLATE = app
CONFIG += qt
CONFIG += c++11
QT += widgets
SOURCES += main.cpp \
fonctions.cpp \
fenaide.cpp \
fenetreprincipale.cpp \
infos.cpp
HEADERS += \
fonctions.h \
fenaide.h \
fenetreprincipale.h \
infos.h
DISTFILES +=
FORMS += \
fenaide.ui \
fenetreprincipale.ui \
infos.ui
And finaly, the wordlist. It can be any .txt file like :
//First line is ignored
This
is
a
wordlist
platypus
Edit:
In addition here are screenshots of the application.
On the analyze tab, default behaviour is pre-selected (trhough the xml file), so user just has to click 'launch alaysis' ('lancer l'analyse'). User can select another wordlist using the button (on the top) ; and chooses between analysis type (ascii only characters, ascii + few accentuated letters, or utf-8)
On the generate word tab, user chooses how many words he wants to create, and sets up a limit to a maximum number of characters.