online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code    Language
#include "main.h" // D'où s'exécute tout le jeu // L'origine de tout int main(void) { afficher_logo(); // On affiche le (magnifique) logo sleep(3); // On met en pose le programme 3 secondes // Initialisation de l'interface graphique (mode texte avancé NCurses) initialiser_ncurses(); int numero_niveau; // On déclare la variable ici au lieu de la placer dans un case du switch pour éviter les erreurs int state = STATE_MAINMENU; // Contient l'état actuel de la navigation while (state != STATE_QUIT) { // tant que l'état n'est pas "quitter" switch(state) { case STATE_MAINMENU: switch (afficher_menu_principal()) { case MAINMENU_PLAY:; // Si l'option choisie est "Jouer" numero_niveau = choix_du_niveau(); // On demande le niveau que le joueur souhaite jouer jouer_niveau(numero_niveau); // On met le niveau en route correspondant à "numero_niveau" break; case MAINMENU_RULES:; // Si l'option choisie est "Règles" afficher_regles(); // On affiche les règles break; case MAINMENU_CONTROLS:; // Si l'option choisie est "Controles" afficher_controles(); // On affche les controles break; case MAINMENU_CREDITS:; // Si l'option choisie est "Credits" afficher_credits(); // On affiche les credits break; case MAINMENU_SCOREBOARD:; // Si l'option choisie est "Leaderboards" numero_niveau = choix_du_niveau(); // On demande le niveau dont le joueur souhaite voir les scores afficher_liste_niveau_scoreboard(numero_niveau); // On affiche un tableau de score du niveau correspondant à "numero_niveau" break; case MAINMENU_QUIT:; // Si l'option choisie est "Quitter" if (afficher_menu_quitter() == 1) { // Si l'utilisateur sélectionne "Oui" // On met l'état sur "quitter" // Ce qui fait sortir de la boucle principale et quitte le programme state = STATE_QUIT; } break; } break; } } fermer_ncurses(); // Fermer toutes les fenêtres NCurses et revenir au mode texte simple system("clear"); // Permet d'enlever le logo, sans ça, il reste et c'est moche ¯\_(ツ)_/¯. return 0; }
#include "main.h" // Démarrer le mode graphique de Ncurses void initialiser_ncurses(void) { initscr(); // Initialisation de l'écran standard de Ncurses (stdscr) noecho(); // Ne pas écrire ce que l'utilisateur tape dans la saisie curs_set(false); // Cacher le curseur // Si le terminal ne supporte pâs les couleurs, on termine l'initialisation if (!has_colors()) { return; } else { // Sinon, on déclare les couleurs du mode graphique // Activation du mode couleur de ncurses start_color(); // Déclaration des palettes de couleur initialiser_couleur(COLOR_RED); // Création de la couleur "rouge" initialiser_couleur(COLOR_GREEN); // Création de la couleur "vert" initialiser_couleur(COLOR_YELLOW); // Création de la couleur "jaune" initialiser_couleur(COLOR_BLUE); // Création de la couleur "bleu" initialiser_couleur(COLOR_MAGENTA); // Création de la couleur "magenta" initialiser_couleur(COLOR_CYAN); // Création de la couleur "cyan" initialiser_couleur(COLOR_WHITE); // Création de la couleur "blanc" } } // Désinitialisation de Ncurses void fermer_ncurses(void) { endwin(); // Fermer toutes les fenêtres de ncurses actuellement ouvertes et quitter le mode "graphique" } // Initialisations des couleurs (pour Ncurses) void initialiser_couleur(int couleur) { // La librairie ncurses gère les couleurs d'une façon particulière: // On doit déclarer une paire de couleurs de fond de texte avec un numéro de paire qui constituent une "palette" // Exemple: paire 1 = rouge en fond et blanc en couleur de texte. // Ici, on utilise un petit raccourci: Vu que les valeurs des couleurs de base du terminal vont de 0 à 7, on peut initialiser une paire avec ce même numéro // Exemple: // Paire #1: // Couleur de texte: 1 (ROUGE) // Couleur de fond: Noir init_pair(couleur, couleur, COLOR_BLACK); } // Calcule le centre d'une zone rectangulaire // Cette zone rectangulaire est définie comme suit : /* gauche (axe X) v haut > +-----------------+ ^ (axe Y) | | | | | | | X | | hauteur (axe Y) | x;y (centre) | | | | | +-----------------+ V <----------------> largeur (axe X) Les pointeurs x et y sont les valeurs de "retour" de la fonction */ void calculer_centre(int hauteur, int largeur, int haut, int gauche, int* y, int* x) { *y = haut + (hauteur / 2); // Attribution de la hauteur dans y *x = gauche + (largeur / 2); // Attribution de la largeur dans x } // Centre une fenêtre dans une zone rectangulaire définie par les valeurs haut, gauche, hauteur et largeur // La fenêtre aura la taille spécifiée par hauteur_cible et largeur_cible // (voir explications de calculer_centre pour plus d'informations) void centrer_fenetre(WINDOW* fenetre, int hauteur_cible, int largeur_cible, int hauteur, int largeur, int haut, int gauche) { //Initialisation des variabes "coordonnées" int y, x; calculer_centre(hauteur, largeur, haut, gauche, &y, &x); // calcule le centre de la fenêtre wresize(fenetre, hauteur_cible, largeur_cible); //Change la taille de la fenêtre mvwin(fenetre, y - (hauteur_cible / 2), x - (largeur_cible / 2)); //Change la position de la fenêtre } // Créer une nouvelle fenêtre de taille 0 WINDOW* nouvelle_fenetre(void) { WINDOW* fenetre = newwin(0, 0, 0, 0); // Nouvelle fenêtre de taille et position 0 keypad(fenetre, true); // Ne pas attendre l'appui sur entrer pour recevoir la saisie return fenetre; //renvoi fenetre } // Efface l'écran et l'actualise void effacer_ecran(void) { erase(); //Efface l'écran refresh(); //Actualise l'écran }
#include "main.h" // Déplace le joueur (si possible) dans la direction indiquée void deplacement (niveau_t* n, char direction){ // Pointeurs vers 1/2 case(s) en avant avant de se déplacer point_t *un_en_avant, *deux_en_avant; // On copie le niveau afin de ne pas modifier l'état précédent (par même référence mémoire) niveau_t* niveau = copier_niveau(n); // On calcule les coordonnées des cases un pas et deux pas en avant (en fonction de la direction) switch (direction){ case DIR_UP: // Direction choisie : HAUT un_en_avant = nouveau_point(niveau->perso->colonne + 0, niveau->perso->ligne - 1); deux_en_avant = nouveau_point(niveau->perso->colonne + 0, niveau->perso->ligne - 2); break; case DIR_DOWN: // Direction choisie : BAS un_en_avant = nouveau_point(niveau->perso->colonne + 0, niveau->perso->ligne + 1); deux_en_avant = nouveau_point(niveau->perso->colonne + 0, niveau->perso->ligne + 2); break; case DIR_LEFT: // Direction choisie : GAUCHE un_en_avant = nouveau_point(niveau->perso->colonne - 1, niveau->perso->ligne + 0); deux_en_avant = nouveau_point(niveau->perso->colonne - 2, niveau->perso->ligne + 0); break; case DIR_RIGHT: // Direction choisie : DROITE un_en_avant = nouveau_point(niveau->perso->colonne + 1, niveau->perso->ligne + 0); deux_en_avant = nouveau_point(niveau->perso->colonne + 2, niveau->perso->ligne + 0); break; default: // Direction invalide return; } // Si il y a une caisse devant nous, et que la case d'après est libre, on pousse la caisse if (caisse_sur_terrain(niveau, un_en_avant->colonne, un_en_avant->ligne) && case_libre_sur_terrain(niveau, deux_en_avant->colonne, deux_en_avant->ligne)){ // On remplace la case en face par une case libre du bon type (cible/vide) switch(lecture_du_terrain_par_coordonnees(niveau, un_en_avant)){ // Si la case en face est une caisse sur une cible case TILE_CRATE_ON_TARGET: //On remplace par une cible place_sur_terrain_par_coordonnees(niveau, un_en_avant, TILE_TARGET); break; // Si la case en face est une caisse simple case TILE_CRATE: //On remplace par le néant le plus total place_sur_terrain_par_coordonnees(niveau, un_en_avant, TILE_EMPTY); break; } // On remplace la case un cran plus loin (que la case en face) par une case du bon type (caisse/caisse sur cible) switch(lecture_du_terrain_par_coordonnees(niveau, deux_en_avant)){ // Si la case deux pas en avant est vide case TILE_EMPTY: //On place une caisse place_sur_terrain_par_coordonnees(niveau, deux_en_avant, TILE_CRATE); break; // Si la case deux pas en avant est une cible case TILE_TARGET: //On remplace par une caisse sur une cible place_sur_terrain_par_coordonnees(niveau, deux_en_avant, TILE_CRATE_ON_TARGET); break; } } // Si la case d'en face est libre if (case_libre_sur_terrain(niveau, un_en_avant->colonne, un_en_avant->ligne)) { // On "déplace" le personnage niveau->perso->colonne = un_en_avant->colonne; niveau->perso->ligne = un_en_avant->ligne; //On ajoute un niveau dans "etats_niveaux" ajouter_niveau(etats_niveaux, niveau); } else { //On libère la mémoire alouée par le niveau liberation_du_niveau(niveau); } //On libère la mémoire alouée par "un_en_avant" free(un_en_avant); //On libère la mémoire alouée par "deux_en_avant" free(deux_en_avant); } // Annule le dernier déplacement void annuler_deplacement(void) { //Si le joueur a effectuer au moins une action, reviens à la dernière position if (etats_niveaux->taille > 1) enlever_dernier_niveau (etats_niveaux); }
#include "main.h" // Permet de lancer un niveau, grâce a un numéro. // Gère la totalité du jeu, en passant par son lancemant, son déroulement, sa fin (déchargement des niveaux) void jouer_niveau(int numero_niveau) { int meilleur_score = lecture_du_score(numero_niveau); DEBUT_JEU:; // Attribution d'une nouvelle liste de niveaux (liste de taille 10) etats_niveaux = nouvelle_liste_niveaux (10); // Initialisation de niveau // Attribution de la lecture de niveau sur le numéro de niveau choisi précdemment niveau_t* niveau = lecture_du_niveau(numero_niveau); if (!niveau) return; //Si le niveau n'existe pas, on quitte la fonction (pas de jeu) // Initialisation de "scores" // Attribution de la lecture de la liste des scores liste_score_t* scores = lire_liste_scores(numero_niveau); // Si il existe pas déjà un tableau de score if (scores == NULL) { //Création d'un tableau de score pour le niveau scores = nouvelle_liste_scores(); } // Ajout d'un niveau ajouter_niveau (etats_niveaux, niveau); int saisie = 0; // On vérifie le niveua est terminé (si toutes les cases à remplir sont remplies) while (nombre_de_caisse_restante_sur_terrain(haut_de_liste(etats_niveaux)) > 0) { niveau = haut_de_liste(etats_niveaux); saisie = affichage_niveau_ncurses(niveau, numero_niveau); //On analyse la touche saisie par le joueur switch (saisie) { case LEAVE: if (afficher_menu_quitter() == 1) { // Permet d'afficher un menu de confirmation avant de quitter goto FIN_JEU; // Si on entre dans le if, on est redirigé à la fin de la boucle. et on apparait au menu principale } break; case RESTART: if (afficher_menu_recommencer() == 1){ // Permet d'afficher un menu de confirmation avant de recommencer while (etats_niveaux->taille > 0) { // Permet libérer la totalité du tableau de niveau. enlever_dernier_niveau(etats_niveaux); } goto DEBUT_JEU; } break; case HELP: afficher_controles(); break; case CANCEL: annuler_deplacement(); break; default: deplacement(niveau, saisie); break; } } int nb_pas = etats_niveaux->taille - 1; //On vérifie si le score du joueur est //meilleur que le meilleur score actuel if (nb_pas < meilleur_score || meilleur_score < 0) { ecriture_du_score(numero_niveau, nb_pas); } //On vérifie si le score du joueur possède sa place dans le tableau des meilleurs scores if (inserable_dans_liste(scores, nb_pas)) { // Message char message[100]; // Message de meilleur score, il n'est pas affiché si il n'y avait aucun meilleur score auparavant // Le message s'affiche si 2 joueurs font un score égaux if(meilleur_score >= nb_pas){ sprintf(message, "Vous avez terminé le niveau %i !!\nEt en seulement %d coups !!\nFélicitations !!", numero_niveau, nb_pas); menu_message("NOUVEAU MEILLEUR SCORE !!", message, 40, 3, COLOR_RED, COLOR_YELLOW); }else{ // Message de félicitation, quand un joueur a sa place dans le tableau des scores, mais pas à la première place. sprintf(message, "Bravo, vous avez termine le niveau %i!\nEt en seulement %d coups !!", numero_niveau, nb_pas); menu_message("Niveau fini", message, 40, 2, COLOR_GREEN, COLOR_YELLOW); } // On demande le nom du joueur, et on le place dans le tableau des scores inserer_score_dans_liste(scores, nb_pas, nom_du_joueur()); enregistrer_liste_scores(scores, numero_niveau); // Et on affiche le scoreboard après qu'il ai valider son nom afficher_liste_niveau_scoreboard(numero_niveau); } else { // Message s'affichant quand le joueur n'as pas sa place dans le tableau des scores char message[100]; sprintf(message, "Bravo, vous avez termine le niveau %i!\nMais en trop de coups ...", numero_niveau); menu_message("Niveau fini", message, 40, 2, COLOR_GREEN, COLOR_WHITE); } FIN_JEU:; //On libère la mémoire que prend les scores liberer_liste_scores(scores); //Tant qu'on est pas de retour au premier état du terrain //(où le joueur n'a pas encore effectuer de coup) while (etats_niveaux->taille > 0) { enlever_dernier_niveau(etats_niveaux); //Enlève le dernier niveau au tableau } }
#include "main.h" // On utilise un tableau dynamique de niveau_t* pour stocker les // etats du jeu au fur et a mesure que le joueur avance. Ainsi, // etats_niveaux->memoire[0] est l'etat initial du jeu, et // etats_niveaux->memoire[etats_niveaux->taille - 1] est l'etat courant. // A chaque deplacement reussi, on ajoute une entree a la liste. // A chaque annulation, on enleve le dernier element de la liste si il y en a plus qu'un. liste_niveaux_t* etats_niveaux; // Permet de créer une nouvelle liste de niveau, permettant par la suite d'utiliser le retour arrière liste_niveaux_t* nouvelle_liste_niveaux(int taille) { liste_niveaux_t *resultat = malloc(sizeof(liste_niveaux_t)); init_liste_niveaux (resultat, taille); //initialise la l return resultat; } // Permet d'initialiser les instances d'une liste de niveau, en fonction de la taille donnée void init_liste_niveaux(liste_niveaux_t* liste, int taille) { liste->memoire = malloc (sizeof (niveau_t *) * taille); liste->taille = 0; liste->taille_memoire = taille; } // Permet de libérer la totalité des niveaux void liberation_de_la_liste_niveaux(liste_niveaux_t* liste) { free(liste->memoire); liste->memoire = NULL; liste->taille = 0; liste->taille_memoire = 0; } // Permet d'agrandir la liste de niveau pour lui permettre d'accueillir un nouveau niveau (semblable à un tableau dynamique) void agrandir_liste_de_niveaux(liste_niveaux_t *liste, int ajout) { if (ajout > 0) { niveau_t** nouveau = malloc(sizeof(niveau_t*) * (liste->taille_memoire + ajout)); memcpy(nouveau, liste->memoire, sizeof(niveau_t*) * liste->taille); free(liste->memoire); liste->memoire = nouveau; liste->taille_memoire += ajout; } } // Permet d'ajouter un niveau à une liste de niveau passer en paramètre void ajouter_niveau(liste_niveaux_t *liste, niveau_t* niveau) { if (liste->taille == liste->taille_memoire) { agrandir_liste_de_niveaux (liste, 10); } liste->memoire[liste->taille] = niveau; niveau->indice = liste->taille; liste->taille += 1; } // Permet de retirer le dernier niveau de la liste passée en paramètre (après une annulation de déplacement) void enlever_dernier_niveau(liste_niveaux_t *liste) { if (liste->taille > 0) { liberation_du_niveau (haut_de_liste(etats_niveaux)); liste->taille -= 1; } } // Permet de renvoyer le dernier élément de la liste, si la liste ne contient rien, cela renvoit NULL niveau_t* haut_de_liste(liste_niveaux_t* liste) { if (liste->taille == 0) return NULL; return liste->memoire[liste->taille - 1]; }
#include "main.h" // Permet de créer un nouveau score score_t* nouveau_score(void) { return malloc(sizeof(score_t)); } // Permet d'affecter les valeurs passées en paramètres à une instance de score_t déjà allouée void initialiser_score(score_t* score, int points, char* nom) { score->score = points; memset(score->nom, '\0', 10); strncpy(score->nom, nom, 9); } // Permet de libérer la mémoire d'une instance score_t void liberer_score(score_t* score) { free(score); } // Permet de créer une nouvelle liste de scores liste_score_t* nouvelle_liste_scores(void) { liste_score_t* scores = malloc(sizeof(liste_score_t)); scores->memoire = malloc(SCORE_BUFFER_SIZE * sizeof(score_t*)); for (int i = 0; i < SCORE_BUFFER_SIZE; ++i) { scores->memoire[i] = nouveau_score(); initialiser_score(scores->memoire[i], 0, ""); } scores->taille = 0; return scores; } // Permet de libérer la mémoire de la liste de score void liberer_liste_scores (liste_score_t* scores) { for (int i = 0; i < SCORE_BUFFER_SIZE; ++i) { liberer_score(scores->memoire[i]); } free(scores->memoire); free(scores); } // Permet de lire la liste scores du niveau correspondant à "numero_niveau" liste_score_t* lire_liste_scores (int numero_niveau) { char chemin_du_fichier[100]; sprintf(chemin_du_fichier, "./niveau/score_multi_%d", numero_niveau); FILE* fichier = fopen(chemin_du_fichier, "r"); if (!fichier) return NULL; liste_score_t* liste_score = nouvelle_liste_scores(); int nombre_scores; fscanf(fichier, "%d", &nombre_scores); liste_score->taille = min(nombre_scores, SCORE_BUFFER_SIZE); for (int numero_score = 0; numero_score < nombre_scores; numero_score++) { fscanf(fichier, "%d %s", &(liste_score->memoire[numero_score]->score), liste_score->memoire[numero_score]->nom); } return liste_score; } // Permet d'enregistrer une liste de scores dans un fichier niveau/score_multi_<nb> // Où nb est numero_niveau void enregistrer_liste_scores (liste_score_t* scores, int numero_niveau) { char nom_fichier[100]; sprintf(nom_fichier, "./niveau/score_multi_%d", numero_niveau); FILE* fichier = fopen(nom_fichier, "w"); if (!fichier) return; score_t* score; fprintf(fichier, "%d\n", scores->taille); for (int i = 0; i < scores->taille; ++i) { score = scores->memoire[i]; fprintf(fichier, "%d %s\n", score->score, score->nom); } fclose(fichier); } // Retourne une vrai si // le nombre de points passé en paramètre est un nouveau high score dans la liste // ou si il reste au moins un emplacement libre dans la liste bool inserable_dans_liste (liste_score_t* scores, int points) { return scores->taille == 0 || points < scores->memoire[scores->taille - 1]->score || scores->taille < SCORE_BUFFER_SIZE; } // Permet d'insèrer le score défini par points/nom dans la liste scores // L'insertion n'a lieu que si le score est meilleur que le dernier // Si un score pour le joueur nom existe déjà, on le met à jour à la place void inserer_score_dans_liste (liste_score_t* scores, int points, char* nom) { if (!inserable_dans_liste(scores, points)) return; score_t* score; for (int numero_score = 0; numero_score < SCORE_BUFFER_SIZE; numero_score++) { score = scores->memoire[numero_score]; if (numero_score < scores->taille) { if (strncmp(nom, score->nom, 8) == 0) { score->score = min(score->score, points); trier_liste_score(scores); return; } } else { initialiser_score(score, points, nom); scores->taille++; trier_liste_score(scores); return; } } initialiser_score(scores->memoire[scores->taille - 1], points, nom); trier_liste_score(scores); } // Permet de trie les scores de la liste par ordre croissant void trier_liste_score (liste_score_t* scores) { score_t** tab = scores->memoire; score_t* tmp; for (int fixe = 0; fixe < scores->taille; ++fixe) { for (int curseur = fixe; curseur < scores->taille; ++curseur) { if (tab[curseur]->score < tab[fixe]->score) { tmp = tab[fixe]; tab[fixe] = tab[curseur]; tab[curseur] = tmp; } } } }
#include "main.h" // Renvoie la valeur minimale entrée en paramètre int min (int premier, int deuxieme){ //Compare les deux paramètres, et permet de renvoyer le plus petit if(premier > deuxieme){ return deuxieme; }else{ return premier; } } // Renvoie la valeur maximale entrée en paramètre int max (int premier, int deuxieme){ //Compare les deux paramètres, et permet de renvoyer le plus grand if(premier < deuxieme){ return deuxieme; }else{ return premier; } } // Renvoie la lettre majuscule en minuscule. int majuscule_en_minuscule(int lettre) { // 65 = A ; Z = 90 if(lettre >= 'A' && lettre <= 'Z'){ return lettre + 32; }else{ return lettre; } }
#include "main.h" // Affiche le niveau de manière (très) brut. void afficher_logo(void){ system("clear"); printf( " ▄▄ \n" " ▄██ ▄█▀▀▀█▄█ ▀███ \n" " ██ ▄██ ▀█ ██ \n" " ██▄████▄ ▄█▀██▄ ▀████████▄ ▀███▄ ▄██▀██▄ ██ ▄██▀ ▄██▀██▄ \n" " ██ ▀████ ██ ██ ██ ▀█████▄██▀ ▀██ ██ ▄█ ██▀ ▀██\n" " ██ ██ ▄█████ ██ ██ ▄ ▀████ ██ ██▄██ ██ ██\n" " ██▄ ▄████ ██ ██ ██ ██ ████▄ ▄██ ██ ▀██▄ ██▄ ▄██\n" " █▀█████▀ ▀████▀██▄████ ████▄ █▀█████▀ ▀█████▀▄████▄ ██▄▄ ▀█████▀ \n"); // 1017 chars > 552 symboles uniques } // Permet de demander à l'utilisateur un entier, pour ensuite choisir le niveau int choix_du_niveau(void) { return menu_saisie_nombre("Choisis un niveau"); } // Permet d'afficher le menu des règles, que nous pouvons quitter avec la touche entrée void afficher_regles(void) { char regles_entiere[1000]; sprintf(regles_entiere, "Règles classiques du Bansoko :\nLe joueur doit placer toutes les caisses (%c)\nsur toutes les cibles (%c)\nMais attention !\nUn joueur est trop faible pour pousser 2 caisses a la fois ...\nOu même les tirer !\n\nPour quitter, appuyez sur ENTREE", DISPLAY_TILE_CRATE, DISPLAY_TILE_TARGET); menu_message("Regles : ", regles_entiere, 50, 9, COLOR_GREEN, COLOR_WHITE); } // Permet d'afficher le menu des crédits, que nous pouvons quitter avec la touche entrée void afficher_credits(void) { char credits_entier[1000]; sprintf(credits_entier, "Un grand merci et bravo aux contributeurs\ndu projets\nJe cite :\n ALMEIDA Néo\n ROUX Hugo\n VANOORENBERGHE Amaury\nEt aux librairies natives\nEt à la superbe librairie Ncurses !\n\nPour quitter, appuyez sur ENTREE\n"); menu_message("Credits : ", credits_entier, 50, 10, COLOR_BLUE, COLOR_WHITE); } // Permet d'afficher le menu des controles, que nous pouvons quitter avec la touche entrée void afficher_controles(void) { char controles[1000]; sprintf(controles, "Se deplacer: fleches / ZQSD\nAnnuler deplacement: %c\nRecommencer: %c\nQuitter: %c\n\nPour quitter, appuyez sur ENTREE", CANCEL, RESTART, LEAVE); menu_message("Controles : ", controles, 50, 6, COLOR_MAGENTA, COLOR_WHITE); } // Permet d'afficher une boite qui attend un chiffre, ce chiffre permet d'afficher les scores du niveau // Le menu créer est quittable avec la touche entrée void afficher_liste_niveau_scoreboard(int numero_niveau) { FILE* fichier; char nom_fichier[100]; sprintf(nom_fichier, "./niveau/niveau_%d", numero_niveau); fichier = fopen(nom_fichier, "r"); if (!fichier) { menu_message("Erreur", "Le niveau specifie n'existe pas", 32, 1, COLOR_RED, COLOR_WHITE); return; } fclose(fichier); int yMax, xMax; // Taille de la console en caractères char titre[100]; sprintf(titre, "Niveau %d - Meilleurs scores", numero_niveau); int largeur = max(40, strlen(titre)); const int marge = 8; WINDOW* fenetre = nouvelle_fenetre(); WINDOW* zone_texte = derwin(fenetre, SCORE_BUFFER_SIZE + 2, largeur, 2, marge / 2); liste_score_t* scores = lire_liste_scores(numero_niveau); do { getmaxyx(stdscr, yMax, xMax); // Lire la taille de la console effacer_ecran(); centrer_fenetre(fenetre, 12, largeur + marge, yMax, xMax, 0, 0); wrefresh(fenetre); // Raffraichissement de la fenêtre wattron(fenetre, COLOR_PAIR(COLOR_CYAN)); // Texte en cyan activé box(fenetre, 0, 0); // Dessine une bordure wattron(fenetre, A_STANDOUT); // Texte en gras activé mvwprintw(fenetre, 0, 2, titre); wattroff(fenetre, A_STANDOUT); // Texte en gras désactivé wattroff(fenetre, COLOR_PAIR(COLOR_CYAN)); // Texte en cyan désactivé if (scores) { wattron(zone_texte, A_BOLD); mvwprintw(zone_texte, 0, 0, "Nom"); mvwprintw(zone_texte, 0, largeur - 5, "Score"); wattroff(zone_texte, A_BOLD); char texte[20]; score_t* score; for (int i = 0; i < scores->taille; ++i) { score = scores->memoire[i]; if (i == 0) { wattron(zone_texte, COLOR_PAIR(COLOR_YELLOW)); } mvwprintw(zone_texte, 2 + i, 0, score->nom); sprintf(texte, "%d coups", score->score); mvwprintw(zone_texte, 2 + i, largeur - strlen(texte), texte); wattroff(zone_texte, COLOR_PAIR(COLOR_YELLOW)); } } else { wattron(zone_texte, A_DIM); // Texte sombre activé mvwprintw(zone_texte, 2, 0, "Aucun score disponible"); wattroff(zone_texte, A_DIM); // Texte sombre désactivé } wattron(fenetre, A_DIM); // Texte sombre activé mvwprintw(fenetre, 10, 4, "Pour quitter, appuyer sur ENTREE"); wattroff(fenetre, A_DIM); // Texte sombre désactivé } while (wgetch(fenetre) != KB_ENTER); if (scores) { liberer_liste_scores(scores); } } // Permet d'afficher le menu principal, celui-ci peut être navigué grâce aux flêches directionnelles (haut et bas) int afficher_menu_principal(void) { char* entries[6]; entries[0] = "Jouer"; entries[1] = "Règles"; entries[2] = "Controles"; entries[3] = "Credits"; entries[4] = "Leaderboards"; entries[5] = "Quitter"; return menu_liste(17, 51, "Bansoko", entries, 6); } // Afficher un menu de confirmation (oui/non) navigable avec les flèches haut/bas int afficher_menu_quitter(void) { char* entries[2]; entries[0] = "Non"; entries[1] = "Oui"; return menu_liste(9, 20, "Quitter ?", entries, 2); } // Afficher un menu de confirmation (oui/non) navigable avec les flèches haut/bas, permettant de recommencer le niveau int afficher_menu_recommencer(void) { char* entries[2]; entries[0] = "Non"; entries[1] = "Oui"; return menu_liste(9, 20, "Recommencer ?", entries, 2); } // Affiche un menu composé d'une liste d'éléments int menu_liste(int hauteur, int largeur, char* titre, char** elements, int nb_elements) { int yMax, xMax; // Taille de la console en caractères WINDOW* fenetre = nouvelle_fenetre(); // Nouvelle fenêtre int selection = 0; // Element sélectionné int input = '\0'; // Saisie while (true) { getmaxyx(stdscr, yMax, xMax); // Lire la taille de la console // Centrer la fenêtre centrer_fenetre(fenetre, hauteur, largeur, yMax, xMax, 0, 0); effacer_ecran(); // Efface l'ecran wclear(fenetre); // Raffraichi la fenêtre box(fenetre, 0, 0); // bordure de la fenêtre mvwprintw(fenetre, 0, 2, titre); // Titre de la fenêtre for (int num_element = 0; num_element < nb_elements; ++num_element) { // Si l'élément actuel est sélectionné if (selection == num_element) { wattron(fenetre, A_STANDOUT); // Texte gras activé wattron(fenetre, COLOR_PAIR(COLOR_RED)); // Texte rouge activé mvwprintw(fenetre, 3 + (2 * num_element), 5, " "); // On affiche un espace (la barre rouge de l'élément sélectionné :D) wattroff(fenetre, COLOR_PAIR(COLOR_RED)); // Texte rouge désactivé } //Affiche les multiples choix du menu mvwprintw(fenetre, 3 + (2 * num_element), 7, elements[num_element]); wattroff(fenetre, A_STANDOUT); // Texte gras désactivé } input = wgetch(fenetre); // Lecture de la saisie switch (input) // Permet de naviguer dans le menu { case KB_UP: selection--; selection = selection < 0 ? 0 : selection; break; case KB_DOWN: selection++; selection = selection >= nb_elements ? nb_elements - 1 : selection; break; case KB_ENTER: delwin(fenetre); return selection; break; } } return -1; } // Affiche un menu permettant d'entrer (seulement) des nombres, que l'ont peut valider avec entrée, 9 chiffres sont acceptés. On peut les supprimer si besoin. int menu_saisie_nombre(char* titre) { int largeur_fenetre = max(strlen(titre), 9) + 10; int yMax, xMax; // Console size in chars WINDOW* fenetre = nouvelle_fenetre(); char texte_saisi[9] = { '\0' }; memset(texte_saisi, '\0', 9 * sizeof(char)); int longueur_texte = 0; int saisie = '\0'; while (true) { longueur_texte = strlen(texte_saisi); getmaxyx(stdscr, yMax, xMax); // Read the console size centrer_fenetre(fenetre, 5, largeur_fenetre, yMax, xMax, 0, 0); effacer_ecran(); wclear(fenetre); // Rafraîchi la fenêtre box(fenetre, 0, 0); // Bordure de fenêtre mvwprintw(fenetre, 0, 2, titre); // Titre de la fenêtre wattron(fenetre, A_STANDOUT); // Surbrillance activée mvwprintw(fenetre, 2, 5, texte_saisi); if (longueur_texte < 9) { wattron(fenetre, COLOR_PAIR(COLOR_YELLOW)); mvwprintw(fenetre, 2, 5 + longueur_texte, "_"); wattroff(fenetre, COLOR_PAIR(COLOR_YELLOW)); } wattroff(fenetre, A_STANDOUT); // Surbrillance désactivée saisie = wgetch(fenetre); // lecture saisie switch (saisie) { case KB_BACKSPACE: // Effacer caractère if (longueur_texte > 0) { texte_saisi[longueur_texte - 1] = '\0'; } break; case KB_ENTER: // Valider saisie (seulement si saisie non vide) if (longueur_texte == 0) break; delwin(fenetre); int numero = 10; sscanf(texte_saisi, "%d", &numero); return numero; default: // On accepte que les chiffres if (longueur_texte < 9 && saisie >= '0' && saisie <= '9') { texte_saisi[longueur_texte] = (char)saisie; } break; } } return -1; } // Affiche un menu permettant d'entrer des chiffres, mais aussi des lettres, et des '_', que l'ont peut valider avec entrée, 8 caractère sont acceptés. On peut les supprimer si besoin. char* menu_saisie_texte(char* titre, int longueur_chaine_max) { int largeur_fenetre = max(strlen(titre), longueur_chaine_max) + 10; int yMax, xMax; // Console size in chars WINDOW* fenetre = nouvelle_fenetre(); char* texte_saisi = malloc(longueur_chaine_max * sizeof(char)); memset(texte_saisi, '\0', longueur_chaine_max * sizeof(char)); int longueur_saisie = 0; int saisie = '\0'; while (true) { longueur_saisie = strlen(texte_saisi); getmaxyx(stdscr, yMax, xMax); // Lecture de la taille de la console // Centrer fenetre centrer_fenetre(fenetre, 5, largeur_fenetre, yMax, xMax, 0, 0); effacer_ecran(); // Efface l'ecran wclear(fenetre); // Raffraichi la fenêtre box(fenetre, 0, 0); // Bordure de la fenêtre mvwprintw(fenetre, 0, 2, titre); // Titre de la fenêtre wattron(fenetre, A_STANDOUT); // Texte gras activé mvwprintw(fenetre, 2, 5, texte_saisi); if (longueur_saisie < longueur_chaine_max) { mvwprintw(fenetre, 2, 5 + longueur_saisie, "_"); } wattroff(fenetre, A_STANDOUT); // Texte gras désactivé saisie = wgetch(fenetre); // Lire la saisie switch (saisie) { case KB_BACKSPACE: if (longueur_saisie > 0) { texte_saisi[longueur_saisie - 1] = '\0'; } break; case KB_ENTER: delwin(fenetre); return texte_saisi; default:; // Saisie texte // Ne pas autoriser la saisie si la longueur de chaine est déjà au maximum if (longueur_saisie >= longueur_chaine_max) break; // N'autoriser que les lettres (minuscules/majuscules), les chiffres, espaces et ttirets bas (underscores) bool saisie_valide = false || (saisie == ' ' || saisie == '_') || (saisie >= '0' && saisie <= '9') || (saisie >= 'a' && saisie <= 'z') || (saisie >= 'A' && saisie <= 'Z'); if (saisie_valide) { texte_saisi[longueur_saisie] = (char)saisie; } break; } } return NULL; } // Affiche une fenêtre qui recouvre la fenêtre actuel, grâce à ses nombreux paramêtres, elle est customisable. On peut la quitter avec la touche entrée void menu_message (char* titre, char* message, int largeur, int hauteur, int couleur, int couleur_texte) { int yMax, xMax; // Taille de la console en caractères WINDOW* fenetre = nouvelle_fenetre(); // Nouvelle fenêtre WINDOW* zone_texte = derwin(fenetre, hauteur, largeur, 2, 2); do { getmaxyx(stdscr, yMax, xMax); // Lecture de la taille de la console centrer_fenetre(fenetre, hauteur + 4, largeur + 4, yMax, xMax, 0, 0); effacer_ecran(); wattron(fenetre, COLOR_PAIR(couleur)); // Sélection de la couleur de fond wclear(fenetre); box(fenetre, 0, 0); wattron(fenetre, A_STANDOUT); // Texte gras activé mvwprintw(fenetre, 0, 2, titre); wattroff(fenetre, A_STANDOUT); // Texte gras désactivé wattroff(fenetre, COLOR_PAIR(couleur)); // Désélection de la couleur de fond wattron(zone_texte, COLOR_PAIR(couleur_texte)); // Sélection de la couleur de texte mvwprintw(zone_texte, 0, 0, message); wattroff(zone_texte, COLOR_PAIR(couleur_texte)); // Désélection de la couleur de texte } while (wgetch(fenetre) != KB_ENTER); delwin(zone_texte); delwin(fenetre); }
#include "main.h" // Crée un nouveau niveau de taille nb_colonnes * nb_lignes et retourne un pointeur vers l'instance créée niveau_t* nouveau_niveau (int nb_colonnes, int nb_lignes){ // Allocation de l'espace mémoire pour l'instance du niveau niveau_t* niveau = malloc(sizeof(niveau_t)); // On assigne les valeurs des attributs de niveau_t niveau->colonnes = nb_colonnes; niveau->lignes = nb_lignes; // On alloue un nouvel espace mémoire pour le terrain de nb_colonnes * nb_lignes cases niveau->terrain = malloc(sizeof(char) * nb_colonnes * nb_lignes); // Les coordonnées du joueur sont pour le moment inconnues... niveau->perso = NULL; // L'état précédent n'existe pas encore, on l'initialise return niveau; } // Supprime une instance de type niveau_t passée en paramètre avec son pointeur void liberation_du_niveau (niveau_t* niveau) { // On libère la mémoire du terrain avant celle de l'instance // Sinon on a une fuite de mémoire car on ne peut plus référencer niveau->terrain free(niveau->perso); free(niveau->terrain); free(niveau); } // Affiche un niveau et renvoie la saisie de l'utilisateur // Note : cette fonction récupère les inputs de l'utilisateur // ATTENTION: Cette fonction se charge de l'affichage ET de la lecture de la saisie clavier char affichage_niveau_ncurses (niveau_t* niveau, int numero_niveau) { int yMax, xMax; // Taille de la console en caractères int meilleur_score = lecture_du_score(numero_niveau); char info[100]; int largeur = 0; // Largeur de la fenetre (création d'une variable car taille non constante) WINDOW* fenetre = nouvelle_fenetre(); // Nouvelle fenêtre int saisie = '\0'; while (true) { getmaxyx(stdscr, yMax, xMax); // Lire la taille de la console // Création du titre de la fenêtre: // Si un high score existe déjà: if (meilleur_score >= 0) { sprintf(info, "Niveau %i | Record: %i coups | %i coups", numero_niveau, meilleur_score, etats_niveaux->taille - 1); } else { // Sinon, si le niveau n'a pas de high score sprintf(info, "Niveau %i | Record: aucun | %i coups", numero_niveau, etats_niveaux->taille - 1); } // Calcul de la largeur idéale de la fenêtre largeur = 2 + max(niveau->colonnes, strlen(info)); // Centrer la fenêtre centrer_fenetre(fenetre, niveau->lignes + 2, largeur + 2, yMax, xMax, 0, 0); effacer_ecran(); // Efface l'ecran box(fenetre, 0, 0); // Bordure de la fenêtre // Permet de calculer le décalage horizontal du niveau pour le centrer dans la fenêtre int decalage = (largeur - niveau->colonnes) / 2; // Affichage du terrain for (int ligne = 0; ligne < niveau->lignes; ++ligne) { for (int colonne = 0; colonne < niveau->colonnes; ++colonne) { //char case_terrain = lecture_du_terrain(niveau, colonne, ligne); char case_affichee = '\0'; int attribut = modification_affichage_niveau(niveau, colonne, ligne, &case_affichee); wattron(fenetre, attribut); mvwaddch(fenetre, ligne + 1, colonne + 1 + decalage, case_affichee); wattroff(fenetre, attribut); wrefresh(fenetre); } } //sprintf("Coups %c", niveau->nb_de_pas); wattron(fenetre, A_STANDOUT); mvwprintw(fenetre, 0, 2, info); // Titre de la fenetre (à changer pour afficher le niveau actuel) //mvwprintw(fenetre, niveau->lignes+1, niveau->colonnes-5, nb_coups); // Nombre de pas (actuellement à 0 vu que c'est l'initialisation du niveau) wattroff(fenetre, A_STANDOUT); mvwprintw(fenetre, niveau->lignes + 1, 2, "[ F1 ou h : Afficher controles ]"); saisie = majuscule_en_minuscule(wgetch(fenetre)); //int saisie = wgetch(fenetre); switch (saisie) { case KB_UP: case DIR_UP: return DIR_UP; case KB_DOWN: case DIR_DOWN: return DIR_DOWN; case KB_LEFT: case DIR_LEFT: return DIR_LEFT; case KB_RIGHT: case DIR_RIGHT: return DIR_RIGHT; case LEAVE: case RESTART: case CANCEL: case HELP: return (char)saisie; case KB_F1: return HELP; } } } // Fonction en charge de lire une case de terrain et de retourner le bon symbole à afficher via le pointeur symbole // Cette fonction renvoie un int correspondant à un code de mise en forme NCurses (couleur, gras, ...) int modification_affichage_niveau (niveau_t* niveau, int x, int y, char* symbole) { char case_terrain = lecture_du_terrain(niveau, x, y); // COmme on n'enregistre pas le joueur comme position dans le terrain // mais via le point_t niveau-> perso, on doit procéder à des vérifications avant l'affichage // Si la case demandée est celle du joueur... if (x == niveau->perso->colonne && y == niveau->perso->ligne) { switch (case_terrain) { case TILE_EMPTY: // Si la case est vide case_terrain = TILE_PLAYER; // On dit que la case est un joueur break; case TILE_TARGET: // Si la case est une cible case_terrain = TILE_PLAYER_ON_TARGET; // La case affichee sera un joueur sur une cible break; } } // Switch sur le type de case (lu depuis le terrain) // pour remplacer par le caractèrre qui sera affiché switch (case_terrain) { case TILE_EMPTY: *symbole = DISPLAY_TILE_EMPTY; break; case TILE_WALL: *symbole = DISPLAY_TILE_WALL; return A_DIM; case TILE_CRATE: *symbole = DISPLAY_TILE_CRATE; return COLOR_PAIR(COLOR_YELLOW); case TILE_TARGET: *symbole = DISPLAY_TILE_TARGET; break; case TILE_CRATE_ON_TARGET: *symbole = DISPLAY_TILE_CRATE_ON_TARGET; return COLOR_PAIR(COLOR_YELLOW); case TILE_PLAYER: *symbole = DISPLAY_TILE_PLAYER; return A_BOLD | COLOR_PAIR(COLOR_GREEN); case TILE_PLAYER_ON_TARGET: *symbole = DISPLAY_TILE_PLAYER_ON_TARGET; return A_BOLD | COLOR_PAIR(COLOR_GREEN); default: *symbole = case_terrain; break; } return 0; } // Afficher le contenu du niveau dans le terminal void affichage_niveau(niveau_t* niveau){ // On "visite" le niveau par ligne puis par colonne for (int ligne = 0; ligne < niveau->lignes; ligne++){ for (int colonne = 0; colonne < niveau->colonnes; colonne++){ // Lecture de la case du terrain char car = lecture_du_terrain(niveau, colonne, ligne); switch (car){ case TILE_EMPTY: car = DISPLAY_TILE_EMPTY; break; case TILE_WALL: car = DISPLAY_TILE_WALL; break; case TILE_CRATE: car = DISPLAY_TILE_CRATE; break; case TILE_TARGET: car = DISPLAY_TILE_TARGET; break; case TILE_CRATE_ON_TARGET: car = DISPLAY_TILE_CRATE_ON_TARGET; break; case TILE_PLAYER: car = DISPLAY_TILE_PLAYER; break; case TILE_PLAYER_ON_TARGET: car = DISPLAY_TILE_PLAYER_ON_TARGET; break; } // Si le joueur est sur la case if (niveau->perso->colonne == colonne && niveau->perso->ligne == ligne){ switch(car){ case TILE_EMPTY: // Si la case est vide, afficher un joueur car = DISPLAY_TILE_PLAYER; break; case TILE_TARGET: // Si la case est une cible, afficher un joueur sur une cible car = DISPLAY_TILE_PLAYER_ON_TARGET; break; } } // On affiche le contenu de la case de coordonnées (colonne;ligne) printf("%c", car); } printf("\n"); // Retour à la ligne } } // Lire un niveau depuis un fichier (dans niveau/) niveau_t* lecture_du_niveau (int numero_niveau){ FILE* fichier; char chemin_du_niveau[100]; sprintf(chemin_du_niveau,"./niveau/niveau_%d", numero_niveau); fichier = fopen(chemin_du_niveau, "r"); // On ouvre le fichier en lecture // Gestion des erreurs... if (!fichier) { menu_message("Fichier introuvable", "Le niveau n'existe pas", 30, 1, COLOR_RED, COLOR_WHITE); return NULL; } int colonne, ligne; // Variables pour stocker les coordonnées fscanf(fichier, "%d %d", &colonne, &ligne); // On lit la taille du niveau dans le fichier // On créée un niveau en mémoire avec les coordonnées lues niveau_t* niveau = nouveau_niveau(colonne, ligne); char car = fgetc(fichier); // On récupère le prochain caractère du fichier int indice_terrain = 0; int taille_tab_terrain = taille_tableau_terrain(niveau); while(car != EOF && indice_terrain <= taille_tab_terrain) { indice_vers_coordonnees_niveau(niveau, indice_terrain, &colonne, &ligne); // Si le caractère n'est pas un retour à la ligne if (car != '\r' && car != '\n'){ // On place le caractère lu sur le terrain puis on incrémente // l'adresse/l'indice d'écriture place_sur_terrain(niveau, colonne, ligne, car); analyser_case_niveau(niveau, indice_terrain); ++indice_terrain; } car = fgetc(fichier); // On récupère le prochain caractère du fichier } fclose(fichier); // On oublie pas de fermer le fichier :D // Gestion des erreurs... if (!niveau->perso) { menu_message("Personnage introuvable", "Le niveau ne contient pas d'emplacement de depart ('@')", 30, 3, COLOR_YELLOW, COLOR_WHITE); return NULL; } // Gestion des erreurs... if (nombre_de_caisse_restante_sur_terrain(niveau) != nombre_cible_sur_terrain(niveau)) { menu_message("Erreur de validation", "Le niveau ne contient pas assez de cibles (.)\nPour pouvoir placer toutes les caisses ($)", 48, 2, COLOR_YELLOW, COLOR_WHITE); return NULL; } return niveau; } // Calcule le nombrede cibles sans caisses sur le terrain int nombre_cible_sur_terrain(niveau_t* niveau){ int nombre_de_cibles = 0; for(int indiceTerrain = 0; indiceTerrain < niveau->colonnes * niveau->lignes;indiceTerrain++){ if(niveau->terrain[indiceTerrain] == TILE_TARGET){ nombre_de_cibles++; } } return nombre_de_cibles; } // Analyse la case à un indice donné et modifie les propriétés de niveau en conséquences // Exemple: si la case lue est un @, on modifie la propriété niveau->perso puis on replace par une case sol void analyser_case_niveau (niveau_t* niveau, int indice){ int colonne, ligne; // On obtient les coordonnées de la case du terrain indice_vers_coordonnees_niveau(niveau, indice, &colonne, &ligne); // On lit la case du terrain char car = lecture_du_terrain(niveau, colonne, ligne); switch (car){ case TILE_PLAYER: // Si la case est un joueur, on modifie niveau->perso niveau->perso = nouveau_point(colonne, ligne); place_sur_terrain(niveau, colonne, ligne, TILE_EMPTY); break; } } // Effectue une copie d'un niveau (pour stocker les états précédents) // Cette copie s'assure que l'on a bien une référence distincte sur le terrain // Au lieu d'ue copie du pointeur vers ce dernier niveau_t* copier_niveau (niveau_t *source) { if (!source) return NULL; niveau_t *copie = malloc (sizeof (niveau_t)); copie->lignes = source->lignes; copie->colonnes = source->colonnes; copie->terrain = malloc (sizeof (char) * taille_tableau_terrain(source)); memcpy (copie->terrain, source->terrain, sizeof(char) * taille_tableau_terrain(source)); copie->perso = malloc (sizeof (point_t)); memcpy (copie->perso, source->perso, sizeof (point_t)); return copie; } // La case est-elle navigable ? (le joueur/une caisse peut-il aller dessus ?) bool case_libre_sur_terrain (niveau_t* niveau, int colonne, int ligne) { char car = lecture_du_terrain(niveau, colonne, ligne); // Si car = TILE_EMPTY ou TILE_TARGET // Si la case en question est vide ou est une cible switch (car){ case TILE_EMPTY: case TILE_TARGET: return true; default: return false; } } // Vérifie si une caisse est présente aux coordonnées entrée en paramètres bool caisse_sur_terrain (niveau_t* niveau, int colonne, int ligne){ char car = lecture_du_terrain(niveau, colonne, ligne); // Si car = TILE_CRATE ou TILE_CRATE_ON_TARGET // Si la case en question est une caisse ou une caisse sur une cible switch (car){ case TILE_CRATE: case TILE_CRATE_ON_TARGET: return true; default: return false; } } // Renvoie le nombre de caisses restantes (qui ne sont pas sur une cible) int nombre_de_caisse_restante_sur_terrain(niveau_t* niveau){ int nombre_de_caisse = 0; // On boucle sur tous le niveau pour chercher le nombre de caisses qui ne sont pas sur une cible for(int indiceTerrain = 0; indiceTerrain < niveau->colonnes * niveau->lignes;indiceTerrain++){ //On vérifie si le le tableau à l'indice indiceTerrain est une caisse //Si oui, on incrémente la valeur du nombre de caisse if(niveau->terrain[indiceTerrain] == TILE_CRATE) { nombre_de_caisse++; } } return nombre_de_caisse; }
#include "main.h" // Détermine pour le niveau spéfcifié l'indice du tableau terrain correspondant aux coordonnées spécifiées int coordonnees_vers_indice_terrain (niveau_t* niveau, int colonne, int ligne){ // On calcule la position dans le tableau terrain // Lecture de gauche à droite puis de haut en bas return ligne * niveau->colonnes + colonne; } // Fonction prenant un indice du tableau terrain et renvoyant la ligne/colonne correspondante void indice_vers_coordonnees_niveau (niveau_t* niveau, int indice, int* colonne, int* ligne){ *ligne = (int)(indice / niveau->colonnes); *colonne = (int)(indice % niveau->colonnes); }
#include "main.h" /* Fonction inutilisée mais demandée, voir fonction : "affichage_niveau_ncurses()" char entree_du_joueur (void){ int var; do { var = getchar(); var = majuscule_en_minuscule(var); } while (var != DIR_UP && var != DIR_LEFT && var != DIR_DOWN && var != DIR_RIGHT && var != LEAVE); printf("%c\n",var); return var; }*/ // Créer une instance d'un point avec les coordonnées spécifiées et renvoie un pointeur vers son adresse point_t* nouveau_point (int colonne, int ligne){ // On alloue de la mémoire pour stocker un point point_t* point = malloc(sizeof(point_t)); // Modification des attributs point->colonne = colonne; point->ligne = ligne; return point; } // Parcours le terrain d'un niveau et renvoie un nouveau personnage point_t* trouver_perso (niveau_t* niveau){ int index = 0; // Indice de parcours dans le tableau terrain du niveau // Tant que la case n'est pas un joueur et que l'indice est dans le tableau while (index < taille_tableau_terrain(niveau) && niveau->terrain[index] != TILE_PLAYER) { ++index; // Incrémenter l'indice de parcours } // Si l'indice est une adresse valide du tableau terrain if (index < taille_tableau_terrain(niveau)){ int colonne, ligne; // On récupère les coordonnées correspondantes à l'indice de parcours indice_vers_coordonnees_niveau(niveau, index, &colonne, &ligne); // On créée et initialise un nouveau personnage point_t* personnage = nouveau_point(colonne, ligne); return personnage; } // Si le niveau ne comporte pas de case personnage, on retourne un pointeur nul return NULL; }
#include "main.h" // Lecture du meilleur score depuis le fichier score_nb // Où nb est le numéro d'un niveau int lecture_du_score(int quel_niveau) { FILE* fichier; char nom_fichier[100]; sprintf(nom_fichier,"./niveau/score_%d", quel_niveau); if ((fichier = fopen(nom_fichier, "r"))) { // Le fichier a bien été ouvert int score; fscanf(fichier, "%d", &score); fclose(fichier); return score; } else { ecriture_du_score(quel_niveau, -1); // Erreur de lecture (le fichier n'existe pas ?) return -1; // Retour d'une valeur d'erreur } } // Insertion du meilleur score dans le fichier score_nb où nb est le numéro du niveau. // (si le score obtenu en fin de partie est supérieur au meilleur score) void ecriture_du_score(int quel_niveau, int score){ FILE* fichier; char nom_fichier[100]; sprintf(nom_fichier, "./niveau/score_%d", quel_niveau); fichier = fopen(nom_fichier, "w"); fprintf(fichier, "%d", score); fclose(fichier); } // Demander le nom du joueur puis l'enregistre dans le tabeau des highscores char* nom_du_joueur(void) { return menu_saisie_texte("Entrez votre nom", 8); }
#include "main.h" /* // Fonction qui permet de simuler une lecture de niveau, elle n'est pas utilisée void initialise_terrain(niveau_t* niveau){ // On parcours les indices du terrain pour placer des murs sur chaque case for (int indice = 0; indice < taille_tableau_terrain(niveau); ++indice) { // On place un mur sur la case n°indice niveau->terrain[indice] = TILE_WALL; } } */ // Modifie une case du terrain du niveau passé en paramètre et la remplace par car void place_sur_terrain (niveau_t* niveau, int colonne, int ligne, char car) { // On calcule l'indice de la case à modifier int indice = coordonnees_vers_indice_terrain(niveau, colonne, ligne); // On remplace la valeur par le char, passé en paramètre niveau->terrain[indice] = car; } // Modifie une case du terrain du niveau passé en paramètre sous forme de point_t et la remplace par car void place_sur_terrain_par_coordonnees(niveau_t* niveau, point_t* coord, char car) { place_sur_terrain(niveau, coord->colonne, coord->ligne, car); } // Lis le contenu du terrain aux coordonées spécifiées en paramètre char lecture_du_terrain(niveau_t* niveau, int colonne, int ligne) { // On calcule l'indice de la case à lire int indice = coordonnees_vers_indice_terrain(niveau, colonne, ligne); return niveau->terrain[indice]; } // Effectue une lecture du terrain aux coordonnées spécifiées sous forme de point_t char lecture_du_terrain_par_coordonnees(niveau_t* niveau, point_t* coord) { // On vérifie que les coordonnées sont valides // Si elles ne sont pas dans le terrain, on retourne \0 (NUL) if (coord->colonne < 0 || coord->colonne >= niveau->colonnes || coord->ligne < 0 || coord->ligne >= niveau->lignes){ return '\0'; }else{ return niveau->terrain[coordonnees_vers_indice_terrain(niveau, coord->colonne, coord->ligne)]; } } // Renvoie la longueur du tableau terrain du niveau spécifié int taille_tableau_terrain(niveau_t* niveau) { return niveau->lignes * niveau->colonnes; }
#ifndef CONSTANTS_H_ #define CONSTANTS_H_ /* — ’ ’ représente les cases vides — ’#’ représente les murs (cases infranchissables) — ’$’ représente une caisse que vous pouvez déplacer — ’.’ représente une zone de rangement sur laquelle vous devez placer une caisse — ’*’ représente une zone de rangement sur laquelle une caisse est actuellement placée — ’@’ représente votre personnage — ’+’ représente votre personnage lorsqu’il est sur une zone de rangement. */ #define TILE_EMPTY ' ' #define TILE_WALL '#' #define TILE_CRATE '$' #define TILE_TARGET '.' #define TILE_CRATE_ON_TARGET '*' #define TILE_PLAYER '@' #define TILE_PLAYER_ON_TARGET '+' #define DISPLAY_TILE_EMPTY ' ' #define DISPLAY_TILE_WALL '#' #define DISPLAY_TILE_CRATE '$' #define DISPLAY_TILE_TARGET '.' #define DISPLAY_TILE_CRATE_ON_TARGET '*' #define DISPLAY_TILE_PLAYER 'M' #define DISPLAY_TILE_PLAYER_ON_TARGET '+' #define DIR_UP 'z' // Touche permettant de se déplacer vers le haut #define DIR_LEFT 'q' // Touche permettant de se déplacer vers la gauche #define DIR_DOWN 's' // Touche permettant de se déplacer vers le bas #define DIR_RIGHT 'd' // Touche permettant de se déplacer vers la droite #define RESTART 'r' // Touche permettant de simuler la touche R, pendant un niveau, elle sert à recommencer le niveau #define LEAVE 'l' // Touche permettant de simuler la touche L, pendant un niveau, elle sert à quitter le niveau #define CANCEL 'a' // Touche permettant de simuler la touche A , pendant un niveau, elle sert à effectuer un retour arrière (annuler_deplacement) #define HELP 'h' // Touche permettant de simuler la touche H, pendant un niveau, elle sert à afficher l'aide #define KB_ENTER 10 // Touche permettant de simuler la touche entrée #define KB_DOWN 258 // Touche permettant de se déplacer vers le bas #define KB_UP 259 // Touche permettant de se déplacer vers le haut #define KB_LEFT 260 // Touche permettant de se déplacer vers la gauche #define KB_RIGHT 261 // Touche permettant de se déplacer vers la droite #define KB_BACKSPACE 263 // Touche permettant de simuler la touche supprimer, pendant une demande de saisie, elle permet de supprimer du texte #define KB_F1 265 // Touche permettant de simuler la touche fonction 1 (F1), pendant un niveau, elle sert à afficher l'aide #define STATE_QUIT 0 #define STATE_MAINMENU 1 #define MAINMENU_PLAY 0 #define MAINMENU_RULES 1 #define MAINMENU_CONTROLS 2 #define MAINMENU_CREDITS 3 #define MAINMENU_SCOREBOARD 4 #define MAINMENU_QUIT 5 #define SCORE_BUFFER_SIZE 5 #endif // CONSTANTS_H_
#ifndef CURSES_UTIL_H #define CURSES_UTIL_H void initialiser_ncurses(); void fermer_ncurses(); void initialiser_couleur(int couleur); void calculer_centre(int hauteur, int largeur, int haut, int gauche, int* y, int* x); void centrer_fenetre(WINDOW* fenetre, int hauteur_cible, int largeur_cible, int hauteur, int largeur, int haut, int gauche); WINDOW* nouvelle_fenetre(); void effacer_ecran(); #endif // CURSES_UTIL_H
#ifndef DEPLACEMENT_H_ #define DEPLACEMENT_H_ void deplacement(niveau_t* niveau, char direction); void annuler_deplacement(); #endif // DEPLACEMENT_H_
#ifndef JOUER_H_ #define JOUER_H_ void jouer_niveau(int numero_niveau); #endif // JOUER_H_
#ifndef LISTE_NIVEAUX_H_ #define LISTE_NIVEAUX_H_ extern liste_niveaux_t* etats_niveaux; liste_niveaux_t *nouvelle_liste_niveaux(int taille); void init_liste_niveaux(liste_niveaux_t* liste, int taille); void liberation_de_la_liste_niveaux(liste_niveaux_t* liste); void ajouter_niveau(liste_niveaux_t* liste, niveau_t* niveau); void enlever_dernier_niveau(liste_niveaux_t* liste); niveau_t* haut_de_liste(liste_niveaux_t* liste); #endif // LISTE_NIVEAUX_H_
#ifndef LISTE_SCORE_H_ #define LISTE_SCORE_H_ score_t* nouveau_score(void); void initialiser_score(score_t* score, int points, char* nom); void liberer_score(score_t* score); liste_score_t* nouvelle_liste_scores(void); void liberer_liste_scores(liste_score_t* scores); liste_score_t* lire_liste_scores(int numero_niveau); void enregistrer_liste_scores(liste_score_t* scores, int numero_niveau); bool inserable_dans_liste(liste_score_t* scores, int points); void inserer_score_dans_liste(liste_score_t* scores, int points, char* nom); void trier_liste_score(liste_score_t* scores); #endif // LISTE_SCORE_H_
#ifndef MAIN_H_ #define MAIN_H_ #include <ncurses.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <unistd.h> #include <string.h> #include "constants.h" #include "math.h" #include "structs.h" #include "point.h" #include "niveau.h" #include "terrain.h" #include "liste_niveaux.h" #include "liste_score.h" #include "curses_util.h" #include "niveau_util.h" #include "menu.h" #include "score.h" #include "deplacement.h" #include "jouer.h" #endif // MAIN_H_
#ifndef MATH_H_ #define MATH_H_ int min(int premier, int deuxieme); int max(int premier, int deuxieme); int majuscule_en_minuscule(int lettre); #endif // MATH_H_
#ifndef MENU_H_ #define MENU_H_ void afficher_logo(void); int choix_du_niveau(void); void afficher_regles(void); void afficher_credits(void); void afficher_controles(void); void instruction_menu(int instruction); int afficher_menu_principal(void); int afficher_menu_quitter(void); int afficher_menu_recommencer(void); void afficher_liste_niveau_scoreboard(int numero_niveau); int menu_liste(int hauteur, int largeur, char* titre, char** elements, int nb_elements); int menu_saisie_nombre(char* titre); char* menu_saisie_texte(char* titre, int longueur_chaine_max); void menu_message(char* titre, char* message, int largeur, int hauteur, int couleur, int couleur_texte); #endif // MENU_H_
#ifndef NIVEAU_H_ #define NIVEAU_H_ niveau_t* nouveau_niveau (int nb_colonnes, int nb_lignes); void liberation_du_niveau (niveau_t* niveau); char affichage_niveau_ncurses (niveau_t* niveau, int numero_niveau); int modification_affichage_niveau (niveau_t* niveau, int x, int y, char* symbole); void affichage_niveau(niveau_t* niveau); niveau_t* lecture_du_niveau(int quel_niveau); int nombre_cible_sur_terrain(niveau_t* niveau); void analyser_case_niveau(niveau_t* niveau, int indice); bool case_libre_sur_terrain(niveau_t* niveau, int colonne, int ligne); bool caisse_sur_terrain(niveau_t* niveau, int colonne, int ligne); int nombre_de_caisse_restante_sur_terrain(niveau_t* niveau); niveau_t* copier_niveau(niveau_t *source); #endif // NIVEAU_H_
#ifndef NIVEAU_UTIL_H_ #define NIVEAU_UTIL_H_ int coordonnees_vers_indice_terrain(niveau_t* niveau, int colonne, int ligne); void indice_vers_coordonnees_niveau(niveau_t* niveau, int indice, int* colonne, int* ligne); #endif // NIVEAU_UTIL_H_
#ifndef POINT_H_ #define POINT_H_ //Fonction inutilisée mais demandée, voir fonction : "affichage_niveau_ncurses()" //char entree_du_joueur(void); point_t* nouveau_point(int colonne, int ligne); point_t* trouver_perso(niveau_t* niveau); #endif // POINT_H_
#ifndef SCORE_H_ #define SCORE_H_ int lecture_du_score(int quel_niveau); void ecriture_du_score(int quel_niveau, int score); char* nom_du_joueur(void); #endif // SCORE_H_
#ifndef STRUCTS_H_ #define STRUCTS_H_ // Structure de donnée représentant la position du joueur typedef struct point_t { int ligne; // Coordonnée verticale (Y) int colonne; // Coordonnée horizontale (X) } point_t; // Structure de donnée représentant un niveau typedef struct niveau_t { int lignes; // Nombre de lignes du niveau (hauteur en cases) int colonnes; // Nombre de colonnes du niveau (largeur en cases) char* terrain; // Contenu du niveau sous forme de caractères point_t* perso; // Position du personnage int indice; // Indice dans la liste de niveaux } niveau_t; // Représente un tableau* de niveaux (pour la fonction d'annulation de déplacements) // *pile/stack typedef struct liste_niveaux_t { niveau_t** memoire; // Contient les pointeurs vers les instances de niveaux représentant des états précédents int taille; // Nombre de cases utilisées int taille_memoire; // Nombre de cases disponibles } liste_niveaux_t; // Représente une paire score/nom joueur typedef struct score_t { int score; //Score char nom[9]; //Nom du joueur } score_t; // Représente une liste de scores de taille fixe (top 5) typedef struct liste_score_t { score_t** memoire; // Ensemble des scores int taille; // Nombre de score stockés (MAX 5) } liste_score_t; #endif // STRUCTS_H_
#ifndef TERRAIN_H_ #define TERRAIN_H_ void initialise_terrain(niveau_t* niveau); void place_sur_terrain(niveau_t* niveau, int colonne, int ligne, char car); void place_sur_terrain_par_coordonnees(niveau_t* niveau, point_t* coord, char car); char lecture_du_terrain(niveau_t* niveau, int colonne, int ligne); char lecture_du_terrain_par_coordonnees(niveau_t* niveau, point_t* coord); int taille_tableau_terrain(niveau_t* niveau); #endif // TERRAIN_H_

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text
×

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue