From 2a322969629e366005cf21756b0218c852199fb9 Mon Sep 17 00:00:00 2001 From: Gretchen Date: Mon, 15 Dec 2025 10:22:10 +0100 Subject: [PATCH 01/19] =?UTF-8?q?Mise=20=C3=A0=20jour=20V3=20:=20Client=20?= =?UTF-8?q?1=20accepte=20IP/port=20en=20arguments=20+=20ajout=20organigram?= =?UTF-8?q?mes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- v3/PN_client1_V3.c | 34 +++- v3/PN_client2_V3.c | 2 + v3/organigramme_V3.svg | 55 +++++ v3/organigramme_V3_pseudocode.txt | 327 ++++++++++++++++++++++++++++++ 4 files changed, 413 insertions(+), 5 deletions(-) create mode 100644 v3/organigramme_V3.svg create mode 100644 v3/organigramme_V3_pseudocode.txt diff --git a/v3/PN_client1_V3.c b/v3/PN_client1_V3.c index 2e93336..4ee4656 100644 --- a/v3/PN_client1_V3.c +++ b/v3/PN_client1_V3.c @@ -32,9 +32,12 @@ void emit(const int code, const char* buffer, int socket) { * Client 1 - Celui qui fait deviner le mot * Entre le mot secret et vérifie les lettres proposées */ -int main(){ +int main(int argc, char *argv[]){ int socket_client; + socklen_t longueurAdresse; struct sockaddr_in adresseServeur; + char ip_serveur[16]; + int port_serveur; char status[10]; char messageRecu[LG_MESSAGE]; char mot_secret[MAX_MOT]; /** Mot secret à faire deviner */ @@ -48,13 +51,34 @@ int main(){ char reponse_message[LG_MESSAGE]; int longueur_mot; + // Récupération arguments + if (argc < 3) { + printf("USAGE : %s ip port\n", argv[0]); + printf("Exemple : %s 127.0.0.1 5000\n", argv[0]); + exit(-1); + } + strncpy(ip_serveur, argv[1], 15); + ip_serveur[15] = '\0'; + sscanf(argv[2], "%d", &port_serveur); + // Création socket socket_client = socket(AF_INET, SOCK_STREAM, 0); - - // Configuration adresse serveur + if (socket_client < 0) { + perror("Erreur socket"); + exit(-1); + } + printf("Socket créée! (%d)\n", socket_client); + + // Configuration adresse + longueurAdresse = sizeof(adresseServeur); + memset(&adresseServeur, 0x00, longueurAdresse); adresseServeur.sin_family = AF_INET; - adresseServeur.sin_port = htons(5000); - adresseServeur.sin_addr.s_addr = inet_addr("127.0.0.1"); + adresseServeur.sin_port = htons(port_serveur); + if (inet_aton(ip_serveur, &adresseServeur.sin_addr) == 0) { + printf("Adresse IP invalide : %s\n", ip_serveur); + close(socket_client); + exit(-2); + } // Connexion connect(socket_client, (struct sockaddr*)&adresseServeur, sizeof(adresseServeur)); diff --git a/v3/PN_client2_V3.c b/v3/PN_client2_V3.c index 9d51d43..54ccdc7 100644 --- a/v3/PN_client2_V3.c +++ b/v3/PN_client2_V3.c @@ -246,6 +246,8 @@ int main(int argc, char *argv[]){ } afficher_pendu(nb_erreurs); + + printf("Mot à deviner : %s\n", mot_decouvert); // Fin de partie if (strcmp(status, "gagne") == 0) { diff --git a/v3/organigramme_V3.svg b/v3/organigramme_V3.svg new file mode 100644 index 0000000..a71de72 --- /dev/null +++ b/v3/organigramme_V3.svg @@ -0,0 +1,55 @@ + + +Client 2(devine) +Serveur(fork) +Client 1(fait deviner) +Client 2(devine) +Serveur(fork) +Client 1(fait deviner) + + + + + +Phase d'initialisation (Processus enfant après fork) + + +1. connect() +2. 3001:"Bienvenue joueur 1..." +3. connect() +4. fork() → Processus enfant +5. 3001:"Bienvenue Client 2..." +6. 2001:"" (demande mot) +7. "PENDU" (mot secret) +8. 2002:"5" (taille mot) + + +Boucle de jeu (tant que partie_en_cours = 1) + + +loop[Jusqu'à "gagne" ou "perdu"] + + +9. "P" (lettre) +10. 2003:"P" + + +Vérifie lettredans le mot + +11. 2006:"oui P__DU 0" +12. 2006:"oui P__DU 0" + + +Affiche statut(mot, erreurs) + + +Fin de partie - Processus enfant se termine + + +13. close() +14. close() + + +Processus parentretourne à accept() + + diff --git a/v3/organigramme_V3_pseudocode.txt b/v3/organigramme_V3_pseudocode.txt new file mode 100644 index 0000000..c94b7c0 --- /dev/null +++ b/v3/organigramme_V3_pseudocode.txt @@ -0,0 +1,327 @@ +═══════════════════════════════════════════════════════════════════════════ + ORGANIGRAMME V3 - EXPLICATION EN PSEUDO-CODE + Jeu du Pendu en Réseau avec Gestion Multi-Parties (fork) +═══════════════════════════════════════════════════════════════════════════ + +┌─────────────────────────────────────────────────────────────────────────┐ +│ SERVEUR PRINCIPAL (Processus Parent) │ +└─────────────────────────────────────────────────────────────────────────┘ + +FONCTION main(): + // Initialisation + socket_ecoute = socket(AF_INET, SOCK_STREAM, 0) + bind(socket_ecoute, port=5000) + listen(socket_ecoute) + + TANT QUE (vrai): + ┌─────────────────────────────────────────────────────────────┐ + │ PHASE 1 : CONNEXION DES CLIENTS │ + └─────────────────────────────────────────────────────────────┘ + + // Attente du premier client + socket_client_1 = accept(socket_ecoute) + ENVOYER(socket_client_1, "3001:Bienvenue joueur 1 ! Attendez...") + + // Attente du deuxième client + socket_client_2 = accept(socket_ecoute) + + ┌─────────────────────────────────────────────────────────────┐ + │ PHASE 2 : CRÉATION DU PROCESSUS ENFANT (fork) │ + └─────────────────────────────────────────────────────────────┘ + + pid = fork() + + SI (pid == 0): + // ─────────────────────────────────────────────────────── + // PROCESSUS ENFANT : Gère une partie + // ─────────────────────────────────────────────────────── + + gerer_partie(socket_client_1, socket_client_2) + + SINON SI (pid > 0): + // ─────────────────────────────────────────────────────── + // PROCESSUS PARENT : Continue à accepter de nouvelles + // connexions pour d'autres parties + // ─────────────────────────────────────────────────────── + + FERMER(socket_client_1) + FERMER(socket_client_2) + // Retourne au début de la boucle pour accepter + // une nouvelle paire de clients + + +┌─────────────────────────────────────────────────────────────────────────┐ +│ FONCTION gerer_partie(socket_client_1, socket_client_2) │ +│ (Exécutée dans le processus enfant) │ +└─────────────────────────────────────────────────────────────────────────┘ + + ┌─────────────────────────────────────────────────────────────────┐ + │ PHASE D'INITIALISATION │ + └─────────────────────────────────────────────────────────────────┘ + + // Accueil du client 2 + ENVOYER(socket_client_2, "3001:Bienvenue Client 2 !...") + + // Demande au client 1 d'entrer un mot + ENVOYER(socket_client_1, "2001:") + + // Réception du mot secret + mot_secret = RECEVOIR(socket_client_1) + longueur_mot = longueur(mot_secret) + + // Informe le client 2 de la taille du mot + ENVOYER(socket_client_2, "2002:" + longueur_mot) + + // Informe le client 1 que le jeu commence + ENVOYER(socket_client_1, "3001:Le joueur 2 devine...") + + ┌─────────────────────────────────────────────────────────────────┐ + │ BOUCLE DE JEU │ + └─────────────────────────────────────────────────────────────────┘ + + partie_en_cours = vrai + + TANT QUE (partie_en_cours): + ┌─────────────────────────────────────────────────────────┐ + │ ÉTAPE 1 : Client 2 propose une lettre │ + └─────────────────────────────────────────────────────────┘ + + lettre = RECEVOIR(socket_client_2) + // Exemple: lettre = "P" + + ┌─────────────────────────────────────────────────────────┐ + │ ÉTAPE 2 : Transmettre la lettre au Client 1 │ + └─────────────────────────────────────────────────────────┘ + + ENVOYER(socket_client_1, "2003:" + lettre) + + ┌─────────────────────────────────────────────────────────┐ + │ ÉTAPE 3 : Client 1 vérifie la lettre │ + │ (dans le code du Client 1) │ + └─────────────────────────────────────────────────────────┘ + + // Le Client 1 reçoit "2003:P" + // Il vérifie si "P" est dans le mot secret + // Il met à jour mot_affiche et nb_erreurs + // Il prépare la réponse + + ┌─────────────────────────────────────────────────────────┐ + │ ÉTAPE 4 : Client 1 envoie la réponse │ + └─────────────────────────────────────────────────────────┘ + + reponse = RECEVOIR(socket_client_1) + // Exemple: reponse = "2006:oui P__DU 0" + // ou: reponse = "2006:non P__DU 1" + // ou: reponse = "2006:gagne PENDU 2" + // ou: reponse = "2006:perdu PENDU 6" + + ┌─────────────────────────────────────────────────────────┐ + │ ÉTAPE 5 : Transmettre la réponse au Client 2 │ + └─────────────────────────────────────────────────────────┘ + + ENVOYER(socket_client_2, reponse) + // Le Client 2 affiche le statut, le mot partiel, + // le nombre d'erreurs et le pendu + + ┌─────────────────────────────────────────────────────────┐ + │ ÉTAPE 6 : Vérifier fin de partie │ + └─────────────────────────────────────────────────────────┘ + + SI (reponse contient "gagne" OU reponse contient "perdu"): + partie_en_cours = faux + SINON: + // Le Client 2 propose une nouvelle lettre + // Retour à l'ÉTAPE 1 + + ┌─────────────────────────────────────────────────────────────────┐ + │ FIN DE PARTIE │ + └─────────────────────────────────────────────────────────────────┘ + + FERMER(socket_client_1) + FERMER(socket_client_2) + QUITTER() // Le processus enfant se termine + + +┌─────────────────────────────────────────────────────────────────────────┐ +│ CLIENT 1 (Fait deviner le mot) │ +└─────────────────────────────────────────────────────────────────────────┘ + +FONCTION main(): + // Connexion au serveur + socket = connect("127.0.0.1", 5000) + + TANT QUE (partie_en_cours): + message = RECEVOIR(socket) + code, donnees = PARSER(message) // Format: "CODE:données" + + SELON code: + CAS "2001": // JOUEUR_1_ENTRE_MOT + AFFICHER("Veuillez entrer un mot à faire deviner : ") + mot_secret = LIRE_ENTREE() + ENVOYER(socket, mot_secret) + // Initialiser mot_affiche avec des tirets + mot_affiche = "_" * longueur(mot_secret) + nb_erreurs = 0 + + CAS "2003": // JOUEUR_2_PROPOSE_LETTRE + lettre = donnees[0] // Exemple: "P" + + // Vérifier si la lettre est valide + SI (lettre n'est pas une lettre): + reponse = "2006:erreur " + mot_affiche + " " + nb_erreurs + ENVOYER(socket, reponse) + CONTINUER + + // Vérifier si déjà testée + SI (lettre déjà testée): + reponse = "2006:deja " + mot_affiche + " " + nb_erreurs + ENVOYER(socket, reponse) + CONTINUER + + // Marquer comme testée + lettres_testees[lettre] = vrai + + // Chercher la lettre dans le mot + trouve = faux + POUR chaque position i dans mot_secret: + SI (mot_secret[i] == lettre): + mot_affiche[i] = lettre + trouve = vrai + + // Mettre à jour le nombre d'erreurs + SI (NON trouve): + nb_erreurs = nb_erreurs + 1 + + // Vérifier fin de partie + SI (mot_affiche ne contient plus de "_"): + status = "gagne" + partie_en_cours = faux + SINON SI (nb_erreurs >= 6): + status = "perdu" + partie_en_cours = faux + SINON: + status = (trouve ? "oui" : "non") + + // Préparer la réponse + SI (partie_terminee ET status == "perdu"): + mot_a_afficher = mot_secret + SINON: + mot_a_afficher = mot_affiche + + reponse = "2006:" + status + " " + mot_a_afficher + " " + nb_erreurs + ENVOYER(socket, reponse) + + CAS "3001": // MESSAGE + AFFICHER(donnees) + + AUTRE: + AFFICHER("Code inconnu: " + code) + + FERMER(socket) + + +┌─────────────────────────────────────────────────────────────────────────┐ +│ CLIENT 2 (Devine le mot) │ +└─────────────────────────────────────────────────────────────────────────┘ + +FONCTION main(): + // Connexion au serveur + socket = connect("127.0.0.1", 5000) + + partie_en_cours = vrai + + TANT QUE (partie_en_cours): + message = RECEVOIR(socket) + code, donnees = PARSER(message) // Format: "CODE:données" + + SELON code: + CAS "2002": // JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER + longueur_mot = ENTIER(donnees) + AFFICHER("Bienvenue au jeu du pendu !") + AFFICHER("Mot de " + longueur_mot + " lettres à deviner") + AFFICHER("Vous avez droit à 6 erreurs maximum") + // Proposer une première lettre + proposer_lettre(socket) + + CAS "2006": // JOUEUR_2_DONNEES_PARTIE + status, mot_decouvert, nb_erreurs = PARSER_DONNEES(donnees) + // Exemple: "oui P__DU 0" + + // Afficher le statut + SELON status: + CAS "oui": + AFFICHER("✓ Bonne lettre !") + CAS "non": + AFFICHER("✗ Mauvaise lettre.") + CAS "deja": + AFFICHER("⚠ Lettre déjà choisie.") + CAS "erreur": + AFFICHER("⚠ Caractère invalide.") + + // Afficher le mot partiel + AFFICHER("Mot : " + mot_decouvert) + AFFICHER("Erreurs : " + nb_erreurs + "/6") + + // Afficher le pendu + AFFICHER_PENDU(nb_erreurs) + + // Vérifier fin de partie + SI (status == "gagne"): + AFFICHER("FÉLICITATIONS ! VOUS AVEZ GAGNÉ !") + AFFICHER("Le mot était : " + mot_decouvert) + partie_en_cours = faux + SINON SI (status == "perdu"): + AFFICHER("DOMMAGE ! VOUS AVEZ PERDU !") + AFFICHER("Le mot était : " + mot_decouvert) + partie_en_cours = faux + SINON: + // Proposer une nouvelle lettre + proposer_lettre(socket) + + CAS "3001": // MESSAGE + AFFICHER(donnees) + + AUTRE: + AFFICHER("Code inconnu: " + code) + + FERMER(socket) + + +FONCTION proposer_lettre(socket): + AFFICHER("Entrez une lettre : ") + lettre = LIRE_ENTREE() + lettre = MAJUSCULE(lettre) + ENVOYER(socket, lettre) + + +═══════════════════════════════════════════════════════════════════════════ + RÉSUMÉ DU FLUX +═══════════════════════════════════════════════════════════════════════════ + +1. Serveur accepte Client 1 → envoie message d'accueil +2. Serveur accepte Client 2 → fait fork() +3. Processus enfant gère la partie : + a. Demande mot au Client 1 + b. Reçoit le mot secret + c. Informe Client 2 de la taille + d. Boucle de jeu : + - Client 2 propose lettre + - Serveur transmet à Client 1 + - Client 1 vérifie et répond + - Serveur transmet réponse à Client 2 + - Répète jusqu'à fin de partie +4. Processus parent retourne à accept() pour nouvelle partie + +═══════════════════════════════════════════════════════════════════════════ + CODES DE COMMUNICATION +═══════════════════════════════════════════════════════════════════════════ + +Format: "CODE:données" + +2001 → Client 1 : Demande d'entrer un mot +2002 → Client 2 : Taille du mot (ex: "2002:5") +2003 → Client 1 : Lettre proposée (ex: "2003:P") +2006 → Client 2 : Données partie (ex: "2006:oui P__DU 0") +3001 → Client(s) : Message informatif + +═══════════════════════════════════════════════════════════════════════════ From 008fe14a08ee6d3d2136009f8be836089939a1e1 Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 16:47:01 +0100 Subject: [PATCH 02/19] =?UTF-8?q?Mise=20=C3=A0=20jour=20V2=20:=20client=20?= =?UTF-8?q?unique=20et=20organigramme=20am=C3=A9lior=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajout de PN_client_V2.c : client unique pour les deux rôles - Mise à jour du README avec instructions pour client unique - Ajout de l'organigramme V2 avec étapes socket/bind/listen/accept - Serveur fait uniquement du relais entre les clients --- v2/PN_client_V2.c | 396 +++++++++++++++++++++++++++++++++++++++++ v2/PN_serveur_V2.c | 167 +++++++++++++++++ v2/README_V2.md | 99 +++++++++++ v2/organigramme_V2.svg | 149 ++++++++++++++++ 4 files changed, 811 insertions(+) create mode 100644 v2/PN_client_V2.c create mode 100644 v2/PN_serveur_V2.c create mode 100644 v2/README_V2.md create mode 100644 v2/organigramme_V2.svg diff --git a/v2/PN_client_V2.c b/v2/PN_client_V2.c new file mode 100644 index 0000000..8d7ce0d --- /dev/null +++ b/v2/PN_client_V2.c @@ -0,0 +1,396 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LG_MESSAGE 256 +#define MAX_MOT 50 +#define MAX_ERREURS 6 + +// Fonction pour afficher le pendu +void afficher_pendu(int nb_erreurs) { + printf("\n"); + switch(nb_erreurs) { + case 0: + printf(" +---+\n"); + printf(" | |\n"); + printf(" |\n"); + printf(" |\n"); + printf(" |\n"); + printf(" |\n"); + printf("=========\n"); + break; + case 1: + printf(" +---+\n"); + printf(" | |\n"); + printf(" O |\n"); + printf(" |\n"); + printf(" |\n"); + printf(" |\n"); + printf("=========\n"); + break; + case 2: + printf(" +---+\n"); + printf(" | |\n"); + printf(" O |\n"); + printf(" | |\n"); + printf(" |\n"); + printf(" |\n"); + printf("=========\n"); + break; + case 3: + printf(" +---+\n"); + printf(" | |\n"); + printf(" O |\n"); + printf(" /| |\n"); + printf(" |\n"); + printf(" |\n"); + printf("=========\n"); + break; + case 4: + printf(" +---+\n"); + printf(" | |\n"); + printf(" O |\n"); + printf(" /|\\ |\n"); + printf(" |\n"); + printf(" |\n"); + printf("=========\n"); + break; + case 5: + printf(" +---+\n"); + printf(" | |\n"); + printf(" O |\n"); + printf(" /|\\ |\n"); + printf(" / |\n"); + printf(" |\n"); + printf("=========\n"); + break; + case 6: + printf(" +---+\n"); + printf(" | |\n"); + printf(" O |\n"); + printf(" /|\\ |\n"); + printf(" / \\ |\n"); + printf(" |\n"); + printf("=========\n"); + printf(" PERDU !\n"); + break; + default: + break; + } + printf("\n"); +} + +/** + * Client V2 - Peut être Client 1 (fait deviner) ou Client 2 (devine) + * + * Usage: + * ./PN_client_V2 + * role: 1 pour faire deviner, 2 pour deviner + * Exemple: ./PN_client_V2 1 127.0.0.1 5000 (Client 1) + * ./PN_client_V2 2 127.0.0.1 5000 (Client 2) + */ +int main(int argc, char *argv[]){ + int socket_client; + struct sockaddr_in adresseServeur; // Va stocker l'IP, le port et le type d'adresse du serveur + socklen_t longueurAdresse; + char ip_serveur[16]; + int port_serveur; + int role; // 1 = fait deviner, 2 = devine + + // Récupération arguments + if (argc < 4) { + printf("USAGE : %s \n", argv[0]); + printf(" role: 1 pour faire deviner, 2 pour deviner\n"); + printf("Exemple : %s 1 127.0.0.1 5000\n", argv[0]); + printf(" %s 2 127.0.0.1 5000\n", argv[0]); + exit(-1); + } + + // Récupération rôle + sscanf(argv[1], "%d", &role); + if (role != 1 && role != 2) { + printf("Erreur : Veuillez entrer 1 pour faire deviner ou 2 pour deviner\n"); + exit(-1); + } + + // Récupération IP et port + strncpy(ip_serveur, argv[2], 15); + ip_serveur[15] = '\0'; + sscanf(argv[3], "%d", &port_serveur); + + // Création socket AF_INET pour IPv4, SOCK_STREAM pour TCP, 0 pour le protocole par défaut + socket_client = socket(AF_INET, SOCK_STREAM, 0); + if (socket_client < 0) { + perror("Erreur socket"); + exit(-1); + } + printf("Socket créée! (%d)\n", socket_client); + + // Configuration adresse + longueurAdresse = sizeof(adresseServeur); + memset(&adresseServeur, 0x00, longueurAdresse); + adresseServeur.sin_family = AF_INET; + adresseServeur.sin_port = htons(port_serveur); // htons convertit le port format machine en format réseau + if (inet_aton(ip_serveur, &adresseServeur.sin_addr) == 0) { // inet_aton convertit l'IP en format binaire + printf("Adresse IP invalide : %s\n", ip_serveur); + close(socket_client); + exit(-2); + } + + // Connexion + printf("Tentative de connexion à %s:%d...\n", ip_serveur, port_serveur); + if ((connect(socket_client, (struct sockaddr *) &adresseServeur, longueurAdresse)) == -1) { + perror("Erreur connexion"); + close(socket_client); + exit(-3); + } + printf(">>> Connexion réussie!\n\n"); + + // ============================================================ + // CLIENT 1 : Fait deviner le mot + // ============================================================ + if (role == 1) { + char messageRecu[LG_MESSAGE]; + char mot_secret[MAX_MOT]; + char mot_affiche[MAX_MOT]; + char lettres_deja_testees[26] = {0}; + int lus; + int nb_erreurs = 0; + + // Reçoit demande serveur, qui demande le mot à deviner + lus = recv(socket_client, messageRecu, LG_MESSAGE-1, 0); + if (lus <= 0) { + perror("Erreur réception"); + close(socket_client); + exit(-4); + } + // \0 permet de terminer la chaîne de caractères pour éviter les problèmes de dépassement de buffer + messageRecu[lus] = '\0'; + printf("%s", messageRecu); + + // Saisie du mot + scanf("%s", mot_secret); + + // Conversion en majuscules + for(int i = 0; mot_secret[i]; i++) { + mot_secret[i] = toupper((unsigned char)mot_secret[i]); + } + + // Initialisation avec des tirets + int longueur_mot = strlen(mot_secret); + for(int i=0; i= MAX_ERREURS) { + strcpy(status, "perdu"); + partie_terminee = 1; + } else { + strcpy(status, trouve ? "oui" : "non"); + } + + // Envoi de la réponse + if(partie_terminee) { + snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, + partie_terminee && strcmp(status, "perdu") == 0 ? mot_secret : mot_affiche, + nb_erreurs); + } else { + snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, mot_affiche, nb_erreurs); + } + + send(socket_client, messageRecu, strlen(messageRecu)+1, 0); + + if(partie_terminee) { + break; + } + } + } + + // ============================================================ + // CLIENT 2 : Devine le mot + // ============================================================ + else { // role == 2 + char buffer[LG_MESSAGE]; + int octets_lus; + char status[20]; + char mot_decouvert[LG_MESSAGE]; + int nb_erreurs; + + // Réception "start x" + memset(buffer, 0, LG_MESSAGE); + octets_lus = recv(socket_client, buffer, LG_MESSAGE, 0); + if (octets_lus <= 0) { + perror("Erreur réception"); + close(socket_client); + exit(-4); + } + buffer[octets_lus] = '\0'; + + int longueur_mot; + // On attend le message "start x" où x est la longueur du mot à deviner + if (sscanf(buffer, "start %d", &longueur_mot) != 1) { + printf("Message inattendu : %s\n", buffer); + close(socket_client); + exit(-5); + } + + printf("\n===========================================\n"); + printf(" BIENVENUE AU JEU DU PENDU !\n"); + printf("===========================================\n"); + printf("Mot de %d lettres à deviner\n", longueur_mot); + printf("Vous avez droit à 6 erreurs maximum\n"); + printf("===========================================\n\n"); + + // Boucle principale + while (1) { + char lettre; + printf("\nEntrez une lettre : "); + if (scanf(" %c", &lettre) != 1) { + printf("Erreur de saisie\n"); + continue; + } + + // Nettoyage buffer + int c; + int chars_ignores = 0; + // On nettoie le buffer d'entrée pour éviter les problèmes de dépassement de buffer + while ((c = getchar()) != '\n' && c != EOF) { + chars_ignores++; + } + if (chars_ignores > 0) { + printf("⚠ Attention : seule la première lettre a été prise en compte.\n"); + } + + lettre = toupper(lettre); + + if (!isalpha(lettre)) { + printf("Veuillez entrer une lettre valide (A-Z)\n"); + continue; + } + + // Envoi de la lettre + sprintf(buffer, "%c", lettre); + send(socket_client, buffer, strlen(buffer) + 1, 0); + + // Réception réponse + memset(buffer, 0, LG_MESSAGE); + octets_lus = recv(socket_client, buffer, LG_MESSAGE, 0); + if (octets_lus <= 0) { + perror("Erreur réception"); + close(socket_client); + exit(-7); + } + buffer[octets_lus] = '\0'; + + // Parsing + if (sscanf(buffer, "%s %s %d", status, mot_decouvert, &nb_erreurs) != 3) { + printf("Réponse inattendue : %s\n", buffer); + continue; + } + + // Affichage + printf("\n"); + printf("Mot : "); + for (int i = 0; i < strlen(mot_decouvert); i++) { + printf("%c ", mot_decouvert[i]); + } + printf("\n"); + printf("Erreurs : %d/6\n", nb_erreurs); + + afficher_pendu(nb_erreurs); + + if (strcmp(status, "oui") == 0) { + printf("✓ Bonne lettre !\n"); + } else if (strcmp(status, "non") == 0) { + printf("✗ Mauvaise lettre.\n"); + } else if (strcmp(status, "deja") == 0) { + printf("⚠ Lettre déjà choisie. Choisissez-en une autre.\n"); + } else if (strcmp(status, "erreur") == 0) { + printf("⚠ Caractère invalide. Entrez une lettre (A-Z).\n"); + } + + // Fin de partie + if (strcmp(status, "gagne") == 0) { + printf("\n"); + printf("*******************************************\n"); + printf(" FÉLICITATIONS ! VOUS AVEZ GAGNÉ !\n"); + printf(" Le mot était : %s\n", mot_decouvert); + printf(" Nombre d'erreurs : %d\n", nb_erreurs); + printf("*******************************************\n"); + break; + } else if (strcmp(status, "perdu") == 0) { + printf("\n"); + printf("*******************************************\n"); + printf(" DOMMAGE ! VOUS AVEZ PERDU !\n"); + printf(" Le mot était : %s\n", mot_decouvert); + printf("*******************************************\n"); + break; + } + } + } + + close(socket_client); + printf("\nConnexion fermée. Au revoir !\n"); + return 0; +} + diff --git a/v2/PN_serveur_V2.c b/v2/PN_serveur_V2.c new file mode 100644 index 0000000..c538d5d --- /dev/null +++ b/v2/PN_serveur_V2.c @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 5000 +#define LG_MESSAGE 512 +#define MAX_ERREURS 6 +#define MOT_SECRET "PENDU" +#define MAX_MOT 50 + +/** + * Serveur V2 - Fait transiter les messages entre 2 clients + * Client 1 : fait deviner (entre le mot) + * Client 2 : devine (propose des lettres) + */ +int main(int argc, char *argv[]){ + int socketEcoute; + int socket_client_1, socket_client_2; + struct sockaddr_in adresseServeur; + socklen_t longueurAdresse; + struct sockaddr_in adresseClient; + char messageRecu[LG_MESSAGE]; + int lus; + + // Création socket d'écoute + socketEcoute = socket(AF_INET, SOCK_STREAM, 0); + if (socketEcoute < 0) { + perror("socket"); + exit(-1); + } + printf("Socket créée avec succès ! (%d)\n", socketEcoute); + + // Option pour réutiliser le port + int opt = 1; + setsockopt(socketEcoute, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + + // Configuration adresse serveur + longueurAdresse = sizeof(adresseServeur); + memset(&adresseServeur, 0x00, longueurAdresse); + adresseServeur.sin_family = PF_INET; + adresseServeur.sin_addr.s_addr = htonl(INADDR_ANY); + adresseServeur.sin_port = htons(PORT); + + // Bind + if ((bind(socketEcoute, (struct sockaddr *)&adresseServeur, longueurAdresse)) < 0) { + perror("bind"); + exit(-2); + } + printf("Socket attachée avec succès !\n"); + + // Listen + if (listen(socketEcoute, 5) < 0) { + perror("listen"); + exit(-3); + } + printf("Socket placée en écoute passive sur le port %d...\n", PORT); + + // Boucle principale + while (1) { + char buffer[LG_MESSAGE]; + char mot_secret[MAX_MOT]; + int longueur_mot; + + // Attente client 1 + printf("\n=== Attente du premier client ===\n"); + + longueurAdresse = sizeof(adresseClient); + socket_client_1 = accept(socketEcoute, (struct sockaddr *) &adresseClient, &longueurAdresse); + + if (socket_client_1 < 0) { + perror("Erreur accept client 1"); + continue; + } + printf(">>> Client 1 connecté depuis %s:%d\n", inet_ntoa(adresseClient.sin_addr), ntohs(adresseClient.sin_port)); + + // Demander le mot + strcpy(buffer, "Veuillez entrer un mot à deviner : "); + send(socket_client_1, buffer, strlen(buffer) + 1, 0); + printf("Envoyé au client 1 : %s\n", buffer); + + // Recevoir le mot + memset(messageRecu, 0, LG_MESSAGE); + lus = recv(socket_client_1, messageRecu, LG_MESSAGE-1, 0); + if (lus <= 0) { + printf("Le client 1 s'est déconnecté.\n"); + close(socket_client_1); + continue; + } + messageRecu[lus] = '\0'; + printf("Le mot entré par le client 1 : %s\n", messageRecu); + + strncpy(mot_secret, messageRecu, MAX_MOT-1); + mot_secret[MAX_MOT-1] = '\0'; + longueur_mot = strlen(messageRecu); + + // Attente client 2 + printf("\n=== Attente du deuxième client ===\n"); + + longueurAdresse = sizeof(adresseClient); + socket_client_2 = accept(socketEcoute, (struct sockaddr *) &adresseClient, &longueurAdresse); + if (socket_client_2 < 0) { + perror("Erreur accept client 2"); + close(socket_client_1); + continue; + } + printf(">>> Client 2 connecté depuis %s:%d\n", inet_ntoa(adresseClient.sin_addr), ntohs(adresseClient.sin_port)); + + // Envoi "start x" + sprintf(buffer, "start %d", longueur_mot); + send(socket_client_2, buffer, strlen(buffer) + 1, 0); + printf("Envoyé au client 2 : %s\n", buffer); + + // Boucle de transit des messages + printf("\n=== Début de la partie ===\n"); + int partie_en_cours = 1; + while (partie_en_cours) { + // Recevoir lettre du client 2 + memset(messageRecu, 0, LG_MESSAGE); + lus = recv(socket_client_2, messageRecu, LG_MESSAGE-1, 0); + if (lus <= 0) { + printf("Le client 2 s'est déconnecté.\n"); + break; + } + messageRecu[lus] = '\0'; + printf("Reçu du client 2 (lettre) : %s → Transite au client 1\n", messageRecu); + + // Transiter au client 1 + send(socket_client_1, messageRecu, strlen(messageRecu) + 1, 0); + + // Recevoir réponse du client 1 + memset(messageRecu, 0, LG_MESSAGE); + lus = recv(socket_client_1, messageRecu, LG_MESSAGE-1, 0); + if (lus <= 0) { + printf("Le client 1 s'est déconnecté.\n"); + break; + } + messageRecu[lus] = '\0'; + printf("Reçu du client 1 (réponse) : %s → Transite au client 2\n", messageRecu); + + // Transiter au client 2 + send(socket_client_2, messageRecu, strlen(messageRecu) + 1, 0); + + // Vérifier fin de partie + if (strstr(messageRecu, "gagne") != NULL || strstr(messageRecu, "perdu") != NULL) { + printf(">>> Partie terminée !\n"); + partie_en_cours = 0; + } + } + + // Fermeture + close(socket_client_1); + close(socket_client_2); + + printf("\n=== Fin de la partie ===\n"); + printf("Le mot à deviner était : %s\n", mot_secret); + printf("Connexions fermées. Prêt pour une nouvelle partie.\n\n"); + } + + close(socketEcoute); + return 0; +} diff --git a/v2/README_V2.md b/v2/README_V2.md new file mode 100644 index 0000000..0692ec6 --- /dev/null +++ b/v2/README_V2.md @@ -0,0 +1,99 @@ +# JEU DU PENDU - Version 2 (V2) + +## Description + +Version 2 du jeu du pendu en réseau. Cette version permet à **2 joueurs** de jouer ensemble : +- **Client 1** : Le joueur qui fait deviner (entre le mot secret) +- **Client 2** : Le joueur qui devine (propose des lettres) + +Le **serveur** fait uniquement transiter les messages entre les 2 clients sans intervenir dans la logique du jeu. + +## Architecture + +``` +Client 1 (fait deviner) ←→ Serveur (relais) ←→ Client 2 (devine) +``` + +## Compilation + +### Linux/macOS : +```bash +# Compiler le serveur +gcc -o PN_serveur_V2 PN_serveur_V2.c + +# Compiler les clients +gcc -o PN_client1_V2 PN_client1_V2.c +gcc -o PN_client2_V2 PN_client2_V2.c +``` + +### Windows (avec MinGW ou WSL) : +Même commande dans WSL ou MinGW + +## Exécution + +### Terminal 1 - Serveur : +```bash +./PN_serveur_V2 +``` + +### Terminal 2 - Client 1 (fait deviner) : +```bash +./PN_client1_V2 +``` +Le client 1 doit entrer un mot à faire deviner. + +### Terminal 3 - Client 2 (devine) : +```bash +./PN_client2_V2 127.0.0.1 5000 +``` +Le client 2 propose des lettres pour deviner le mot. + +## Règles du jeu + +- Le **Client 1** entre un mot secret (maximum 50 caractères) +- Le **Client 2** doit deviner le mot en proposant des lettres +- Maximum d'erreurs : **6** +- Le pendu s'affiche progressivement avec chaque erreur +- La partie se termine quand : + - Le mot est complètement découvert → **Victoire** + - 6 erreurs sont commises → **Défaite** + +## Format des messages + +### Messages envoyés par le serveur : +- `"Veuillez entrer un mot à deviner : "` → Client 1 +- `"start x"` → Client 2 (x = nombre de lettres) + +### Messages entre clients (via le serveur) : +- Client 2 → Client 1 : Lettre proposée (ex: `"P"`) +- Client 1 → Client 2 : Réponse formatée + - `"oui mot_decouvert nb_erreurs"` (ex: `"oui P__DU 0"`) + - `"non mot_decouvert nb_erreurs"` (ex: `"non P__DU 1"`) + - `"deja mot_decouvert nb_erreurs"` (lettre déjà testée) + - `"gagne mot_complet nb_erreurs"` (victoire) + - `"perdu mot_secret nb_erreurs"` (défaite) + +## Fonctionnalités + +- ✅ Communication TCP/IP entre 2 clients via un serveur +- ✅ Affichage du pendu ASCII selon le nombre d'erreurs +- ✅ Gestion des lettres déjà testées +- ✅ Détection automatique de fin de partie +- ✅ Serveur qui reste actif pour plusieurs parties + +## En cas de problème + +### Port déjà utilisé : +```bash +lsof -i :5000 +kill -9 [PID] +``` + +### Erreur de connexion : +- Vérifier que le serveur est lancé avant les clients +- Vérifier l'IP et le port (127.0.0.1:5000 par défaut) + +## Auteur + +Mapbaya + diff --git a/v2/organigramme_V2.svg b/v2/organigramme_V2.svg new file mode 100644 index 0000000..2542cb4 --- /dev/null +++ b/v2/organigramme_V2.svg @@ -0,0 +1,149 @@ + + + + Organigramme V2 - Communication Client/Serveur + + + + Client 1 + + + Serveur + + + Client 2 + + + + + + + + + Phase d'initialisation serveur + + + + socket() + + + + bind() + + + + listen() + + + + accept() - En attente Client 1 + + + + Phase d'initialisation Client 1 + + + + socket() + + + + 1. connect() + + + + accept() - Client 1 connecté + + + + 2. "Veuillez entrer un mot à deviner : " + + + + 3. Mot secret + + + + accept() - En attente Client 2 + + + + Phase d'initialisation Client 2 + + + + socket() + + + + 4. connect() + + + + accept() - Client 2 connecté + + + + 5. "start x" + + + + Boucle de jeu - relais des messages + + + + Client 1 vérifie + si lettre dans + le mot + + + + Client 2 affiche + statut mot, + erreurs, pendu + + + + [Boucle jusqu'à fin de partie] + + + + 6. Lettre proposée + + + + 7. Transite la lettre + + + + 8. Réponse formatée + "status mot erreurs" + + + + 9. Transite la réponse + + + + Fin de partie + + + + 10. close() + + + + 11. close() + + + + Serveur retourne à accept() + pour une nouvelle partie + + + + + + + + From d1c66c25076bb210d9adcdb55c570f0b4d11b80e Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:09:32 +0100 Subject: [PATCH 03/19] =?UTF-8?q?Mise=20=C3=A0=20jour=20V3=20:=20client=20?= =?UTF-8?q?unique=20et=20nettoyage=20complet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Suppression de tous les anciens fichiers V3 - Ajout de PN_serveur_V3.c avec fork() pour multi-parties - Ajout de PN_client_V3.c (client unique avec détection automatique des rôles) - Ajout de README_V3.md avec documentation complète - Système de codes de communication (2001-2006, 3001) - Client unique qui gère automatiquement les deux rôles --- v3/PN_client2_V3.c => PN_client_V3.c | 175 +++++++++--- v3/PN_serveur_V3.c => PN_serveur_V3.c | 0 README.md | 107 ------- v3/README_V3.md => README_V3.md | 75 ++--- v2/PN_client_V2.c | 396 -------------------------- v2/PN_serveur_V2.c | 167 ----------- v2/README_V2.md | 99 ------- v2/organigramme_V2.svg | 149 ---------- v3/PN_client1_V3.c | 211 -------------- v3/organigramme_V3.svg | 55 ---- v3/organigramme_V3_pseudocode.txt | 327 --------------------- 11 files changed, 167 insertions(+), 1594 deletions(-) rename v3/PN_client2_V3.c => PN_client_V3.c (60%) rename v3/PN_serveur_V3.c => PN_serveur_V3.c (100%) delete mode 100644 README.md rename v3/README_V3.md => README_V3.md (54%) delete mode 100644 v2/PN_client_V2.c delete mode 100644 v2/PN_serveur_V2.c delete mode 100644 v2/README_V2.md delete mode 100644 v2/organigramme_V2.svg delete mode 100644 v3/PN_client1_V3.c delete mode 100644 v3/organigramme_V3.svg delete mode 100644 v3/organigramme_V3_pseudocode.txt diff --git a/v3/PN_client2_V3.c b/PN_client_V3.c similarity index 60% rename from v3/PN_client2_V3.c rename to PN_client_V3.c index 54ccdc7..e16668e 100644 --- a/v3/PN_client2_V3.c +++ b/PN_client_V3.c @@ -9,7 +9,10 @@ #include #define LG_MESSAGE 256 +#define MAX_MOT 50 +#define MAX_ERREURS 6 +// Voir définition des codes dans PN_serveur_V3.c #define JOUEUR_1_ENTRE_MOT 2001 #define JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER 2002 #define JOUEUR_2_PROPOSE_LETTRE 2003 @@ -126,31 +129,32 @@ void joueur_choisi_lettre(int socket_client) { emit(JOUEUR_2_PROPOSE_LETTRE, lettre, socket_client); } - /** - * Client 2 - Celui qui devine le mot - * Propose des lettres et reçoit les réponses + * Client - Celui qui fait deviner le mot ou devine en fonction du serveur + * Entre le mot secret et vérifie les lettres proposées */ int main(int argc, char *argv[]){ int socket_client; - struct sockaddr_in adresseServeur; socklen_t longueurAdresse; - char buffer[LG_MESSAGE]; - int octets_lus; + struct sockaddr_in adresseServeur; char ip_serveur[16]; int port_serveur; + char status[10]; + char messageRecu[LG_MESSAGE]; + int lus; + + // Client 1 + char mot_secret[MAX_MOT]; /** Mot secret à faire deviner */ + char mot_affiche[MAX_MOT]; /** Mot avec lettres découvertes (ex: "P__DU") */ + char lettres_deja_testees[26] = {0}; /** Tableau pour éviter les lettres déjà testées */ + int nb_erreurs = 0; int partie_en_cours = 1; + int type_joueur = -1; int reponse_code; // ex : 2003 char reponse_message[LG_MESSAGE]; - - // Variables pour parser les réponses - char status[20]; - char mot_decouvert[LG_MESSAGE]; - int longueur_mot; - int nb_erreurs; - + // Récupération arguments if (argc < 3) { printf("USAGE : %s ip port\n", argv[0]); @@ -179,44 +183,124 @@ int main(int argc, char *argv[]){ close(socket_client); exit(-2); } - + // Connexion - printf("Tentative de connexion à %s:%d...\n", ip_serveur, port_serveur); - if ((connect(socket_client, (struct sockaddr *) &adresseServeur, longueurAdresse)) == -1) { - perror("Erreur connexion"); - close(socket_client); - exit(-3); - } - printf(">>> Connexion réussie!\n\n"); + connect(socket_client, (struct sockaddr*)&adresseServeur, sizeof(adresseServeur)); + // Boucle principale while(partie_en_cours) { - memset(buffer, 0, LG_MESSAGE); - octets_lus = recv(socket_client, buffer, LG_MESSAGE - 1, 0); - if (octets_lus <= 0) { - perror("Erreur réception"); - close(socket_client); - exit(-4); - } + lus = recv(socket_client, messageRecu, LG_MESSAGE-1, 0); + if(lus <= 0) break; - buffer[octets_lus] = '\0'; + messageRecu[lus] = '\0'; - if (sscanf(buffer, "%4d", &reponse_code) != 1) { // récupére le code - printf("Format de communication non respecté : %s\n", buffer); + /* Récupere les 4 premiers chiffres du message, correspondants au code à interpreter plus bas*/ + if (sscanf(messageRecu, "%4d", &reponse_code) != 1) { // récupére le code + printf("Format de communication non respecté : %s\n", messageRecu); close(socket_client); exit(-5); } - char *msg = strchr(buffer, ':'); + char *msg = strchr(messageRecu, ':'); if (msg != NULL) { // récupere le contenu (potentiel) msg++; // supprime le ':' strcpy(reponse_message, msg); } else { - printf("Format de communication non respecté/Erreur sur le contenu : %s\n", buffer); - close(socket_client); - exit(-6); + printf("Format de communication non respecté/Erreur sur le contenu : %s\n", messageRecu); } - + switch(reponse_code){ + case JOUEUR_1_ENTRE_MOT: + printf("Un joueur est arrivé !\nVeuillez entrer le mot à faire deviner : "); + scanf("%s", mot_secret); + + for (int i = 0; mot_secret[i]; i++) + mot_secret[i] = toupper((unsigned char)mot_secret[i]); + + // Initialisation avec des tirets + longueur_mot = strlen(mot_secret); + for(int i=0;i 'Z') { + strcpy(status, "erreur"); + snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, mot_affiche, nb_erreurs); + emit(JOUEUR_2_DONNEES_PARTIE, messageRecu, socket_client); + break; + } + + // Vérification si déjà testée + if (lettres_deja_testees[lettre - 'A']) { + strcpy(status, "deja"); + snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, mot_affiche, nb_erreurs); + emit(JOUEUR_2_DONNEES_PARTIE, messageRecu, socket_client); + break; + } + + // Marquer comme testée + lettres_deja_testees[lettre - 'A'] = 1; + + // Recherche dans le mot + int trouve = 0; + for (int i = 0; i < longueur_mot; i++) { + if (mot_secret[i] == lettre) { + mot_affiche[i] = lettre; + trouve = 1; + } + } + + if (!trouve) + nb_erreurs++; + + // Vérifier mot complet + int mot_complet = 1; + for (int i = 0; i < longueur_mot; i++) { + if (mot_affiche[i] == '_') { + mot_complet = 0; + break; + } + } + + + if (mot_complet) { + strcpy(status, "gagne"); + partie_terminee = 1; + } else if (nb_erreurs >= MAX_ERREURS) { + strcpy(status, "perdu"); + partie_terminee = 1; + } else { + strcpy(status, trouve ? "oui" : "non"); + } + + if(partie_terminee && (strcmp(status, "perdu")|| strcmp(status, "gagne"))) + printf("Le joueur a %s la partie ! Le mot était : %s\n", strcmp(status, "gagne") == 0 ? "gagné" : "perdu", mot_secret); + + + // Envoi réponse + snprintf(messageRecu, LG_MESSAGE, "%s %s %d", + status, + (partie_terminee && strcmp(status, "perdu") == 0) ? mot_secret : mot_affiche, + nb_erreurs); + + emit(JOUEUR_2_DONNEES_PARTIE, messageRecu, socket_client); + + if (partie_terminee) + partie_en_cours = 0; + + + break; + } case JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER: longueur_mot = atoi(reponse_message); printf("\n===========================================\n"); @@ -230,8 +314,8 @@ int main(int argc, char *argv[]){ break; case JOUEUR_2_DONNEES_PARTIE: - if (sscanf(reponse_message, "%s %s %d", status, mot_decouvert, &nb_erreurs) != 3) { - printf("Réponse inattendue : %s\n", buffer); + if (sscanf(reponse_message, "%s %s %d", status, mot_affiche, &nb_erreurs) != 3) { + printf("Réponse inattendue : %s\n",messageRecu); break; } @@ -247,14 +331,14 @@ int main(int argc, char *argv[]){ afficher_pendu(nb_erreurs); - printf("Mot à deviner : %s\n", mot_decouvert); + printf("Mot à deviner : %s\n", mot_affiche); // Fin de partie if (strcmp(status, "gagne") == 0) { printf("\n"); printf("*******************************************\n"); printf(" FÉLICITATIONS ! VOUS AVEZ GAGNÉ !\n"); - printf(" Le mot était : %s\n", mot_decouvert); + printf(" Le mot était : %s\n", mot_affiche); printf(" Nombre d'erreurs : %d\n", nb_erreurs); printf("*******************************************\n"); partie_en_cours = 0; @@ -263,7 +347,7 @@ int main(int argc, char *argv[]){ printf("\n"); printf("*******************************************\n"); printf(" DOMMAGE ! VOUS AVEZ PERDU !\n"); - printf(" Le mot était : %s\n", mot_decouvert); + printf(" Le mot était : %s\n", mot_affiche); printf("*******************************************\n"); partie_en_cours = 0; break; @@ -273,14 +357,13 @@ int main(int argc, char *argv[]){ break; case MESSAGE: printf("%s\n", reponse_message); - break; + break; default: - printf("Code inconnu reçu : %d (contenu: %s)\n", reponse_code, reponse_message); + printf("Code reçu inconnu : %d\n", reponse_code); break; - } + } } - + close(socket_client); - printf("\nConnexion fermée. Au revoir !\n"); return 0; } diff --git a/v3/PN_serveur_V3.c b/PN_serveur_V3.c similarity index 100% rename from v3/PN_serveur_V3.c rename to PN_serveur_V3.c diff --git a/README.md b/README.md deleted file mode 100644 index c512ec9..0000000 --- a/README.md +++ /dev/null @@ -1,107 +0,0 @@ -# 🧩 SAE_Socket — Jeu du Pendu en C avec Sockets - -## 🎯 Description du projet - -Le projet **SAE_Socket** a été réalisé dans le cadre d’une **SAÉ (Situation d’Apprentissage et d’Évaluation)** à l’IUT. -L’objectif principal est de concevoir **plusieurs versions évolutives** d’une application client-serveur en **langage C**, en utilisant **les sockets TCP/IP** pour la communication entre les processus. - -Chaque version introduit de **nouvelles fonctionnalités** et une **meilleure architecture** réseau, en s’appuyant sur le même concept de base : le **jeu du Pendu**. - ---- - -## 🧠 Objectifs pédagogiques - -- Comprendre le **fonctionnement des sockets** en C (communication réseau bas niveau). -- Implémenter une architecture **client/serveur**. -- Gérer **les échanges et la synchronisation** entre plusieurs processus. -- Améliorer progressivement le code (**robustesse, modularité, expérience utilisateur**). - ---- - -## ⚙️ Fonctionnement global - -Le projet se compose de deux programmes principaux : - -- **Serveur** : - Gère le mot à deviner, la connexion des clients, et les échanges réseau. - Il renvoie les réponses et l’état du jeu à chaque tentative du joueur. - -- **Client** : - Se connecte au serveur, envoie les lettres à deviner, et affiche les retours côté joueur. - ---- - -## 🚀 Versions développées - -| Version | Description | Améliorations clés | -|----------|--------------|--------------------| -| **v1 — Connexion simple** | Création d’un serveur et d’un client basique avec des sockets TCP. | Envoi/réception de messages simples. | -| **v2 — Jeu du pendu intégré** | Intégration de la logique du jeu du pendu côté serveur. | Gestion d’un seul joueur. | -| **v3 — Multi-clients** | Le serveur gère plusieurs clients simultanément. | Utilisation de `select()` ou `fork()`. | -| **v4 — Améliorations réseau** | Amélioration de la robustesse et de la modularité du code. | Meilleure gestion des erreurs, découpage en modules. | - ---- - -## 🧩 Architecture du dépôt - -SAE_Socket/ -├── src/ -│ ├── serveur/ -│ │ ├── serveur_v1.c -│ │ ├── serveur_v2.c -│ │ ├── ... -│ ├── client/ -│ │ ├── client_v1.c -│ │ ├── client_v2.c -│ │ ├── ... -├── include/ -│ ├── fonctions.h -│ ├── constants.h -├── docs/ -│ ├── compte_rendu.pdf -│ ├── diagrammes/ -└── README.md - ---- - -## 🧪 Compilation et exécution - -### Compilation -Utiliser `make` pour compiler les différentes versions : -make serveur_v2 -make client_v2 - -### Exécution -Démarrer d’abord le serveur : -./serveur_v2 -Puis le client dans un autre terminal : -./client_v2 - ---- - -## 👥 Équipe de développement - -Projet réalisé par : -- **[OUTMANI Zinab]** — [S'occupe de la version n°0] -- **[KIME Marwa]** — [S'occupe de la version n°2] -- **[GOBFERT Frédéric]** — [S'occupe de la version n°1] -- **[MOHAMMEDI Selyan]** — [S'occupe de la version n°3] - - -> Encadré par **[M.François Rousselle]**, Département Informatique — IUT de Calais. - ---- - -## 📚 Technologies utilisées - -- **Langage** : C pur -- **Protocoles** : TCP/IP (sockets POSIX) -- **Outils** : GCC, Makefile, Git, Linux terminal - ---- - -## 🧾 Licence - -Projet académique — utilisation libre à des fins pédagogiques. - ---- diff --git a/v3/README_V3.md b/README_V3.md similarity index 54% rename from v3/README_V3.md rename to README_V3.md index fbe009b..08aecd5 100644 --- a/v3/README_V3.md +++ b/README_V3.md @@ -4,10 +4,11 @@ Version 3 du jeu du pendu en réseau. Cette version permet à **2 joueurs** de jouer ensemble, avec la possibilité pour le serveur de gérer **plusieurs parties simultanément** grâce à l'utilisation de `fork()`. +- **Client unique** : Un seul fichier client qui gère automatiquement les deux rôles selon les codes reçus - **Client 1** : Le joueur qui fait deviner (entre le mot secret) - **Client 2** : Le joueur qui devine (propose des lettres) -Le **serveur** fait transiter les messages entre les 2 clients et utilise des processus séparés pour gérer chaque partie en parallèle. +Le **serveur** fait transiter les messages entre les 2 clients et utilise des processus séparés (`fork()`) pour gérer chaque partie en parallèle. ## Architecture @@ -22,6 +23,7 @@ Client 1 (fait deviner) ←→ Serveur (relais + fork) ←→ Client 2 (devi - ✅ **Gestion de plusieurs parties simultanées** : Le serveur peut accepter plusieurs paires de joueurs en même temps - ✅ **Utilisation de `fork()`** : Chaque partie est gérée dans un processus séparé - ✅ **Système de codes de communication** : Messages formatés avec codes pour une meilleure organisation +- ✅ **Client unique** : Un seul fichier client pour les deux rôles (détection automatique) - ✅ **Meilleure gestion des connexions** : Le serveur principal reste disponible pour de nouvelles parties ## Compilation @@ -31,9 +33,8 @@ Client 1 (fait deviner) ←→ Serveur (relais + fork) ←→ Client 2 (devi # Compiler le serveur gcc -o PN_serveur_V3 PN_serveur_V3.c -# Compiler les clients -gcc -o PN_client1_V3 PN_client1_V3.c -gcc -o PN_client2_V3 PN_client2_V3.c +# Compiler le client unique +gcc -o PN_client_V3 PN_client_V3.c ``` ### Windows (avec MinGW ou WSL) : @@ -48,17 +49,17 @@ Même commande dans WSL ou MinGW ### Terminal 2 - Client 1 (fait deviner) : ```bash -./PN_client1_V3 +./PN_client_V3 127.0.0.1 5000 ``` -Le client 1 doit entrer un mot à faire deviner. +Le client 1 reçoit automatiquement le code `2001` (JOUEUR_1_ENTRE_MOT) et doit entrer un mot à faire deviner. ### Terminal 3 - Client 2 (devine) : ```bash -./PN_client2_V3 127.0.0.1 5000 +./PN_client_V3 127.0.0.1 5000 ``` -Le client 2 propose des lettres pour deviner le mot. +Le client 2 reçoit automatiquement le code `2002` (JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER) et peut commencer à proposer des lettres. -**Note** : Vous pouvez lancer plusieurs paires de clients simultanément, le serveur gérera chaque partie dans un processus séparé. +**Note** : Vous pouvez lancer plusieurs paires de clients simultanément, le serveur gérera chaque partie dans un processus séparé grâce à `fork()`. ## Règles du jeu @@ -70,41 +71,41 @@ Le client 2 propose des lettres pour deviner le mot. - Le mot est complètement découvert → **Victoire** - 6 erreurs sont commises → **Défaite** -## Format des messages +## Format des messages (codes) -### Système de codes +Le système utilise des codes numériques pour identifier le type de message : -Les messages sont formatés avec un code suivi de `:` et du contenu : -- Format : `CODE:contenu` +### Codes de communication : +- **2001** : `JOUEUR_1_ENTRE_MOT` - Le serveur demande au Client 1 d'entrer un mot +- **2002** : `JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER` - Le Client 2 reçoit la taille du mot et peut commencer +- **2003** : `JOUEUR_2_PROPOSE_LETTRE` - Le Client 2 propose une lettre +- **2004** : `JOUEUR_1_VALIDE_OU_NON` - Le Client 1 valide ou non la lettre +- **2005** : `JOUEUR_2_RECOIT_VALIDE_OU_NON` - Le Client 2 reçoit la validation +- **2006** : `JOUEUR_2_DONNEES_PARTIE` - Le Client 2 reçoit les données de la partie (mot, erreurs, statut) +- **3001** : `MESSAGE` - Message informatif (ne déclenche aucune action) -### Codes utilisés +### Format des messages : +Les messages sont formatés comme suit : `code:données` -- **2001** (`JOUEUR_1_ENTRE_MOT`) : Le serveur demande au client 1 d'entrer un mot -- **2002** (`JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER`) : Le client 2 reçoit la taille du mot et peut commencer -- **2003** (`JOUEUR_2_PROPOSE_LETTRE`) : Le client 2 propose une lettre -- **2004** (`JOUEUR_1_VALIDE_OU_NON`) : Le client 1 valide ou non la lettre -- **2005** (`JOUEUR_2_RECOIT_VALIDE_OU_NON`) : Le client 2 reçoit la validation -- **2006** (`JOUEUR_2_DONNEES_PARTIE`) : Le client 2 reçoit les données de la partie -- **3001** (`MESSAGE`) : Message informatif (ne déclenche aucune action) - -### Exemples de messages - -- `2001:` → Client 1 doit entrer un mot -- `2002:5` → Client 2 : mot de 5 lettres -- `2003:P` → Client 1 reçoit la lettre "P" -- `2006:oui P__DU 0` → Client 2 : bonne lettre, mot partiel, 0 erreur -- `2006:gagne PENDU 2` → Client 2 : partie gagnée -- `3001:Bienvenue joueur 1 !` → Message informatif +Exemples : +- `2001:` → Demande au Client 1 d'entrer un mot +- `2002:5` → Client 2 reçoit la taille du mot (5 lettres) +- `2003:P` → Client 2 propose la lettre P +- `2006:oui P__DU 0` → Client 2 reçoit les données (oui, mot partiel, 0 erreur) ## Fonctionnalités -- ✅ Communication TCP/IP entre 2 clients via un serveur -- ✅ Gestion de plusieurs parties simultanées avec `fork()` -- ✅ Système de codes pour organiser les communications +- ✅ Communication TCP/IP avec système de codes +- ✅ Gestion multi-parties simultanées avec `fork()` +- ✅ Client unique pour les deux rôles (détection automatique) - ✅ Affichage du pendu ASCII selon le nombre d'erreurs - ✅ Gestion des lettres déjà testées - ✅ Détection automatique de fin de partie -- ✅ Serveur qui reste actif pour plusieurs parties en parallèle +- ✅ Serveur qui reste actif pour plusieurs parties + +## Organigramme + +Un organigramme détaillé de la communication est disponible dans `organigramme_V3.svg`. ## En cas de problème @@ -118,9 +119,9 @@ kill -9 [PID] - Vérifier que le serveur est lancé avant les clients - Vérifier l'IP et le port (127.0.0.1:5000 par défaut) -### Problème de processus : -- Si des processus zombies apparaissent, vérifier que les processus enfants se terminent correctement -- Utiliser `ps aux | grep PN_serveur` pour voir les processus actifs +### Problème avec fork() : +- Vérifier que le système supporte `fork()` (Linux/macOS) +- Sur Windows, utiliser WSL ou MinGW ## Auteur diff --git a/v2/PN_client_V2.c b/v2/PN_client_V2.c deleted file mode 100644 index 8d7ce0d..0000000 --- a/v2/PN_client_V2.c +++ /dev/null @@ -1,396 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LG_MESSAGE 256 -#define MAX_MOT 50 -#define MAX_ERREURS 6 - -// Fonction pour afficher le pendu -void afficher_pendu(int nb_erreurs) { - printf("\n"); - switch(nb_erreurs) { - case 0: - printf(" +---+\n"); - printf(" | |\n"); - printf(" |\n"); - printf(" |\n"); - printf(" |\n"); - printf(" |\n"); - printf("=========\n"); - break; - case 1: - printf(" +---+\n"); - printf(" | |\n"); - printf(" O |\n"); - printf(" |\n"); - printf(" |\n"); - printf(" |\n"); - printf("=========\n"); - break; - case 2: - printf(" +---+\n"); - printf(" | |\n"); - printf(" O |\n"); - printf(" | |\n"); - printf(" |\n"); - printf(" |\n"); - printf("=========\n"); - break; - case 3: - printf(" +---+\n"); - printf(" | |\n"); - printf(" O |\n"); - printf(" /| |\n"); - printf(" |\n"); - printf(" |\n"); - printf("=========\n"); - break; - case 4: - printf(" +---+\n"); - printf(" | |\n"); - printf(" O |\n"); - printf(" /|\\ |\n"); - printf(" |\n"); - printf(" |\n"); - printf("=========\n"); - break; - case 5: - printf(" +---+\n"); - printf(" | |\n"); - printf(" O |\n"); - printf(" /|\\ |\n"); - printf(" / |\n"); - printf(" |\n"); - printf("=========\n"); - break; - case 6: - printf(" +---+\n"); - printf(" | |\n"); - printf(" O |\n"); - printf(" /|\\ |\n"); - printf(" / \\ |\n"); - printf(" |\n"); - printf("=========\n"); - printf(" PERDU !\n"); - break; - default: - break; - } - printf("\n"); -} - -/** - * Client V2 - Peut être Client 1 (fait deviner) ou Client 2 (devine) - * - * Usage: - * ./PN_client_V2 - * role: 1 pour faire deviner, 2 pour deviner - * Exemple: ./PN_client_V2 1 127.0.0.1 5000 (Client 1) - * ./PN_client_V2 2 127.0.0.1 5000 (Client 2) - */ -int main(int argc, char *argv[]){ - int socket_client; - struct sockaddr_in adresseServeur; // Va stocker l'IP, le port et le type d'adresse du serveur - socklen_t longueurAdresse; - char ip_serveur[16]; - int port_serveur; - int role; // 1 = fait deviner, 2 = devine - - // Récupération arguments - if (argc < 4) { - printf("USAGE : %s \n", argv[0]); - printf(" role: 1 pour faire deviner, 2 pour deviner\n"); - printf("Exemple : %s 1 127.0.0.1 5000\n", argv[0]); - printf(" %s 2 127.0.0.1 5000\n", argv[0]); - exit(-1); - } - - // Récupération rôle - sscanf(argv[1], "%d", &role); - if (role != 1 && role != 2) { - printf("Erreur : Veuillez entrer 1 pour faire deviner ou 2 pour deviner\n"); - exit(-1); - } - - // Récupération IP et port - strncpy(ip_serveur, argv[2], 15); - ip_serveur[15] = '\0'; - sscanf(argv[3], "%d", &port_serveur); - - // Création socket AF_INET pour IPv4, SOCK_STREAM pour TCP, 0 pour le protocole par défaut - socket_client = socket(AF_INET, SOCK_STREAM, 0); - if (socket_client < 0) { - perror("Erreur socket"); - exit(-1); - } - printf("Socket créée! (%d)\n", socket_client); - - // Configuration adresse - longueurAdresse = sizeof(adresseServeur); - memset(&adresseServeur, 0x00, longueurAdresse); - adresseServeur.sin_family = AF_INET; - adresseServeur.sin_port = htons(port_serveur); // htons convertit le port format machine en format réseau - if (inet_aton(ip_serveur, &adresseServeur.sin_addr) == 0) { // inet_aton convertit l'IP en format binaire - printf("Adresse IP invalide : %s\n", ip_serveur); - close(socket_client); - exit(-2); - } - - // Connexion - printf("Tentative de connexion à %s:%d...\n", ip_serveur, port_serveur); - if ((connect(socket_client, (struct sockaddr *) &adresseServeur, longueurAdresse)) == -1) { - perror("Erreur connexion"); - close(socket_client); - exit(-3); - } - printf(">>> Connexion réussie!\n\n"); - - // ============================================================ - // CLIENT 1 : Fait deviner le mot - // ============================================================ - if (role == 1) { - char messageRecu[LG_MESSAGE]; - char mot_secret[MAX_MOT]; - char mot_affiche[MAX_MOT]; - char lettres_deja_testees[26] = {0}; - int lus; - int nb_erreurs = 0; - - // Reçoit demande serveur, qui demande le mot à deviner - lus = recv(socket_client, messageRecu, LG_MESSAGE-1, 0); - if (lus <= 0) { - perror("Erreur réception"); - close(socket_client); - exit(-4); - } - // \0 permet de terminer la chaîne de caractères pour éviter les problèmes de dépassement de buffer - messageRecu[lus] = '\0'; - printf("%s", messageRecu); - - // Saisie du mot - scanf("%s", mot_secret); - - // Conversion en majuscules - for(int i = 0; mot_secret[i]; i++) { - mot_secret[i] = toupper((unsigned char)mot_secret[i]); - } - - // Initialisation avec des tirets - int longueur_mot = strlen(mot_secret); - for(int i=0; i= MAX_ERREURS) { - strcpy(status, "perdu"); - partie_terminee = 1; - } else { - strcpy(status, trouve ? "oui" : "non"); - } - - // Envoi de la réponse - if(partie_terminee) { - snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, - partie_terminee && strcmp(status, "perdu") == 0 ? mot_secret : mot_affiche, - nb_erreurs); - } else { - snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, mot_affiche, nb_erreurs); - } - - send(socket_client, messageRecu, strlen(messageRecu)+1, 0); - - if(partie_terminee) { - break; - } - } - } - - // ============================================================ - // CLIENT 2 : Devine le mot - // ============================================================ - else { // role == 2 - char buffer[LG_MESSAGE]; - int octets_lus; - char status[20]; - char mot_decouvert[LG_MESSAGE]; - int nb_erreurs; - - // Réception "start x" - memset(buffer, 0, LG_MESSAGE); - octets_lus = recv(socket_client, buffer, LG_MESSAGE, 0); - if (octets_lus <= 0) { - perror("Erreur réception"); - close(socket_client); - exit(-4); - } - buffer[octets_lus] = '\0'; - - int longueur_mot; - // On attend le message "start x" où x est la longueur du mot à deviner - if (sscanf(buffer, "start %d", &longueur_mot) != 1) { - printf("Message inattendu : %s\n", buffer); - close(socket_client); - exit(-5); - } - - printf("\n===========================================\n"); - printf(" BIENVENUE AU JEU DU PENDU !\n"); - printf("===========================================\n"); - printf("Mot de %d lettres à deviner\n", longueur_mot); - printf("Vous avez droit à 6 erreurs maximum\n"); - printf("===========================================\n\n"); - - // Boucle principale - while (1) { - char lettre; - printf("\nEntrez une lettre : "); - if (scanf(" %c", &lettre) != 1) { - printf("Erreur de saisie\n"); - continue; - } - - // Nettoyage buffer - int c; - int chars_ignores = 0; - // On nettoie le buffer d'entrée pour éviter les problèmes de dépassement de buffer - while ((c = getchar()) != '\n' && c != EOF) { - chars_ignores++; - } - if (chars_ignores > 0) { - printf("⚠ Attention : seule la première lettre a été prise en compte.\n"); - } - - lettre = toupper(lettre); - - if (!isalpha(lettre)) { - printf("Veuillez entrer une lettre valide (A-Z)\n"); - continue; - } - - // Envoi de la lettre - sprintf(buffer, "%c", lettre); - send(socket_client, buffer, strlen(buffer) + 1, 0); - - // Réception réponse - memset(buffer, 0, LG_MESSAGE); - octets_lus = recv(socket_client, buffer, LG_MESSAGE, 0); - if (octets_lus <= 0) { - perror("Erreur réception"); - close(socket_client); - exit(-7); - } - buffer[octets_lus] = '\0'; - - // Parsing - if (sscanf(buffer, "%s %s %d", status, mot_decouvert, &nb_erreurs) != 3) { - printf("Réponse inattendue : %s\n", buffer); - continue; - } - - // Affichage - printf("\n"); - printf("Mot : "); - for (int i = 0; i < strlen(mot_decouvert); i++) { - printf("%c ", mot_decouvert[i]); - } - printf("\n"); - printf("Erreurs : %d/6\n", nb_erreurs); - - afficher_pendu(nb_erreurs); - - if (strcmp(status, "oui") == 0) { - printf("✓ Bonne lettre !\n"); - } else if (strcmp(status, "non") == 0) { - printf("✗ Mauvaise lettre.\n"); - } else if (strcmp(status, "deja") == 0) { - printf("⚠ Lettre déjà choisie. Choisissez-en une autre.\n"); - } else if (strcmp(status, "erreur") == 0) { - printf("⚠ Caractère invalide. Entrez une lettre (A-Z).\n"); - } - - // Fin de partie - if (strcmp(status, "gagne") == 0) { - printf("\n"); - printf("*******************************************\n"); - printf(" FÉLICITATIONS ! VOUS AVEZ GAGNÉ !\n"); - printf(" Le mot était : %s\n", mot_decouvert); - printf(" Nombre d'erreurs : %d\n", nb_erreurs); - printf("*******************************************\n"); - break; - } else if (strcmp(status, "perdu") == 0) { - printf("\n"); - printf("*******************************************\n"); - printf(" DOMMAGE ! VOUS AVEZ PERDU !\n"); - printf(" Le mot était : %s\n", mot_decouvert); - printf("*******************************************\n"); - break; - } - } - } - - close(socket_client); - printf("\nConnexion fermée. Au revoir !\n"); - return 0; -} - diff --git a/v2/PN_serveur_V2.c b/v2/PN_serveur_V2.c deleted file mode 100644 index c538d5d..0000000 --- a/v2/PN_serveur_V2.c +++ /dev/null @@ -1,167 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 5000 -#define LG_MESSAGE 512 -#define MAX_ERREURS 6 -#define MOT_SECRET "PENDU" -#define MAX_MOT 50 - -/** - * Serveur V2 - Fait transiter les messages entre 2 clients - * Client 1 : fait deviner (entre le mot) - * Client 2 : devine (propose des lettres) - */ -int main(int argc, char *argv[]){ - int socketEcoute; - int socket_client_1, socket_client_2; - struct sockaddr_in adresseServeur; - socklen_t longueurAdresse; - struct sockaddr_in adresseClient; - char messageRecu[LG_MESSAGE]; - int lus; - - // Création socket d'écoute - socketEcoute = socket(AF_INET, SOCK_STREAM, 0); - if (socketEcoute < 0) { - perror("socket"); - exit(-1); - } - printf("Socket créée avec succès ! (%d)\n", socketEcoute); - - // Option pour réutiliser le port - int opt = 1; - setsockopt(socketEcoute, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - - // Configuration adresse serveur - longueurAdresse = sizeof(adresseServeur); - memset(&adresseServeur, 0x00, longueurAdresse); - adresseServeur.sin_family = PF_INET; - adresseServeur.sin_addr.s_addr = htonl(INADDR_ANY); - adresseServeur.sin_port = htons(PORT); - - // Bind - if ((bind(socketEcoute, (struct sockaddr *)&adresseServeur, longueurAdresse)) < 0) { - perror("bind"); - exit(-2); - } - printf("Socket attachée avec succès !\n"); - - // Listen - if (listen(socketEcoute, 5) < 0) { - perror("listen"); - exit(-3); - } - printf("Socket placée en écoute passive sur le port %d...\n", PORT); - - // Boucle principale - while (1) { - char buffer[LG_MESSAGE]; - char mot_secret[MAX_MOT]; - int longueur_mot; - - // Attente client 1 - printf("\n=== Attente du premier client ===\n"); - - longueurAdresse = sizeof(adresseClient); - socket_client_1 = accept(socketEcoute, (struct sockaddr *) &adresseClient, &longueurAdresse); - - if (socket_client_1 < 0) { - perror("Erreur accept client 1"); - continue; - } - printf(">>> Client 1 connecté depuis %s:%d\n", inet_ntoa(adresseClient.sin_addr), ntohs(adresseClient.sin_port)); - - // Demander le mot - strcpy(buffer, "Veuillez entrer un mot à deviner : "); - send(socket_client_1, buffer, strlen(buffer) + 1, 0); - printf("Envoyé au client 1 : %s\n", buffer); - - // Recevoir le mot - memset(messageRecu, 0, LG_MESSAGE); - lus = recv(socket_client_1, messageRecu, LG_MESSAGE-1, 0); - if (lus <= 0) { - printf("Le client 1 s'est déconnecté.\n"); - close(socket_client_1); - continue; - } - messageRecu[lus] = '\0'; - printf("Le mot entré par le client 1 : %s\n", messageRecu); - - strncpy(mot_secret, messageRecu, MAX_MOT-1); - mot_secret[MAX_MOT-1] = '\0'; - longueur_mot = strlen(messageRecu); - - // Attente client 2 - printf("\n=== Attente du deuxième client ===\n"); - - longueurAdresse = sizeof(adresseClient); - socket_client_2 = accept(socketEcoute, (struct sockaddr *) &adresseClient, &longueurAdresse); - if (socket_client_2 < 0) { - perror("Erreur accept client 2"); - close(socket_client_1); - continue; - } - printf(">>> Client 2 connecté depuis %s:%d\n", inet_ntoa(adresseClient.sin_addr), ntohs(adresseClient.sin_port)); - - // Envoi "start x" - sprintf(buffer, "start %d", longueur_mot); - send(socket_client_2, buffer, strlen(buffer) + 1, 0); - printf("Envoyé au client 2 : %s\n", buffer); - - // Boucle de transit des messages - printf("\n=== Début de la partie ===\n"); - int partie_en_cours = 1; - while (partie_en_cours) { - // Recevoir lettre du client 2 - memset(messageRecu, 0, LG_MESSAGE); - lus = recv(socket_client_2, messageRecu, LG_MESSAGE-1, 0); - if (lus <= 0) { - printf("Le client 2 s'est déconnecté.\n"); - break; - } - messageRecu[lus] = '\0'; - printf("Reçu du client 2 (lettre) : %s → Transite au client 1\n", messageRecu); - - // Transiter au client 1 - send(socket_client_1, messageRecu, strlen(messageRecu) + 1, 0); - - // Recevoir réponse du client 1 - memset(messageRecu, 0, LG_MESSAGE); - lus = recv(socket_client_1, messageRecu, LG_MESSAGE-1, 0); - if (lus <= 0) { - printf("Le client 1 s'est déconnecté.\n"); - break; - } - messageRecu[lus] = '\0'; - printf("Reçu du client 1 (réponse) : %s → Transite au client 2\n", messageRecu); - - // Transiter au client 2 - send(socket_client_2, messageRecu, strlen(messageRecu) + 1, 0); - - // Vérifier fin de partie - if (strstr(messageRecu, "gagne") != NULL || strstr(messageRecu, "perdu") != NULL) { - printf(">>> Partie terminée !\n"); - partie_en_cours = 0; - } - } - - // Fermeture - close(socket_client_1); - close(socket_client_2); - - printf("\n=== Fin de la partie ===\n"); - printf("Le mot à deviner était : %s\n", mot_secret); - printf("Connexions fermées. Prêt pour une nouvelle partie.\n\n"); - } - - close(socketEcoute); - return 0; -} diff --git a/v2/README_V2.md b/v2/README_V2.md deleted file mode 100644 index 0692ec6..0000000 --- a/v2/README_V2.md +++ /dev/null @@ -1,99 +0,0 @@ -# JEU DU PENDU - Version 2 (V2) - -## Description - -Version 2 du jeu du pendu en réseau. Cette version permet à **2 joueurs** de jouer ensemble : -- **Client 1** : Le joueur qui fait deviner (entre le mot secret) -- **Client 2** : Le joueur qui devine (propose des lettres) - -Le **serveur** fait uniquement transiter les messages entre les 2 clients sans intervenir dans la logique du jeu. - -## Architecture - -``` -Client 1 (fait deviner) ←→ Serveur (relais) ←→ Client 2 (devine) -``` - -## Compilation - -### Linux/macOS : -```bash -# Compiler le serveur -gcc -o PN_serveur_V2 PN_serveur_V2.c - -# Compiler les clients -gcc -o PN_client1_V2 PN_client1_V2.c -gcc -o PN_client2_V2 PN_client2_V2.c -``` - -### Windows (avec MinGW ou WSL) : -Même commande dans WSL ou MinGW - -## Exécution - -### Terminal 1 - Serveur : -```bash -./PN_serveur_V2 -``` - -### Terminal 2 - Client 1 (fait deviner) : -```bash -./PN_client1_V2 -``` -Le client 1 doit entrer un mot à faire deviner. - -### Terminal 3 - Client 2 (devine) : -```bash -./PN_client2_V2 127.0.0.1 5000 -``` -Le client 2 propose des lettres pour deviner le mot. - -## Règles du jeu - -- Le **Client 1** entre un mot secret (maximum 50 caractères) -- Le **Client 2** doit deviner le mot en proposant des lettres -- Maximum d'erreurs : **6** -- Le pendu s'affiche progressivement avec chaque erreur -- La partie se termine quand : - - Le mot est complètement découvert → **Victoire** - - 6 erreurs sont commises → **Défaite** - -## Format des messages - -### Messages envoyés par le serveur : -- `"Veuillez entrer un mot à deviner : "` → Client 1 -- `"start x"` → Client 2 (x = nombre de lettres) - -### Messages entre clients (via le serveur) : -- Client 2 → Client 1 : Lettre proposée (ex: `"P"`) -- Client 1 → Client 2 : Réponse formatée - - `"oui mot_decouvert nb_erreurs"` (ex: `"oui P__DU 0"`) - - `"non mot_decouvert nb_erreurs"` (ex: `"non P__DU 1"`) - - `"deja mot_decouvert nb_erreurs"` (lettre déjà testée) - - `"gagne mot_complet nb_erreurs"` (victoire) - - `"perdu mot_secret nb_erreurs"` (défaite) - -## Fonctionnalités - -- ✅ Communication TCP/IP entre 2 clients via un serveur -- ✅ Affichage du pendu ASCII selon le nombre d'erreurs -- ✅ Gestion des lettres déjà testées -- ✅ Détection automatique de fin de partie -- ✅ Serveur qui reste actif pour plusieurs parties - -## En cas de problème - -### Port déjà utilisé : -```bash -lsof -i :5000 -kill -9 [PID] -``` - -### Erreur de connexion : -- Vérifier que le serveur est lancé avant les clients -- Vérifier l'IP et le port (127.0.0.1:5000 par défaut) - -## Auteur - -Mapbaya - diff --git a/v2/organigramme_V2.svg b/v2/organigramme_V2.svg deleted file mode 100644 index 2542cb4..0000000 --- a/v2/organigramme_V2.svg +++ /dev/null @@ -1,149 +0,0 @@ - - - - Organigramme V2 - Communication Client/Serveur - - - - Client 1 - - - Serveur - - - Client 2 - - - - - - - - - Phase d'initialisation serveur - - - - socket() - - - - bind() - - - - listen() - - - - accept() - En attente Client 1 - - - - Phase d'initialisation Client 1 - - - - socket() - - - - 1. connect() - - - - accept() - Client 1 connecté - - - - 2. "Veuillez entrer un mot à deviner : " - - - - 3. Mot secret - - - - accept() - En attente Client 2 - - - - Phase d'initialisation Client 2 - - - - socket() - - - - 4. connect() - - - - accept() - Client 2 connecté - - - - 5. "start x" - - - - Boucle de jeu - relais des messages - - - - Client 1 vérifie - si lettre dans - le mot - - - - Client 2 affiche - statut mot, - erreurs, pendu - - - - [Boucle jusqu'à fin de partie] - - - - 6. Lettre proposée - - - - 7. Transite la lettre - - - - 8. Réponse formatée - "status mot erreurs" - - - - 9. Transite la réponse - - - - Fin de partie - - - - 10. close() - - - - 11. close() - - - - Serveur retourne à accept() - pour une nouvelle partie - - - - - - - - diff --git a/v3/PN_client1_V3.c b/v3/PN_client1_V3.c deleted file mode 100644 index 4ee4656..0000000 --- a/v3/PN_client1_V3.c +++ /dev/null @@ -1,211 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LG_MESSAGE 256 -#define MAX_MOT 50 -#define MAX_ERREURS 6 - -// Voir définition des codes dans PN_serveur_V3.c - -#define JOUEUR_1_ENTRE_MOT 2001 -#define JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER 2002 -#define JOUEUR_2_PROPOSE_LETTRE 2003 -#define JOUEUR_1_VALIDE_OU_NON 2004 -#define JOUEUR_2_RECOIT_VALIDE_OU_NON 2005 -#define JOUEUR_2_DONNEES_PARTIE 2006 -#define MESSAGE 3001 - -void emit(const int code, const char* buffer, int socket) { - char message[LG_MESSAGE]; - sprintf(message, "%s"/*, code*/, buffer); - send(socket, message, strlen(message), 0); -} - -/** - * Client 1 - Celui qui fait deviner le mot - * Entre le mot secret et vérifie les lettres proposées - */ -int main(int argc, char *argv[]){ - int socket_client; - socklen_t longueurAdresse; - struct sockaddr_in adresseServeur; - char ip_serveur[16]; - int port_serveur; - char status[10]; - char messageRecu[LG_MESSAGE]; - char mot_secret[MAX_MOT]; /** Mot secret à faire deviner */ - char mot_affiche[MAX_MOT]; /** Mot avec lettres découvertes (ex: "P__DU") */ - char lettres_deja_testees[26] = {0}; /** Tableau pour éviter les lettres déjà testées */ - int lus; - int nb_erreurs = 0; - int partie_en_cours = 1; - - int reponse_code; // ex : 2003 - char reponse_message[LG_MESSAGE]; - int longueur_mot; - - // Récupération arguments - if (argc < 3) { - printf("USAGE : %s ip port\n", argv[0]); - printf("Exemple : %s 127.0.0.1 5000\n", argv[0]); - exit(-1); - } - strncpy(ip_serveur, argv[1], 15); - ip_serveur[15] = '\0'; - sscanf(argv[2], "%d", &port_serveur); - - // Création socket - socket_client = socket(AF_INET, SOCK_STREAM, 0); - if (socket_client < 0) { - perror("Erreur socket"); - exit(-1); - } - printf("Socket créée! (%d)\n", socket_client); - - // Configuration adresse - longueurAdresse = sizeof(adresseServeur); - memset(&adresseServeur, 0x00, longueurAdresse); - adresseServeur.sin_family = AF_INET; - adresseServeur.sin_port = htons(port_serveur); - if (inet_aton(ip_serveur, &adresseServeur.sin_addr) == 0) { - printf("Adresse IP invalide : %s\n", ip_serveur); - close(socket_client); - exit(-2); - } - - // Connexion - connect(socket_client, (struct sockaddr*)&adresseServeur, sizeof(adresseServeur)); - - // Boucle principale - while(partie_en_cours) { - lus = recv(socket_client, messageRecu, LG_MESSAGE-1, 0); - if(lus <= 0) break; - - messageRecu[lus] = '\0'; - - /* Récupere les 4 premiers chiffres du message, correspondants au code à interpreter plus bas*/ - if (sscanf(messageRecu, "%4d", &reponse_code) != 1) { // récupére le code - printf("Format de communication non respecté : %s\n", messageRecu); - close(socket_client); - exit(-5); - } - - char *msg = strchr(messageRecu, ':'); - if (msg != NULL) { // récupere le contenu (potentiel) - msg++; // supprime le ':' - strcpy(reponse_message, msg); - } else { - printf("Format de communication non respecté/Erreur sur le contenu : %s\n", messageRecu); - } - - switch(reponse_code){ - case JOUEUR_1_ENTRE_MOT: - printf("Un joueur est arrivé !\nVeuillez entrer le mot à faire deviner : "); - scanf("%s", mot_secret); - - for (int i = 0; mot_secret[i]; i++) - mot_secret[i] = toupper((unsigned char)mot_secret[i]); - - // Initialisation avec des tirets - longueur_mot = strlen(mot_secret); - for(int i=0;i 'Z') { - strcpy(status, "erreur"); - snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, mot_affiche, nb_erreurs); - emit(JOUEUR_2_DONNEES_PARTIE, messageRecu, socket_client); - break; - } - - // Vérification si déjà testée - if (lettres_deja_testees[lettre - 'A']) { - strcpy(status, "deja"); - snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, mot_affiche, nb_erreurs); - emit(JOUEUR_2_DONNEES_PARTIE, messageRecu, socket_client); - break; - } - - // Marquer comme testée - lettres_deja_testees[lettre - 'A'] = 1; - - // Recherche dans le mot - int trouve = 0; - for (int i = 0; i < longueur_mot; i++) { - if (mot_secret[i] == lettre) { - mot_affiche[i] = lettre; - trouve = 1; - } - } - - if (!trouve) - nb_erreurs++; - - // Vérifier mot complet - int mot_complet = 1; - for (int i = 0; i < longueur_mot; i++) { - if (mot_affiche[i] == '_') { - mot_complet = 0; - break; - } - } - - - if (mot_complet) { - strcpy(status, "gagne"); - partie_terminee = 1; - } else if (nb_erreurs >= MAX_ERREURS) { - strcpy(status, "perdu"); - partie_terminee = 1; - } else { - strcpy(status, trouve ? "oui" : "non"); - } - - if(partie_terminee && (strcmp(status, "perdu")|| strcmp(status, "gagne"))) - printf("Le joueur a %s la partie ! Le mot était : %s\n", strcmp(status, "gagne") == 0 ? "gagné" : "perdu", mot_secret); - - - // Envoi réponse - snprintf(messageRecu, LG_MESSAGE, "%s %s %d", - status, - (partie_terminee && strcmp(status, "perdu") == 0) ? mot_secret : mot_affiche, - nb_erreurs); - - emit(JOUEUR_2_DONNEES_PARTIE, messageRecu, socket_client); - - if (partie_terminee) - partie_en_cours = 0; - - - break; - } - case MESSAGE: - printf("%s\n", reponse_message); - break; - default: - printf("Code reçu inconnu : %d\n", reponse_code); - break; - } - } - - close(socket_client); - return 0; -} diff --git a/v3/organigramme_V3.svg b/v3/organigramme_V3.svg deleted file mode 100644 index a71de72..0000000 --- a/v3/organigramme_V3.svg +++ /dev/null @@ -1,55 +0,0 @@ - - -Client 2(devine) -Serveur(fork) -Client 1(fait deviner) -Client 2(devine) -Serveur(fork) -Client 1(fait deviner) - - - - - -Phase d'initialisation (Processus enfant après fork) - - -1. connect() -2. 3001:"Bienvenue joueur 1..." -3. connect() -4. fork() → Processus enfant -5. 3001:"Bienvenue Client 2..." -6. 2001:"" (demande mot) -7. "PENDU" (mot secret) -8. 2002:"5" (taille mot) - - -Boucle de jeu (tant que partie_en_cours = 1) - - -loop[Jusqu'à "gagne" ou "perdu"] - - -9. "P" (lettre) -10. 2003:"P" - - -Vérifie lettredans le mot - -11. 2006:"oui P__DU 0" -12. 2006:"oui P__DU 0" - - -Affiche statut(mot, erreurs) - - -Fin de partie - Processus enfant se termine - - -13. close() -14. close() - - -Processus parentretourne à accept() - - diff --git a/v3/organigramme_V3_pseudocode.txt b/v3/organigramme_V3_pseudocode.txt deleted file mode 100644 index c94b7c0..0000000 --- a/v3/organigramme_V3_pseudocode.txt +++ /dev/null @@ -1,327 +0,0 @@ -═══════════════════════════════════════════════════════════════════════════ - ORGANIGRAMME V3 - EXPLICATION EN PSEUDO-CODE - Jeu du Pendu en Réseau avec Gestion Multi-Parties (fork) -═══════════════════════════════════════════════════════════════════════════ - -┌─────────────────────────────────────────────────────────────────────────┐ -│ SERVEUR PRINCIPAL (Processus Parent) │ -└─────────────────────────────────────────────────────────────────────────┘ - -FONCTION main(): - // Initialisation - socket_ecoute = socket(AF_INET, SOCK_STREAM, 0) - bind(socket_ecoute, port=5000) - listen(socket_ecoute) - - TANT QUE (vrai): - ┌─────────────────────────────────────────────────────────────┐ - │ PHASE 1 : CONNEXION DES CLIENTS │ - └─────────────────────────────────────────────────────────────┘ - - // Attente du premier client - socket_client_1 = accept(socket_ecoute) - ENVOYER(socket_client_1, "3001:Bienvenue joueur 1 ! Attendez...") - - // Attente du deuxième client - socket_client_2 = accept(socket_ecoute) - - ┌─────────────────────────────────────────────────────────────┐ - │ PHASE 2 : CRÉATION DU PROCESSUS ENFANT (fork) │ - └─────────────────────────────────────────────────────────────┘ - - pid = fork() - - SI (pid == 0): - // ─────────────────────────────────────────────────────── - // PROCESSUS ENFANT : Gère une partie - // ─────────────────────────────────────────────────────── - - gerer_partie(socket_client_1, socket_client_2) - - SINON SI (pid > 0): - // ─────────────────────────────────────────────────────── - // PROCESSUS PARENT : Continue à accepter de nouvelles - // connexions pour d'autres parties - // ─────────────────────────────────────────────────────── - - FERMER(socket_client_1) - FERMER(socket_client_2) - // Retourne au début de la boucle pour accepter - // une nouvelle paire de clients - - -┌─────────────────────────────────────────────────────────────────────────┐ -│ FONCTION gerer_partie(socket_client_1, socket_client_2) │ -│ (Exécutée dans le processus enfant) │ -└─────────────────────────────────────────────────────────────────────────┘ - - ┌─────────────────────────────────────────────────────────────────┐ - │ PHASE D'INITIALISATION │ - └─────────────────────────────────────────────────────────────────┘ - - // Accueil du client 2 - ENVOYER(socket_client_2, "3001:Bienvenue Client 2 !...") - - // Demande au client 1 d'entrer un mot - ENVOYER(socket_client_1, "2001:") - - // Réception du mot secret - mot_secret = RECEVOIR(socket_client_1) - longueur_mot = longueur(mot_secret) - - // Informe le client 2 de la taille du mot - ENVOYER(socket_client_2, "2002:" + longueur_mot) - - // Informe le client 1 que le jeu commence - ENVOYER(socket_client_1, "3001:Le joueur 2 devine...") - - ┌─────────────────────────────────────────────────────────────────┐ - │ BOUCLE DE JEU │ - └─────────────────────────────────────────────────────────────────┘ - - partie_en_cours = vrai - - TANT QUE (partie_en_cours): - ┌─────────────────────────────────────────────────────────┐ - │ ÉTAPE 1 : Client 2 propose une lettre │ - └─────────────────────────────────────────────────────────┘ - - lettre = RECEVOIR(socket_client_2) - // Exemple: lettre = "P" - - ┌─────────────────────────────────────────────────────────┐ - │ ÉTAPE 2 : Transmettre la lettre au Client 1 │ - └─────────────────────────────────────────────────────────┘ - - ENVOYER(socket_client_1, "2003:" + lettre) - - ┌─────────────────────────────────────────────────────────┐ - │ ÉTAPE 3 : Client 1 vérifie la lettre │ - │ (dans le code du Client 1) │ - └─────────────────────────────────────────────────────────┘ - - // Le Client 1 reçoit "2003:P" - // Il vérifie si "P" est dans le mot secret - // Il met à jour mot_affiche et nb_erreurs - // Il prépare la réponse - - ┌─────────────────────────────────────────────────────────┐ - │ ÉTAPE 4 : Client 1 envoie la réponse │ - └─────────────────────────────────────────────────────────┘ - - reponse = RECEVOIR(socket_client_1) - // Exemple: reponse = "2006:oui P__DU 0" - // ou: reponse = "2006:non P__DU 1" - // ou: reponse = "2006:gagne PENDU 2" - // ou: reponse = "2006:perdu PENDU 6" - - ┌─────────────────────────────────────────────────────────┐ - │ ÉTAPE 5 : Transmettre la réponse au Client 2 │ - └─────────────────────────────────────────────────────────┘ - - ENVOYER(socket_client_2, reponse) - // Le Client 2 affiche le statut, le mot partiel, - // le nombre d'erreurs et le pendu - - ┌─────────────────────────────────────────────────────────┐ - │ ÉTAPE 6 : Vérifier fin de partie │ - └─────────────────────────────────────────────────────────┘ - - SI (reponse contient "gagne" OU reponse contient "perdu"): - partie_en_cours = faux - SINON: - // Le Client 2 propose une nouvelle lettre - // Retour à l'ÉTAPE 1 - - ┌─────────────────────────────────────────────────────────────────┐ - │ FIN DE PARTIE │ - └─────────────────────────────────────────────────────────────────┘ - - FERMER(socket_client_1) - FERMER(socket_client_2) - QUITTER() // Le processus enfant se termine - - -┌─────────────────────────────────────────────────────────────────────────┐ -│ CLIENT 1 (Fait deviner le mot) │ -└─────────────────────────────────────────────────────────────────────────┘ - -FONCTION main(): - // Connexion au serveur - socket = connect("127.0.0.1", 5000) - - TANT QUE (partie_en_cours): - message = RECEVOIR(socket) - code, donnees = PARSER(message) // Format: "CODE:données" - - SELON code: - CAS "2001": // JOUEUR_1_ENTRE_MOT - AFFICHER("Veuillez entrer un mot à faire deviner : ") - mot_secret = LIRE_ENTREE() - ENVOYER(socket, mot_secret) - // Initialiser mot_affiche avec des tirets - mot_affiche = "_" * longueur(mot_secret) - nb_erreurs = 0 - - CAS "2003": // JOUEUR_2_PROPOSE_LETTRE - lettre = donnees[0] // Exemple: "P" - - // Vérifier si la lettre est valide - SI (lettre n'est pas une lettre): - reponse = "2006:erreur " + mot_affiche + " " + nb_erreurs - ENVOYER(socket, reponse) - CONTINUER - - // Vérifier si déjà testée - SI (lettre déjà testée): - reponse = "2006:deja " + mot_affiche + " " + nb_erreurs - ENVOYER(socket, reponse) - CONTINUER - - // Marquer comme testée - lettres_testees[lettre] = vrai - - // Chercher la lettre dans le mot - trouve = faux - POUR chaque position i dans mot_secret: - SI (mot_secret[i] == lettre): - mot_affiche[i] = lettre - trouve = vrai - - // Mettre à jour le nombre d'erreurs - SI (NON trouve): - nb_erreurs = nb_erreurs + 1 - - // Vérifier fin de partie - SI (mot_affiche ne contient plus de "_"): - status = "gagne" - partie_en_cours = faux - SINON SI (nb_erreurs >= 6): - status = "perdu" - partie_en_cours = faux - SINON: - status = (trouve ? "oui" : "non") - - // Préparer la réponse - SI (partie_terminee ET status == "perdu"): - mot_a_afficher = mot_secret - SINON: - mot_a_afficher = mot_affiche - - reponse = "2006:" + status + " " + mot_a_afficher + " " + nb_erreurs - ENVOYER(socket, reponse) - - CAS "3001": // MESSAGE - AFFICHER(donnees) - - AUTRE: - AFFICHER("Code inconnu: " + code) - - FERMER(socket) - - -┌─────────────────────────────────────────────────────────────────────────┐ -│ CLIENT 2 (Devine le mot) │ -└─────────────────────────────────────────────────────────────────────────┘ - -FONCTION main(): - // Connexion au serveur - socket = connect("127.0.0.1", 5000) - - partie_en_cours = vrai - - TANT QUE (partie_en_cours): - message = RECEVOIR(socket) - code, donnees = PARSER(message) // Format: "CODE:données" - - SELON code: - CAS "2002": // JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER - longueur_mot = ENTIER(donnees) - AFFICHER("Bienvenue au jeu du pendu !") - AFFICHER("Mot de " + longueur_mot + " lettres à deviner") - AFFICHER("Vous avez droit à 6 erreurs maximum") - // Proposer une première lettre - proposer_lettre(socket) - - CAS "2006": // JOUEUR_2_DONNEES_PARTIE - status, mot_decouvert, nb_erreurs = PARSER_DONNEES(donnees) - // Exemple: "oui P__DU 0" - - // Afficher le statut - SELON status: - CAS "oui": - AFFICHER("✓ Bonne lettre !") - CAS "non": - AFFICHER("✗ Mauvaise lettre.") - CAS "deja": - AFFICHER("⚠ Lettre déjà choisie.") - CAS "erreur": - AFFICHER("⚠ Caractère invalide.") - - // Afficher le mot partiel - AFFICHER("Mot : " + mot_decouvert) - AFFICHER("Erreurs : " + nb_erreurs + "/6") - - // Afficher le pendu - AFFICHER_PENDU(nb_erreurs) - - // Vérifier fin de partie - SI (status == "gagne"): - AFFICHER("FÉLICITATIONS ! VOUS AVEZ GAGNÉ !") - AFFICHER("Le mot était : " + mot_decouvert) - partie_en_cours = faux - SINON SI (status == "perdu"): - AFFICHER("DOMMAGE ! VOUS AVEZ PERDU !") - AFFICHER("Le mot était : " + mot_decouvert) - partie_en_cours = faux - SINON: - // Proposer une nouvelle lettre - proposer_lettre(socket) - - CAS "3001": // MESSAGE - AFFICHER(donnees) - - AUTRE: - AFFICHER("Code inconnu: " + code) - - FERMER(socket) - - -FONCTION proposer_lettre(socket): - AFFICHER("Entrez une lettre : ") - lettre = LIRE_ENTREE() - lettre = MAJUSCULE(lettre) - ENVOYER(socket, lettre) - - -═══════════════════════════════════════════════════════════════════════════ - RÉSUMÉ DU FLUX -═══════════════════════════════════════════════════════════════════════════ - -1. Serveur accepte Client 1 → envoie message d'accueil -2. Serveur accepte Client 2 → fait fork() -3. Processus enfant gère la partie : - a. Demande mot au Client 1 - b. Reçoit le mot secret - c. Informe Client 2 de la taille - d. Boucle de jeu : - - Client 2 propose lettre - - Serveur transmet à Client 1 - - Client 1 vérifie et répond - - Serveur transmet réponse à Client 2 - - Répète jusqu'à fin de partie -4. Processus parent retourne à accept() pour nouvelle partie - -═══════════════════════════════════════════════════════════════════════════ - CODES DE COMMUNICATION -═══════════════════════════════════════════════════════════════════════════ - -Format: "CODE:données" - -2001 → Client 1 : Demande d'entrer un mot -2002 → Client 2 : Taille du mot (ex: "2002:5") -2003 → Client 1 : Lettre proposée (ex: "2003:P") -2006 → Client 2 : Données partie (ex: "2006:oui P__DU 0") -3001 → Client(s) : Message informatif - -═══════════════════════════════════════════════════════════════════════════ From 201bf200ff3c851eeab3822a23565fe9ed4f5eda Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:15:11 +0100 Subject: [PATCH 04/19] Ajout organigramme V3 dans le style V2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Organigramme détaillé de la communication V3 - Représentation du fork() et des processus enfants - Codes de communication (2001-2006, 3001) - Même style visuel que l'organigramme V2 --- organigramme_V3.svg | 181 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 organigramme_V3.svg diff --git a/organigramme_V3.svg b/organigramme_V3.svg new file mode 100644 index 0000000..40128d8 --- /dev/null +++ b/organigramme_V3.svg @@ -0,0 +1,181 @@ + + + + Organigramme V3 - Communication Client/Serveur avec fork() + + + + Client 1 + + + Serveur + + + Client 2 + + + + + + + + + Phase d'initialisation serveur + + + + socket() + + + + bind() + + + + listen() + + + + accept() - En attente Client 1 + + + + Phase d'initialisation Client 1 + + + + socket() + + + + 1. connect() + + + + accept() - Client 1 connect + + + + 2. 3001: Bienvenue joueur 1 + + + + accept() - En attente Client 2 + + + + Phase d'initialisation Client 2 + + + + socket() + + + + 3. connect() + + + + accept() - Client 2 connect + + + + fork() - Cration processus enfant + Le parent retourne accept() + + + + Processus enfant gre la partie + + + + 4. 3001: Bienvenue Client 2 + + + + 5. 2001: Entrez un mot + + + + 6. Mot secret + + + + 7. 2002: Taille du mot + + + + 8. 3001: Le joueur 2 devine + + + + Boucle de jeu - relais des messages avec codes + + + + Client 1 vrifie + si lettre dans + le mot + + + + Client 2 affiche + statut mot, + erreurs, pendu + + + + [Boucle jusqu' fin de partie] + + + + 9. 2003: Lettre propose + + + + 10. 2003: Transite la lettre + + + + 11. 2006: Rponse formate + status mot erreurs + + + + 12. 2006: Transite la rponse + + + + Fin de partie + + + + 13. close() + + + + 14. close() + + + + Processus enfant se termine + Le parent peut accepter + de nouvelles parties + + + + Codes de communication + 2001: JOUEUR_1_ENTRE_MOT + 2002: JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER + 2003: JOUEUR_2_PROPOSE_LETTRE + 2006: JOUEUR_2_DONNEES_PARTIE + 3001: MESSAGE + Format: code:donnes + + + + + + + + From 9801652a238b5d6acf56cfdfa0629cd117c33fff Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:24:22 +0100 Subject: [PATCH 05/19] =?UTF-8?q?Correction=20encodage=20UTF-8=20et=20?= =?UTF-8?q?=C3=A9tape=2013=20close()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Correction de tous les caractères accentués (é, à, è) - Étape 13 : les deux clients ferment leur connexion (pas seulement Client 1) - Encodage UTF-8 correct pour l'affichage des accents --- organigramme_V3.svg | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/organigramme_V3.svg b/organigramme_V3.svg index 40128d8..f2cb52f 100644 --- a/organigramme_V3.svg +++ b/organigramme_V3.svg @@ -52,7 +52,7 @@ - accept() - Client 1 connect + accept() - Client 1 connecté @@ -76,22 +76,22 @@ - accept() - Client 2 connect + accept() - Client 2 connecté - fork() - Cration processus enfant - Le parent retourne accept() + fork() - Création processus enfant + Le parent retourne à accept() - Processus enfant gre la partie + Processus enfant gère la partie 4. 3001: Bienvenue Client 2 - + 5. 2001: Entrez un mot @@ -99,11 +99,11 @@ 6. Mot secret - + 7. 2002: Taille du mot - + 8. 3001: Le joueur 2 devine @@ -113,7 +113,7 @@ - Client 1 vrifie + Client 1 vérifie si lettre dans le mot @@ -125,24 +125,24 @@ - [Boucle jusqu' fin de partie] + [Boucle jusqu'à fin de partie] - 9. 2003: Lettre propose + 9. 2003: Lettre proposée 10. 2003: Transite la lettre - + - 11. 2006: Rponse formate + 11. 2006: Réponse formatée status mot erreurs - + - 12. 2006: Transite la rponse + 12. 2006: Transite la réponse @@ -154,7 +154,7 @@ - 14. close() + 13. close() @@ -162,7 +162,7 @@ Le parent peut accepter de nouvelles parties - + Codes de communication 2001: JOUEUR_1_ENTRE_MOT @@ -170,9 +170,9 @@ 2003: JOUEUR_2_PROPOSE_LETTRE 2006: JOUEUR_2_DONNEES_PARTIE 3001: MESSAGE - Format: code:donnes + Format: code:données - + From d3a21010c885de718350df2bb18ae2f4d07ca289 Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:26:37 +0100 Subject: [PATCH 06/19] =?UTF-8?q?Correction=20=C3=A9tape=2013=20:=20close(?= =?UTF-8?q?)=20c=C3=B4t=C3=A9=20clients=20uniquement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Chaque client ferme sa propre connexion (action locale) - Les flèches sont remplacées par des blocs locaux - Le serveur ferme aussi ses sockets mais c'est une action interne --- organigramme_V3.svg | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/organigramme_V3.svg b/organigramme_V3.svg index f2cb52f..55d4932 100644 --- a/organigramme_V3.svg +++ b/organigramme_V3.svg @@ -149,18 +149,19 @@ Fin de partie - - 13. close() + + 13. close() - - 13. close() + + 13. close() - - Processus enfant se termine - Le parent peut accepter - de nouvelles parties + + Processus enfant ferme + ses sockets et se termine + Le parent peut accepter + de nouvelles parties From ec292712b177438e030782198cbdc0441760ffa8 Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:42:25 +0100 Subject: [PATCH 07/19] =?UTF-8?q?Correction=20=C3=A9tape=208=20et=20r?= =?UTF-8?q?=C3=A9duction=20taille=20pour=20PDF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Étape 8 : texte repositionné à gauche (vers Client 1) - Réduction des espacements verticaux - ViewBox ajusté à 1750 pour PDF - Boucle de jeu compressée (240 au lieu de 300) - Légende repositionnée --- organigramme_V3.svg | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/organigramme_V3.svg b/organigramme_V3.svg index 55d4932..bc37353 100644 --- a/organigramme_V3.svg +++ b/organigramme_V3.svg @@ -1,5 +1,5 @@ - + Organigramme V3 - Communication Client/Serveur avec fork() @@ -14,9 +14,9 @@ Client 2 - - - + + + @@ -105,7 +105,7 @@ - 8. 3001: Le joueur 2 devine + 8. 3001: Le joueur 2 devine @@ -165,13 +165,13 @@ - Codes de communication - 2001: JOUEUR_1_ENTRE_MOT - 2002: JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER - 2003: JOUEUR_2_PROPOSE_LETTRE - 2006: JOUEUR_2_DONNEES_PARTIE - 3001: MESSAGE - Format: code:données + Codes de communication + 2001: JOUEUR_1_ENTRE_MOT + 2002: JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER + 2003: JOUEUR_2_PROPOSE_LETTRE + 2006: JOUEUR_2_DONNEES_PARTIE + 3001: MESSAGE + Format: code:données From d56474d5345781bae81450939f5b9f478854af9d Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:46:18 +0100 Subject: [PATCH 08/19] =?UTF-8?q?Simplification=20fin=20de=20diagramme=20-?= =?UTF-8?q?=20suppression=20l=C3=A9gende=20d=C3=A9taill=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Suppression de la légende détaillée des codes - Note processus enfant simplifiée - ViewBox réduit à 1650 pour PDF - Diagramme plus compact --- organigramme_V3.svg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/organigramme_V3.svg b/organigramme_V3.svg index bc37353..2983f8b 100644 --- a/organigramme_V3.svg +++ b/organigramme_V3.svg @@ -1,5 +1,5 @@ - + Organigramme V3 - Communication Client/Serveur avec fork() @@ -14,9 +14,9 @@ Client 2 - - - + + + From 8906af101195a81878d6a413be641cb379a3854a Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:46:37 +0100 Subject: [PATCH 09/19] =?UTF-8?q?Suppression=20compl=C3=A8te=20de=20la=20l?= =?UTF-8?q?=C3=A9gende=20d=C3=A9taill=C3=A9e=20des=20codes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Légende des codes supprimée (trop de détails) - ViewBox réduit à 1630 - Diagramme plus simple et compact pour PDF --- organigramme_V3.svg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/organigramme_V3.svg b/organigramme_V3.svg index 2983f8b..88cd0a4 100644 --- a/organigramme_V3.svg +++ b/organigramme_V3.svg @@ -1,5 +1,5 @@ - + Organigramme V3 - Communication Client/Serveur avec fork() @@ -14,9 +14,9 @@ Client 2 - - - + + + From b0780cdfdb7a8faf5f7e4437f45344364f3cbb42 Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:46:49 +0100 Subject: [PATCH 10/19] =?UTF-8?q?Suppression=20d=C3=A9finitive=20de=20la?= =?UTF-8?q?=20l=C3=A9gende=20d=C3=A9taill=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Légende des codes complètement supprimée - Note processus enfant simplifiée (2 lignes au lieu de 4) - Diagramme plus épuré --- organigramme_V3.svg | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/organigramme_V3.svg b/organigramme_V3.svg index 88cd0a4..5018441 100644 --- a/organigramme_V3.svg +++ b/organigramme_V3.svg @@ -157,21 +157,9 @@ 13. close() - - Processus enfant ferme - ses sockets et se termine - Le parent peut accepter - de nouvelles parties - - - - Codes de communication - 2001: JOUEUR_1_ENTRE_MOT - 2002: JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER - 2003: JOUEUR_2_PROPOSE_LETTRE - 2006: JOUEUR_2_DONNEES_PARTIE - 3001: MESSAGE - Format: code:données + + Processus enfant se termine + Le parent accepte nouvelles parties From 182db481aa7075affd9fe70eb287bfb2c583fe8d Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:49:24 +0100 Subject: [PATCH 11/19] =?UTF-8?q?Suppression=20des=20codes=20num=C3=A9riqu?= =?UTF-8?q?es=20dans=20toutes=20les=20=C3=A9tapes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Codes 2001, 2002, 2003, 2006, 3001 supprimés - Messages simplifiés (ex: '5. Entrez un mot' au lieu de '5. 2001: Entrez un mot') - Titre boucle de jeu simplifié --- organigramme_V3.svg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/organigramme_V3.svg b/organigramme_V3.svg index 5018441..e1d972e 100644 --- a/organigramme_V3.svg +++ b/organigramme_V3.svg @@ -56,7 +56,7 @@ - 2. 3001: Bienvenue joueur 1 + 2. Bienvenue joueur 1 @@ -93,7 +93,7 @@ - 5. 2001: Entrez un mot + 5. Entrez un mot @@ -105,7 +105,7 @@ - 8. 3001: Le joueur 2 devine + 8. Le joueur 2 devine @@ -129,7 +129,7 @@ - 9. 2003: Lettre proposée + 9. Lettre proposée From f232fda59c5c4ddd267ffa96d7627dccf6a7a6ad Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:53:29 +0100 Subject: [PATCH 12/19] =?UTF-8?q?Correction=20finale=20:=20suppression=20c?= =?UTF-8?q?odes=20=C3=A9tapes=204,=207=20et=2011?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Étape 4 : '4. Bienvenue Client 2' (sans 3001) - Étape 7 : '7. Taille du mot' (sans 2002) - Étape 11 : '11. Réponse formatée' (sans 2006) - Titre boucle corrigé --- organigramme_V3.svg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/organigramme_V3.svg b/organigramme_V3.svg index e1d972e..a830239 100644 --- a/organigramme_V3.svg +++ b/organigramme_V3.svg @@ -101,7 +101,7 @@ - 7. 2002: Taille du mot + 7. Taille du mot @@ -133,7 +133,7 @@ - 10. 2003: Transite la lettre + 10. Transite la lettre @@ -142,7 +142,7 @@ - 12. 2006: Transite la réponse + 12. Transite la réponse From e0b7242c350d8ab46a4b1c2d69c7c5710f3ad215 Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 21:55:12 +0100 Subject: [PATCH 13/19] =?UTF-8?q?Correction=20=C3=A9tape=204=20:=20suppres?= =?UTF-8?q?sion=20code=203001?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Étape 4 : '4. Bienvenue Client 2' (sans 3001:) --- organigramme_V3.svg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/organigramme_V3.svg b/organigramme_V3.svg index a830239..30cdd4b 100644 --- a/organigramme_V3.svg +++ b/organigramme_V3.svg @@ -109,7 +109,7 @@ - Boucle de jeu - relais des messages avec codes + Boucle de jeu - relais des messages @@ -137,7 +137,7 @@ - 11. 2006: Réponse formatée + 11. Réponse formatée status mot erreurs From abfff8c90c7d754c8df9239f1a56787b82e201ad Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 22:05:08 +0100 Subject: [PATCH 14/19] =?UTF-8?q?Mise=20=C3=A0=20jour=20organigramme=20V3?= =?UTF-8?q?=20final?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- organigramme_V3.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/organigramme_V3.svg b/organigramme_V3.svg index 30cdd4b..b3be41b 100644 --- a/organigramme_V3.svg +++ b/organigramme_V3.svg @@ -89,7 +89,7 @@ - 4. 3001: Bienvenue Client 2 + 4. Bienvenue Client 2 From 027f3baef81c00edd1d0bf75bbc0deb14c812642 Mon Sep 17 00:00:00 2001 From: Gretchen Date: Tue, 16 Dec 2025 22:05:09 +0100 Subject: [PATCH 15/19] Remplacement SVG par PDF pour organigramme V3 --- organigramme_V3.pdf | Bin 0 -> 21549 bytes organigramme_V3.svg | 170 -------------------------------------------- 2 files changed, 170 deletions(-) create mode 100644 organigramme_V3.pdf delete mode 100644 organigramme_V3.svg diff --git a/organigramme_V3.pdf b/organigramme_V3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..58901024b4c18d9dca3b8586c085f9c70e9ecac9 GIT binary patch literal 21549 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

dz*k5v?6sqr7Dcd(9K9kX#EJld@?_ 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 - - - Organigramme V3 - Communication Client/Serveur avec fork() - - - - Client 1 - - - Serveur - - - Client 2 - - - - - - - - - Phase d'initialisation serveur - - - - socket() - - - - bind() - - - - listen() - - - - accept() - En attente Client 1 - - - - Phase d'initialisation Client 1 - - - - socket() - - - - 1. connect() - - - - accept() - Client 1 connecté - - - - 2. Bienvenue joueur 1 - - - - accept() - En attente Client 2 - - - - Phase d'initialisation Client 2 - - - - socket() - - - - 3. connect() - - - - accept() - Client 2 connecté - - - - fork() - Création processus enfant - Le parent retourne à accept() - - - - Processus enfant gère la partie - - - - 4. Bienvenue Client 2 - - - - 5. Entrez un mot - - - - 6. Mot secret - - - - 7. Taille du mot - - - - 8. Le joueur 2 devine - - - - Boucle de jeu - relais des messages - - - - Client 1 vérifie - si lettre dans - le mot - - - - Client 2 affiche - statut mot, - erreurs, pendu - - - - [Boucle jusqu'à fin de partie] - - - - 9. Lettre proposée - - - - 10. Transite la lettre - - - - 11. Réponse formatée - status mot erreurs - - - - 12. Transite la réponse - - - - Fin de partie - - - - 13. close() - - - - 13. close() - - - - Processus enfant se termine - Le parent accepte nouvelles parties - - - - - - - - From a3c19de0f955e6214e0ec4b01d9b2371cdc2775d Mon Sep 17 00:00:00 2001 From: Mapbaya <159463438+Mapbaya@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:07:58 +0100 Subject: [PATCH 16/19] Rename README_V3.md to README.md --- README_V3.md => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README_V3.md => README.md (100%) diff --git a/README_V3.md b/README.md similarity index 100% rename from README_V3.md rename to README.md From 66e498672fc4a77d393ec6ad1c1c344182a6690c Mon Sep 17 00:00:00 2001 From: Zinab Date: Wed, 17 Dec 2025 09:48:14 +0100 Subject: [PATCH 17/19] version plus ameliorer Refactor player letter selection to accept both letters and words, improving input handling and validation. --- PN_client_V3.c | 252 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 201 insertions(+), 51 deletions(-) diff --git a/PN_client_V3.c b/PN_client_V3.c index e16668e..450b2ef 100644 --- a/PN_client_V3.c +++ b/PN_client_V3.c @@ -1,3 +1,124 @@ +__ Zinab__ 🎀 +zinab9191 +Invisible + +Caradoc — 12/11/25, 3:15 PM +Vous gérer le dépôt sur Moodle? +Мудрый — 12/11/25, 3:35 PM +D'accord merci! Oui on s'en occupe +Selyan — 12/12/25, 3:13 PM +Vous faites du télé travail ? +Мудрый — 12/12/25, 3:53 PM +Oui! +Selyan — 12/12/25, 4:09 PM +Synave a fait l'appel ce matin +Jsp si il fait que pour mon td +Мудрый — 12/12/25, 4:18 PM +Sûrement .. +Merci d'avoir prévenu +Selyan — 12/13/25, 3:15 PM +Qui s'occupe de la v4? +Je suis toujours sur la v3 (que je vais terminer aujourd'hui normalement), il me manquera le (diagramme) à faire +Caradoc — 12/13/25, 3:16 PM +Moi je suis toujours sur la V1, je pense avoir fini aujourdhui ou demain matin selon les galères. +Selyan — 12/13/25, 3:18 PM +Pour te dire j'ai commencé à vraiment travailler hier soir, j'ai pas réussi dans la semaine +Entre les changements de salle, les horaires décalés, les cours en même temps surtout +Mais ducoup là j'ai changé quasiment tout le code, je fais le travail que je devais faire en 3/4j en 1 journée max +Caradoc — 12/13/25, 3:22 PM +ok pas de soucis, moi j'ai travaillé dessus hier et depuis ce matin. Mais je ne suis pas dispo en fin d'aprem donc peut être plutôt demain matin du coup. +Selyan — 12/13/25, 9:03 PM +J'ai terminé la v3 (elle fonctionne). Dites moi si vous voulez le code maintenant ou plutôt attendre lundi pour tester +Мудрый — 12/14/25, 12:09 AM +Je vais la commencer demain +Мудрый — 12/14/25, 12:10 AM +Tu peux la push sur une branche V3 sur GitHub ? +Selyan — 12/14/25, 10:39 PM +j'ai pas vu le message déso ! +Concernant github je galère pas mal avec git, tu penses pouvoir le faire si je te donne les fichiers ? +Мудрый — 12/14/25, 10:39 PM +Oui pas de soucis! +Selyan — 12/15/25, 8:47 AM +Vous êtes en quelle salle? +Мудрый — 12/15/25, 8:48 AM +136 +Selyan — 12/15/25, 9:51 AM +Antigouvernementalisation +Selyan — 12/15/25, 3:46 PM +Image +Caradoc — 12/15/25, 3:46 PM +cest de la SAE ça? +Мудрый — 12/15/25, 3:46 PM +Oui😂 +Selyan — 12/15/25, 3:46 PM +Oui +Selyan — Yesterday at 10:56 AM +je vais adapter mon code pour qu'il fonctionne seul, je devrais terminer d'ici 16h max +__ Zinab__ 🎀 + + — Yesterday at 6:10 PM +Salut everybody !! +on est d'accord pour la presentation oral de demain , on devrai presenter le code de la V4 , ainsi une demo , et le diagramme +Selyan — Yesterday at 6:25 PM +Il me semble oui +Qu'en est il de celle-ci? +Мудрый — Yesterday at 6:38 PM +Oui normalement +Мудрый — Yesterday at 6:39 PM +Elle devrait être finie +T'as fini la v3? +Selyan — Yesterday at 6:39 PM +Ça fonctionne +J'ai pas eu grand chose à modifier grâce à mon système mis en place +Мудрый — Yesterday at 6:41 PM +Tu peux envoyer les fichiers sur ⁠🔗・v3 je vais les push github +Selyan — Yesterday at 7:53 PM +c'est fait. Je te conseille de compiler et de tester vite fait +Selyan — Yesterday at 11:07 PM +Demain matin : compte-rendu verification du fonctionnement du 4 ? +Мудрый — Yesterday at 11:08 PM +oui +__ Zinab__ 🎀 + + — 8:33 AM +Êtes vous à l'IUT +? +Selyan — 8:34 AM +Non, me suis réveillé ya 20m .. j'ai raté mon premier réveil +Caradoc — 8:34 AM +Oui mais en cours 😕 +Selyan — 8:53 AM +@Мудрый vous êtes en quelle salle ? +__ Zinab__ 🎀 + + — 8:54 AM +Moi je suis en biblio +Selyan — 8:54 AM +Marwa est pas avec toi? +__ Zinab__ 🎀 + + — 8:54 AM +Je pense pas que Marwa est là ? +Selyan — 9:47 AM +#include +#include +#include +#include +#include +#include +Expand +PN_client_V3.c +14 KB +#include +#include +#include +#include +#include +#include +Expand +PN_serveur_V3.c +8 KB + #include #include #include @@ -15,7 +136,7 @@ // Voir définition des codes dans PN_serveur_V3.c #define JOUEUR_1_ENTRE_MOT 2001 #define JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER 2002 -#define JOUEUR_2_PROPOSE_LETTRE 2003 +#define JOUEUR_2_PROPOSE_LETTRE_OU_MOT 2003 #define JOUEUR_1_VALIDE_OU_NON 2004 #define JOUEUR_2_RECOIT_VALIDE_OU_NON 2005 #define JOUEUR_2_DONNEES_PARTIE 2006 @@ -101,32 +222,44 @@ void afficher_pendu(int nb_erreurs) { printf("\n"); } -void joueur_choisi_lettre(int socket_client) { - char lettre[2]; - printf("\nEntrez une lettre : "); - if (scanf(" %c", &lettre[0]) != 1) { +void joueur_choisi_lettre(int socket_client, int taille_mot) { + char buffer[1024]; // taille raisonnable côté saisie + + printf("\nEntrez une lettre ou un mot : "); + + if (fgets(buffer, sizeof(buffer), stdin) == NULL) { printf("Erreur de saisie, réessayez.\n"); - joueur_choisi_lettre(socket_client); + joueur_choisi_lettre(socket_client, taille_mot); + return; } - int c; - int chars_ignores = 0; - while ((c = getchar()) != '\n' && c != EOF) { - chars_ignores++; - } - if (chars_ignores > 0) { - printf("⚠ Attention : seule la première lettre a été prise en compte.\n"); + // Supprime '\n' + buffer[strcspn(buffer, "\n")] = '\0'; + + size_t len = strlen(buffer); + + if (len == 0) { + printf("Veuillez entrer au moins un caractère.\n"); + joueur_choisi_lettre(socket_client, taille_mot); + return; } - - lettre[0] = toupper(lettre[0]); - if (!isalpha(lettre[0])) { - printf("Veuillez entrer une lettre valide (A-Z)\n"); - joueur_choisi_lettre(socket_client); + if (len > taille_mot) { + printf("Mot trop long.\n"); + joueur_choisi_lettre(socket_client, taille_mot); return; - } + } + + // Vérification pour que ce soit uniquement des lettres + for (size_t i = 0; i < len; i++) { + if (!isalpha((unsigned char)buffer[i])) { + printf("Uniquement des lettres (A-Z).\n"); + return; + } + buffer[i] = toupper(buffer[i]); + } - emit(JOUEUR_2_PROPOSE_LETTRE, lettre, socket_client); + emit(JOUEUR_2_PROPOSE_LETTRE_OU_MOT, buffer, socket_client); // envoi au serveur } /** @@ -224,44 +357,59 @@ int main(int argc, char *argv[]){ mot_affiche[longueur_mot] = '\0'; send(socket_client, mot_secret, longueur_mot, 0); break; - case JOUEUR_2_PROPOSE_LETTRE: { + case JOUEUR_2_PROPOSE_LETTRE_OU_MOT: { char status[20]; int partie_terminee = 0; + int trouve = 0; // si lettre trouvée = 1 - char lettre = toupper((unsigned char)reponse_message[0]); + int len = strlen(reponse_message); - printf("Le joueur propose la lettre : %c\n", lettre); + if (len == 1) { // si c'est une lettre uniquement + char lettre = toupper((unsigned char)reponse_message[0]); - // Vérification lettre valide - if (!isalpha((unsigned char)lettre) || lettre < 'A' || lettre > 'Z') { - strcpy(status, "erreur"); - snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, mot_affiche, nb_erreurs); - emit(JOUEUR_2_DONNEES_PARTIE, messageRecu, socket_client); - break; - } + printf("Le joueur propose la lettre : %c\n", lettre); - // Vérification si déjà testée - if (lettres_deja_testees[lettre - 'A']) { - strcpy(status, "deja"); - snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, mot_affiche, nb_erreurs); - emit(JOUEUR_2_DONNEES_PARTIE, messageRecu, socket_client); - break; - } + // Vérification lettre valide + if (!isalpha((unsigned char)lettre) || lettre < 'A' || lettre > 'Z') { + strcpy(status, "erreur"); + snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, mot_affiche, nb_erreurs); + emit(JOUEUR_2_DONNEES_PARTIE, messageRecu, socket_client); + break; + } - // Marquer comme testée - lettres_deja_testees[lettre - 'A'] = 1; + // Vérification si déjà testée + if (lettres_deja_testees[lettre - 'A']) { + strcpy(status, "deja"); + snprintf(messageRecu, LG_MESSAGE, "%s %s %d", status, mot_affiche, nb_erreurs); + emit(JOUEUR_2_DONNEES_PARTIE, messageRecu, socket_client); + break; + } - // Recherche dans le mot - int trouve = 0; - for (int i = 0; i < longueur_mot; i++) { - if (mot_secret[i] == lettre) { - mot_affiche[i] = lettre; - trouve = 1; + // Marquer la lettre comme testée + lettres_deja_testees[lettre - 'A'] = 1; + + // Recherche dans le mot + for (int i = 0; i < longueur_mot; i++) { + if (mot_secret[i] == lettre) { + mot_affiche[i] = lettre; + trouve = 1; + } } - } - if (!trouve) - nb_erreurs++; + if (!trouve) + nb_erreurs++; + } + // Cas mot + else { + printf("Le joueur propose le mot : %s\n", reponse_message); + + // Vérifier mot complet + if (strcmp(reponse_message, mot_secret) == 0) { + strcpy(mot_affiche, mot_secret); + } else { + nb_erreurs++; + } + } // Vérifier mot complet int mot_complet = 1; @@ -310,7 +458,7 @@ int main(int argc, char *argv[]){ printf("Vous avez droit à 6 erreurs maximum\n"); printf("===========================================\n\n"); - joueur_choisi_lettre(socket_client); + joueur_choisi_lettre(socket_client, longueur_mot); break; case JOUEUR_2_DONNEES_PARTIE: @@ -322,7 +470,7 @@ int main(int argc, char *argv[]){ if (strcmp(status, "oui") == 0) { printf("✓ Bonne lettre !\n"); } else if (strcmp(status, "non") == 0) { - printf("✗ Mauvaise lettre.\n"); + printf("✗ Mauvaise lettre ou mot.\n"); } else if (strcmp(status, "deja") == 0) { printf("⚠ Lettre déjà choisie. Choisissez-en une autre.\n"); } else if (strcmp(status, "erreur") == 0) { @@ -352,7 +500,7 @@ int main(int argc, char *argv[]){ partie_en_cours = 0; break; } else { - joueur_choisi_lettre(socket_client); + joueur_choisi_lettre(socket_client, longueur_mot); } break; case MESSAGE: @@ -367,3 +515,5 @@ int main(int argc, char *argv[]){ close(socket_client); return 0; } +PN_client_V3.c +14 KB From 47e6170c71433072abeb1e65f3202a21d0af4712 Mon Sep 17 00:00:00 2001 From: Zinab Date: Wed, 17 Dec 2025 09:48:58 +0100 Subject: [PATCH 18/19] Remove commented-out conversation and clean up code --- PN_client_V3.c | 123 +------------------------------------------------ 1 file changed, 1 insertion(+), 122 deletions(-) diff --git a/PN_client_V3.c b/PN_client_V3.c index 450b2ef..8a59bac 100644 --- a/PN_client_V3.c +++ b/PN_client_V3.c @@ -1,123 +1,3 @@ -__ Zinab__ 🎀 -zinab9191 -Invisible - -Caradoc — 12/11/25, 3:15 PM -Vous gérer le dépôt sur Moodle? -Мудрый — 12/11/25, 3:35 PM -D'accord merci! Oui on s'en occupe -Selyan — 12/12/25, 3:13 PM -Vous faites du télé travail ? -Мудрый — 12/12/25, 3:53 PM -Oui! -Selyan — 12/12/25, 4:09 PM -Synave a fait l'appel ce matin -Jsp si il fait que pour mon td -Мудрый — 12/12/25, 4:18 PM -Sûrement .. -Merci d'avoir prévenu -Selyan — 12/13/25, 3:15 PM -Qui s'occupe de la v4? -Je suis toujours sur la v3 (que je vais terminer aujourd'hui normalement), il me manquera le (diagramme) à faire -Caradoc — 12/13/25, 3:16 PM -Moi je suis toujours sur la V1, je pense avoir fini aujourdhui ou demain matin selon les galères. -Selyan — 12/13/25, 3:18 PM -Pour te dire j'ai commencé à vraiment travailler hier soir, j'ai pas réussi dans la semaine -Entre les changements de salle, les horaires décalés, les cours en même temps surtout -Mais ducoup là j'ai changé quasiment tout le code, je fais le travail que je devais faire en 3/4j en 1 journée max -Caradoc — 12/13/25, 3:22 PM -ok pas de soucis, moi j'ai travaillé dessus hier et depuis ce matin. Mais je ne suis pas dispo en fin d'aprem donc peut être plutôt demain matin du coup. -Selyan — 12/13/25, 9:03 PM -J'ai terminé la v3 (elle fonctionne). Dites moi si vous voulez le code maintenant ou plutôt attendre lundi pour tester -Мудрый — 12/14/25, 12:09 AM -Je vais la commencer demain -Мудрый — 12/14/25, 12:10 AM -Tu peux la push sur une branche V3 sur GitHub ? -Selyan — 12/14/25, 10:39 PM -j'ai pas vu le message déso ! -Concernant github je galère pas mal avec git, tu penses pouvoir le faire si je te donne les fichiers ? -Мудрый — 12/14/25, 10:39 PM -Oui pas de soucis! -Selyan — 12/15/25, 8:47 AM -Vous êtes en quelle salle? -Мудрый — 12/15/25, 8:48 AM -136 -Selyan — 12/15/25, 9:51 AM -Antigouvernementalisation -Selyan — 12/15/25, 3:46 PM -Image -Caradoc — 12/15/25, 3:46 PM -cest de la SAE ça? -Мудрый — 12/15/25, 3:46 PM -Oui😂 -Selyan — 12/15/25, 3:46 PM -Oui -Selyan — Yesterday at 10:56 AM -je vais adapter mon code pour qu'il fonctionne seul, je devrais terminer d'ici 16h max -__ Zinab__ 🎀 - - — Yesterday at 6:10 PM -Salut everybody !! -on est d'accord pour la presentation oral de demain , on devrai presenter le code de la V4 , ainsi une demo , et le diagramme -Selyan — Yesterday at 6:25 PM -Il me semble oui -Qu'en est il de celle-ci? -Мудрый — Yesterday at 6:38 PM -Oui normalement -Мудрый — Yesterday at 6:39 PM -Elle devrait être finie -T'as fini la v3? -Selyan — Yesterday at 6:39 PM -Ça fonctionne -J'ai pas eu grand chose à modifier grâce à mon système mis en place -Мудрый — Yesterday at 6:41 PM -Tu peux envoyer les fichiers sur ⁠🔗・v3 je vais les push github -Selyan — Yesterday at 7:53 PM -c'est fait. Je te conseille de compiler et de tester vite fait -Selyan — Yesterday at 11:07 PM -Demain matin : compte-rendu verification du fonctionnement du 4 ? -Мудрый — Yesterday at 11:08 PM -oui -__ Zinab__ 🎀 - - — 8:33 AM -Êtes vous à l'IUT -? -Selyan — 8:34 AM -Non, me suis réveillé ya 20m .. j'ai raté mon premier réveil -Caradoc — 8:34 AM -Oui mais en cours 😕 -Selyan — 8:53 AM -@Мудрый vous êtes en quelle salle ? -__ Zinab__ 🎀 - - — 8:54 AM -Moi je suis en biblio -Selyan — 8:54 AM -Marwa est pas avec toi? -__ Zinab__ 🎀 - - — 8:54 AM -Je pense pas que Marwa est là ? -Selyan — 9:47 AM -#include -#include -#include -#include -#include -#include -Expand -PN_client_V3.c -14 KB -#include -#include -#include -#include -#include -#include -Expand -PN_serveur_V3.c -8 KB  #include #include @@ -515,5 +395,4 @@ int main(int argc, char *argv[]){ close(socket_client); return 0; } -PN_client_V3.c -14 KB + From ab29574175693d12fb0f19f1a6e92468617e17ea Mon Sep 17 00:00:00 2001 From: Zinab Date: Wed, 17 Dec 2025 09:51:18 +0100 Subject: [PATCH 19/19] Rename constant for player 2 letter proposal --- PN_serveur_V3.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/PN_serveur_V3.c b/PN_serveur_V3.c index 4df25fb..52f62be 100644 --- a/PN_serveur_V3.c +++ b/PN_serveur_V3.c @@ -31,7 +31,7 @@ Joueur 2 : devine (propose des lettres) #define JOUEUR_1_ENTRE_MOT 2001 #define JOUEUR_2_TAILLE_MOT_ET_PEUT_JOUER 2002 -#define JOUEUR_2_PROPOSE_LETTRE 2003 +#define JOUEUR_2_PROPOSE_LETTRE_OU_MOT 2003 #define JOUEUR_1_VALIDE_OU_NON 2004 #define JOUEUR_2_RECOIT_VALIDE_OU_NON 2005 #define JOUEUR_2_DONNEES_PARTIE 2006 @@ -179,13 +179,12 @@ int main(int argc, char *argv[]){ printf("Reçu du client 2 (lettre) : %s → Transite au client 1\n", messageRecu); - emit(JOUEUR_2_PROPOSE_LETTRE, messageRecu, socket_client_1, 1); + emit(JOUEUR_2_PROPOSE_LETTRE_OU_MOT, messageRecu, socket_client_1, 1); // Recevoir réponse du client 1 traiter_message(messageRecu, socket_client_1); printf("Reçu du client 1 (réponse) : %s → Transite au client 2\n", messageRecu); - // Vérifier fin de partie if (strstr(messageRecu, "gagne") != NULL || strstr(messageRecu, "perdu") != NULL) { printf(">>> Partie terminée !\n");