#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#define MAX_ELEMENTS 12
typedef struct {
unsigned short num_elements; // le nb d'éléments contenus dans la table
unsigned short next_unused; // indice pour la prochaine insertion
struct {
bool in_use; // la case est utilisee
char *data; // en general, c'est une structure plus complexe ici
} entry[MAX_ELEMENTS];
} t_fixed_table;
#define MAX_ITEM_SIZE 64
typedef struct {
unsigned short nb_items;
bool zerostart;
char question[MAX_ITEM_SIZE];
struct {
bool (*command)(t_fixed_table *);
bool (*display)(t_fixed_table *);
bool displayed;
char text[MAX_ITEM_SIZE];
} item[];
} t_menu;
static char *cluedo_name[10] = {
"Mademoiselle Rose",
"Colonel Moutarde",
"Madame Leblanc",
"Docteur Olive",
"Madame Pervenche",
"Professeur Violet",
"Mademoiselle Peche",
"Monsieur Prunelle",
"Sergent Legris",
"Madame Chose"
};
/*************************************************************
* Les 4 actions de base proposées par menus *
* On mettra le code après le main, histoire de les séparer *
* des fonctions utilitaires *
*************************************************************/
bool ajouter_element(t_fixed_table *table);
bool supprimer_element(t_fixed_table *table);
bool lister_table(t_fixed_table *table);
bool quitter(t_fixed_table *table);
/* action supplémentaire spéciale christyleblack */
bool toggle_pedagogical(t_fixed_table *table);
/* codage vite fait d'une fonction de lecture et inversion */
bool acces_pedagogical(bool invert) {
static bool pedagogical_mode = false;
if (invert) {
pedagogical_mode = pedagogical_mode?false:true;
}
return pedagogical_mode;
}
bool toggle_pedagogical(t_fixed_table *table) {
acces_pedagogical(true);
return true;
}
/*************************************************************
* Fonctions élémentaires de manipulation de la table *
* - Initialisation de la table *
* - Ajout d'une entrée *
* - Suppression d'une entrée *
* - Listage de la table *
*************************************************************/
void init_table(t_fixed_table *table) {
if (table) {
int i;
table->num_elements = 0;
table->next_unused = 0;
for (i = 0; i < MAX_ELEMENTS; ++i) {
table->entry[i].in_use = false;
table->entry[i].data = NULL;
}
}
}
void add_data(t_fixed_table *table, char *data) {
if (table && (table->next_unused < MAX_ELEMENTS)) {
int i;
// On ajoute le contenu et declare la case utilisée
table->entry[table->next_unused].in_use = true;
table->entry[table->next_unused].data = data;
// on met a jour le nb d'elts
++table->num_elements;
// et l'indice pour la prochaine insertion
++table->next_unused;
for (i = table->next_unused; i < MAX_ELEMENTS; ++i) {
if (table->entry[i].in_use == false) {
break;
}
++table->next_unused;
}
}
}
void delete_data(t_fixed_table *table, unsigned short index) {
if (table && (index < table->num_elements)) {
int i, j;
// on trouve l'indice dans le tableau a partir de celui donné
// par l'utilisateur en sautant les cases inutilisées
j = 0;
for (i = 0; i < MAX_ELEMENTS; ++i) {
if (table->entry[i].in_use == true) {
if (j == index) {
break;
}
j++;
}
}
// on supprime le contenu et declare la case inutilisée
table->entry[i].in_use = false;
table->entry[i].data = NULL;
// on met a jour le nb d'elts
--table->num_elements;
// et si necessaire l'indice pour la prochaine insertion
if (table->next_unused > i) {
table->next_unused = i;
}
}
}
void print_table_state(t_fixed_table *table, bool pedagogical) {
if (table) {
int i, j;
/* impression avec toute la table */
if (pedagogical) {
j = 1;
printf("--------------------------------------\n" );
printf("| case | numero | nom |\n" );
printf("--------------------------------------\n" );
for (i = 0; i < MAX_ELEMENTS; ++i) {
if (table->entry[i].in_use == true) {
printf(" %-18s |\n", table->entry
[i
].
data);
j++;
}
else {
}
}
printf("--------------------------------------\n" );
}
/* impression de la partie utilisée de la table */
else {
j = 1;
printf("-------------------------------\n" );
printf("| numero | nom |\n" );
printf("-------------------------------\n" );
for (i = 0; i < MAX_ELEMENTS; ++i) {
if (table->entry[i].in_use == true) {
printf(" %-18s |\n", table->entry
[i
].
data);
j++;
}
}
printf("-------------------------------\n" );
}
}
}
/*************************************************************
* Fonctions renseignant les menus de l'état de la table *
*************************************************************/
bool table_not_full(t_fixed_table *table) {
return (table && (table->num_elements < MAX_ELEMENTS))?true:false;
}
bool table_not_empty(t_fixed_table *table) {
return (table && (table->num_elements > 0))?true:false;
}
bool table_exists(t_fixed_table *table) {
return (table)?true:false;
}
bool always_true(t_fixed_table *table) {
return true;
}
/* vidage de buffer classique */
void clean_stdin() {
int c;
do {
c = getchar();
} while (c != '\n' && c != EOF);
}
/*************************************************************
* Fonctions de gestion des menus *
*************************************************************/
void items_enable(t_menu *menu, t_fixed_table *table) {
int i;
for (i = 0; i < menu->nb_items; ++i) {
menu->item[i].displayed = (*menu->item[i].display)(table);
}
}
int affiche_menu(t_menu *menu) {
int i;
int displayed = menu->zerostart?0:1;
for (i = 0; i < menu->nb_items; ++i) {
if (menu->item[i].displayed) {
printf("%d - %s\n", displayed++, menu->item
[i
].
text);
}
}
return menu->zerostart?displayed:displayed-1;
}
#define MAX_MENU_ERRORS 5
bool (*choix_menu(t_menu *menu))(t_fixed_table *) {
unsigned short saisie = 0;
unsigned short nb_errors = 0;
int min_item = 1;
int nb_items, retcode, i, j;
nb_items = affiche_menu(menu);
if (menu->zerostart) {
--nb_items;
--min_item;
}
do {
retcode = scanf("%d", &saisie);
clean_stdin();
if ((retcode == 1) && (min_item <= saisie) && (saisie <= nb_items)) {
j = menu->zerostart?0:1;
for (i = 0; i < menu->nb_items; ++i) {
if (menu->item[i].displayed) {
if (j == saisie) {
break;
}
++j;
}
}
return menu->item[i].command;
}
else {
++nb_errors;
if (nb_errors >= MAX_MENU_ERRORS) {
return &quitter;
}
else {
printf("\nErreur! reponse incorrecte, recommencez.\n" );
}
}
} while(true);
}
/*************************************************************
* recuperation d'un entier entre par l'utilisateur *
* avec controle de la validité *
*************************************************************/
#define MAX_SAISIE_ERRORS 5
bool get_user_num(t_fixed_table *table, int *num) {
int saisie, retcode;
int nb_errors = 0;
do {
printf("Donnez le numero de l'élément à supprimer [1-%d]: ", table->num_elements
);
retcode = scanf("%d", &saisie);
clean_stdin();
if (retcode == 1) {
if (saisie < 1) {
printf("Valeur trop petite! valeur minimale: 1 " );
}
else if (saisie > table->num_elements) {
printf("Valeur trop grande! valeur maximale: %d", table->num_elements
);
}
else {
*num = saisie;
return true;
}
}
else {
printf("Valeur saisie incorrecte! " );
}
++nb_errors;
if (nb_errors >= MAX_SAISIE_ERRORS ) {
return false;
}
else {
}
} while(true);
}
/* ------------------------------------------------------------------------ */
int main() {
t_fixed_table mytable;
static t_menu mymenu = {
5,
false,
"Entrer votre choix : ",
{ {&ajouter_element, &table_not_full, true, "Ajouter un element"},
{&supprimer_element, &table_not_empty, true, "Supprimer un element"},
{&lister_table, &table_exists, true, "Lister les elements"},
{&toggle_pedagogical, &always_true, true, "Changer de mode (normal/pedagogique)"},
{&quitter, &always_true, true, "Quitter"},
}
};
init_table(&mytable);
do {
items_enable(&mymenu, &mytable);
} while((*choix_menu(&mymenu))(&mytable));
return 0;
}
/*************************************************************
* les 4 actions associées aux menus *
* elles font appel aux fonctions basiques de manipulation *
* de la table, avec les parametres ad-hoc *
* en sortie, false fait sortir de la boucle du main *
**************************************************************/
bool ajouter_element(t_fixed_table *table) {
add_data(table, cluedo_name[rand() % 10]);
return true;
}
bool supprimer_element(t_fixed_table *table) {
int numero;
print_table_state(table, false); // pour choisir le numero
if (get_user_num(table, &numero)) {
delete_data(table, numero-1);
}
return true;
}
bool lister_table(t_fixed_table *table) {
print_table_state(table, acces_pedagogical(false));
return true;
}
bool quitter(t_fixed_table *table) {
return false;
}