/* ______________________
	declarations
______________________	*/

/* ______________________
	structure de donnee	*/

/* ____ donnees statiques (valeurs constantes) */

#define TAILLE_COMBI 4
#define NOMBRE_ESSAI 10
#define NOMBRE_COULEUR 8

/* codes couleur :
	- 8 codes pour les couleurs : rouge, bleu, vert, mauve, orange, jaune, blanc, noir
	- 1 code pour indiquer que la couleur est indéterminée (variable de type couleur, dont valeur couleur n'est pas encore ou n'est plus determinee)
*/
enum e_couleur
{
	COULEUR_NONE=0,
	COULEUR_ROUGE,
	COULEUR_BLEU,
	COULEUR_VERT,
	COULEUR_MAUVE,
	COULEUR_ORANGE,
	COULEUR_JAUNE,
	COULEUR_BLANC,
	COULEUR_NOIR
};

/* etat d'une partie, pour un jeu quelconque a un joueur
	- 3 codes pour les etats : en cours, gagnee, perdue
	- 1 code pour indiquer que l'etat de la partie n'est pas determine (quand une partie n'est pas lancee)
*/
enum e_etat_partie
{
	ETAT_PARTIE_NONE=0,
	ETAT_PARTIE_ENCOURS,
	ETAT_PARTIE_GAGNEE,
	ETAT_PARTIE_PERDUE
};

/* ____ donnees dynamiques (dont la valeur est variable) */

/* combinaison : liste de TAILLE_COMBI couleurs ordonnées */
struct s_combinaison
{
	enum e_couleur liste_couleur[TAILLE_COMBI];
};

/* essai :
	- 1 combinaison
	- 1 nombre de couleurs correctes, et correctement placees
	- 1 nombre de couleurs correctes
*/
struct s_essai
{
	struct s_combinaison code;
	int nb_ok_place;
	int nb_ok;
};

/* mastermind :
	- 1 etat de la partie
	- 1 nombre d'essais tentes
*/
struct s_mastermind
{
	enum e_etat_partie etat;						/* ETAT_PARTIE_NONE ou départ */
	int nb_coups_joues;						        /* 0 au départ */
	struct s_combinaison combi_secrete;		        /* (COULEUR_NONE,COULEUR_NONE,COULEUR_NONE,COULEUR_NONE) au départ */
	struct s_essai liste_essai[NOMBRE_ESSAI];	    /* (COULEUR_NONE,COULEUR_NONE,COULEUR_NONE,COULEUR_NONE,-1,-1) pour chaque essai au départ */
};

/* ______________________
	alias de type	*/

/* couleur */
typedef enum e_couleur couleur ;

/* etat partie */
typedef enum e_etat_partie etat_partie;

/* combinaison */
typedef struct s_combinaison combinaison ;

/* essai */
typedef struct s_essai essai ;

/* mastermind */
typedef struct s_mastermind mastermind ;

/* ______________________
	fonctions de manipulation :: accesseurs en lecture	*/

/* ___ combinaison */

/* renvoie la couleur de l'element d'indice "indice" de la combinaison "une_combi"
    Pré-condition : 0 <= indice < TAILLE_COMBI */
couleur combinaison_get_couleur(combinaison une_combi, int indice);

/* ___ essai */

/* renvoie la couleur de l'element d'indice "indice" de la combinaison de l'essai "un_essai"
    Pré-condition : 0 <= indice < TAILLE_COMBI */
couleur essai_get_couleur(essai un_essai, int indice);

/* renvoie le nombre de couleurs bien placees de l'essai "un_essai" */
int essai_get_nb_ok_place(essai un_essai);

/* renvoie le nombre de couleurs correctes de l'essai "un_essai" */
int essai_get_nb_ok(essai un_essai);

/* ___ mastermind */

/* renvoie l'etat de la partie de mastermind "mm"  */
etat_partie mastermind_get_etat(mastermind mm);

/* renvoie le nombre de coups joues de la partie de mastermind "mm"  */
int mastermind_get_nb_coups_joues(mastermind mm);

/* renvoie 1 si la partie est gagnee, 0 sinon  */
int mastermind_is_partie_gagnee(mastermind mm);

/* renvoie 1 si la partie est perdue, 0 sinon  */
int mastermind_is_partie_perdue(mastermind mm);

/* ______________________
	fonctions de manipulation :: accesseurs en ecriture	*/

/* ___ combinaison */

/* initialise les valeurs d'une combinaison : toutes les couleurs sont indefinies (valeur "COULEUR_NONE")  */
combinaison combinaison_set_default(combinaison une_combi);

/* copie la combinaison "combi_source" dans la combinaison "combi_cible" */
combinaison combinaison_set_copie(combinaison combi_cible, combinaison combi_source);

/* attribue aleatoirement les couleurs d'une combinaison
    Pré-condition : la graine aleatoire est initialisee */
combinaison combinaison_set_random(combinaison une_combi);

/* ___ essai */

/* initialise les valeurs d'un essai :
    - la combinaison est initialisee
    - les nombres de couleurs correct sont mis a "-1"  */
essai essai_set_default(essai un_essai);

/* affecte la combinaison "une_combi" a l'essai "un_essai" */
essai essai_set_code(essai un_essai, combinaison une_combi);

/* affecte les nombres de couleurs correctes a l'essai "un_essai" */
essai essai_set_nb(essai un_essai, int nb_ok_place, int nb_ok);

/* ____ mastermind */

/* initialise une partie de mastermind "mm"
    Pré-condition : la graine aleatoire est initialisee
    Post-conditions :
        - une nouvelle combinaison secrete de la partie de mastermind "mm" est definie (aleatoirement)
        - la partie de mastermind "mm" est dans l'etat "ETAT_PARTIE_ENCOURS"
        - le nombre de coups joues est 0
        - les essais sont tous reinitialises
*/
mastermind mastermind_set_random(mastermind mm);

/* affecte la combinaison "une_combi" a l'essai en cours de la partie de mastermind "mm"
    Post-conditions :
        - le nombre de coups joues est incremente
        - les nombres de couleurs correctes, et correctes et correctement placees sont mis a jour
        - si la combinaison est gagnante, l'etat de la partie "mm" est "ETAT_PARTIE_GAGNE"
        - si la combinaison est perdante et que le nombre de coups joues atteint "NOMBRE_ESSAI", l'etat de la partie "mm" est "ETAT_PARTIE_PERDU"
*/
mastermind mastermind_set_essai(mastermind mm, combinaison une_combi);

/* ______________________
	entrées/sorties */

/* ____ affichage console */

/* __ combinaison */
void combinaison_afficher(combinaison une_combi);

/* __ essai */
void essai_afficher(essai un_essai);

/* __ mastermind */
void mastermind_afficher_essai(mastermind mm);
void mastermind_afficher_combi_secrete(mastermind mm);
void mastermind_afficher_partie(mastermind mm);

/* ____ saisie console */

/* __ combinaison */
combinaison combinaison_set_par_saisie(combinaison combi_saisie);

/* __ mastermind */
mastermind mastermind_set_essai_par_saisie(mastermind mm);

/* ______________________
	definitions
______________________	*/

#include<stdio.h>   /* pour les fonctions d'entrée /sortie */
#include<stdlib.h>  /* pour la fonction rand() */

/* ______________________
	fonctions de manipulation :: accesseurs en lecture	*/

/* ______________________
	fonctions de manipulation :: accesseurs en ecriture	*/

/* ______________________
	entrées/sorties */

/* ____ affichage console */

/* ____ saisie clavier */

/* ______________________
	programmes
______________________	*/

#include<stdlib.h> /* pour la constante EXIT_SUCCESS */

/* ______________________
	programme jeu   */

/* ____ fonction de jeu (saisie clavier sortie console) */
void mastermind_jouer();

/* ____ fonction de jeu (saisie clavier sortie console) */
void mastermind_jouer()
{
    mastermind mm;
	int do_jouer = 1;
	char c;

	while (do_jouer)
	{
		/* initialisation de la partie */
		mm = mastermind_set_random(mm);

		/* deroulement de la partie */
		while(! (mastermind_is_partie_gagnee(mm) || mastermind_is_partie_perdue(mm)))
		{
		    /* saisie essai par le joueur */
			mm = mastermind_set_essai_par_saisie(mm);

		    /* affichage de l'essai joue */
			mastermind_afficher_essai(mm);
		}

        /* affichage partie */
        if (mastermind_is_partie_gagnee(mm))
            printf("Bravo, vous avez remporte la partie !\n");
        else
        {
            printf("La partie est perdue. Affichage de la partie :\n");
            mastermind_afficher_partie(mm);
        }

        /* invitation a poursuivre */
        printf("... appuyer sur une touche pour continuer, s/S pour arreter\n");
        c = getchar();
        if (c == 's' || c == 'S')
            do_jouer = 0;
	}
}

/* PROGRAMME :: 1 pour test structure, 2 pour jeu   */
#define PROGRAMME 2
int main()
{
    if (PROGRAMME == 1)
        mastermind_test_all();
    else
        mastermind_jouer();
	return EXIT_SUCCESS;
}


