#include "puissance4.hpp" std::random_device rd; std::default_random_engine e(rd()); // Définition des méthodes de la classe P4 bool P4::GrillePleine() const { for (int i = 0; i < ROWS; ++i) { for (int j = 0; j < COLS; ++j) { if (board[i][j] == ' ') { return false; } } } return true; } bool P4::EstGagnant(int row, int col) const { char joueur = board[row][col]; // Vérification horizontale int count = 1; for (int j = col - 1; j >= 0 && board[row][j] == joueur; --j) { ++count; } for (int j = col + 1; j < COLS && board[row][j] == joueur; ++j) { ++count; } if (count >= 4) return true; // Vérification verticale count = 1; for (int i = row - 1; i >= 0 && board[i][col] == joueur; --i) { ++count; } for (int i = row + 1; i < ROWS && board[i][col] == joueur; ++i) { ++count; } if (count >= 4) return true; // Vérification diagonale (descendante) count = 1; for (int i = row - 1, j = col - 1; i >= 0 && j >= 0 && board[i][j] == joueur; --i, --j) { ++count; } for (int i = row + 1, j = col + 1; i < ROWS && j < COLS && board[i][j] == joueur; ++i, ++j) { ++count; } if (count >= 4) return true; // Vérification diagonale (montante) count = 1; for (int i = row - 1, j = col + 1; i >= 0 && j < COLS && board[i][j] == joueur; --i, ++j) { ++count; } for (int i = row + 1, j = col - 1; i < ROWS && j >= 0 && board[i][j] == joueur; ++i, --j) { ++count; } if (count >= 4) return true; return false; } P4::P4() { board.assign(ROWS, std::vector(COLS, ' ')); } std::string P4::ToString() const { std::string result; for (int i = 0; i < ROWS; ++i) { for (int j = 0; j < COLS; ++j) { result += board[i][j]; result += ' '; } result += '\n'; } return result; } void P4::EffectuerCoup(unsigned col) { for (int i = ROWS - 1; i >= 0; --i) { if (board[i][col] == ' ') { char joueur = (j1aletrait) ? 'X' : 'O'; board[i][col] = joueur; j1aletrait = !j1aletrait; if (EstGagnant(i, col)) { std::cout << ToString() << std::endl; std::cout << joueur << " a gagné !" << std::endl; exit(0); } if (GrillePleine()) { std::cout << ToString() << std::endl; std::cout << "Partie nulle !" << std::endl; exit(0); } return; } } std::cerr << "Colonne pleine, coup invalide." << std::endl; } unsigned P4::Nbcoups() { unsigned count = 0; for (int col = 0; col < COLS; ++col) { if (board[0][col] == ' ') { ++count; } } return count; } Resultat P4::Eval() const { for (int i = 0; i < ROWS; ++i) { for (int j = 0; j < COLS; ++j) { if (board[i][j] != ' ') { char joueur = board[i][j]; // Vérification horizontale if (j + 3 < COLS && board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2] && board[i][j] == board[i][j + 3]) { return (joueur == 'X') ? Resultat::j1gagne : Resultat::j0gagne; } // Vérification verticale if (i + 3 < ROWS && board[i][j] == board[i + 1][j] && board[i][j] == board[i + 2][j] && board[i][j] == board[i + 3][j]) { return (joueur == 'X') ? Resultat::j1gagne : Resultat::j0gagne; } // Vérification diagonale (descendante) if (i + 3 < ROWS && j + 3 < COLS && board[i][j] == board[i + 1][j + 1] && board[i][j] == board[i + 2][j + 2] && board[i][j] == board[i + 3][j + 3]) { return (joueur == 'X') ? Resultat::j1gagne : Resultat::j0gagne; } // Vérification diagonale (montante) if (i - 3 >= 0 && j + 3 < COLS && board[i][j] == board[i - 1][j + 1] && board[i][j] == board[i - 2][j + 2] && board[i][j] == board[i - 3][j + 3]) { return (joueur == 'X') ? Resultat::j1gagne : Resultat::j0gagne; } } } } if (!GrillePleine()) { return Resultat::partieNulle; } return Resultat::partieNulle; } // Définition des méthodes de la classe JHP4 JHP4::JHP4() { nom = "Joueur Humain (Puissance 4)"; } unsigned JHP4::Jouer(P4 p) { unsigned col; std::cout << "Entrez le numéro de la colonne où vous voulez jouer (de 1 à 7) : "; std::cin >> col; // Convertir de 1-indexed à 0-indexed return col - 1; } IARandom::IARandom() { nom = "IA Aléatoire"; // Initialisation du générateur de nombres aléatoires std::srand(std::time(nullptr)); } unsigned IARandom::Jouer(P4 p) { // Obtenir le nombre de colonnes possibles unsigned nbCols = p.Nbcoups(); // Choisir aléatoirement une colonne entre 0 et nbCols - 1 unsigned col = std::rand() % nbCols; return col; } template unsigned noeud

::compt = 0; template noeud

::noeud(noeud

* pere, P p) : pere(pere), p(p), cross{0}, win{0} { ++compt; nbfils = p.Nbcoups(); fils = new noeud

*[nbfils]; for (unsigned i = 0; i < nbfils; ++i) fils[i] = nullptr; } template noeud

::~noeud() { for (unsigned i = 0; i < nbfils; ++i) { delete fils[i]; } delete[] fils; --compt; } template noeud

* noeud

::MeilleurFils() { if (fils[indiceMeilleurFils] != nullptr) { return fils[indiceMeilleurFils]; } P q = p; q.EffectuerCoup(indiceMeilleurFils); fils[indiceMeilleurFils] = new noeud

(this, q); return fils[indiceMeilleurFils]; } template void noeud

::CalculMeilleurFils(double a) { double s; double sM = 0; if (p.j1aletrait) { for (unsigned i = 0; i < nbfils; ++i) { if (fils[i] == nullptr) { s = 1; } else { s = (fils[i]->win + a) / (fils[i]->cross + a); } if (s > sM) { sM = s; indiceMeilleurFils = i; } } } else { for (unsigned i = 0; i < nbfils; ++i) { if (fils[i] == nullptr) { s = 1; } else { s = (fils[i]->cross - fils[i]->win + a) / (fils[i]->cross + a); } if (s > sM) { sM = s; indiceMeilleurFils = i; } } } } template std::string noeud

::ToString() const { std::string s = ""; s = s + "indice MF = " + std::to_string(indiceMeilleurFils); double note; s += "\n note="; if (fils[indiceMeilleurFils]) { note = (1.0 * fils[indiceMeilleurFils]->win) / fils[indiceMeilleurFils]->cross; s += std::to_string(note); } else s += "?"; s += "\n nbC=" + std::to_string(cross / 2); s += "\n" + std::to_string(compt); return s; } template JMCTS

::JMCTS(double a, unsigned temps) : a(a), temps(temps) { this->nom = "JMCTS(a=" + std::to_string(a) + ",temps=" + std::to_string(temps) + ")"; } template unsigned JMCTS

::JeuHasard(P p) const { unsigned re = 1; while (p.Nbcoups() > 0) { p.EffectuerCoup(e() % p.Nbcoups()); } if (p.Eval() == Resultat::j1gagne) { re = 2; } if (p.Eval() == Resultat::j0gagne) { re = 0; } return re; } template unsigned JMCTS

::Jouer(P p) { std::clock_t t0 = std::clock(); std::clock_t t1 = t0 + temps * (CLOCKS_PER_SEC / 1000); racine = new noeud

(nullptr, p); unsigned iter = 0; while (std::clock() < t1) { noeud

* no = racine; do // Sélection { no->CalculMeilleurFils(a); no = no->MeilleurFils(); } while (no->cross > 0 && no->nbfils > 0); unsigned re = JeuHasard(no->p); // Simulation while (no != nullptr) // Rétropropagation { no->cross += 2; no->win += re; no = no->pere; } ++iter; } racine->CalculMeilleurFils(a); this->message = std::to_string(iter) + " itérations\n"; this->message += racine->ToString(); unsigned res = racine->indiceMeilleurFils; delete racine; return res; } template Partie

::Partie(Joueur

& j1, Joueur

& j0, P pInitiale, bool aff) : j1(j1), j0(j0), pCourante(pInitiale), affichage(aff) {} template void Partie

::Commencer() { if (affichage) std::cout << pCourante.ToString() << std::endl; while (pCourante.Nbcoups() > 0) { if (pCourante.j1aletrait) { if (affichage) std::cout << j1.nom << "(j1) joue" << std::endl; pCourante.EffectuerCoup(j1.Jouer(pCourante)); if (affichage) std::cout << j1.message << std::endl; } else { if (affichage) std::cout << j0.nom << "(j0) joue" << std::endl; pCourante.EffectuerCoup(j0.Jouer(pCourante)); if (affichage) std::cout << j0.message << std::endl; } if (affichage) std::cout << pCourante.ToString() << std::endl; } r = pCourante.Eval(); if (affichage) { switch (r) { case Resultat::j1gagne: std::cout << "j1 a gagné" << std::endl; break; case Resultat::j0gagne: std::cout << "j0 a gagné" << std::endl; break; case Resultat::partieNulle: std::cout << "Partie nulle" << std::endl; break; } } j1.FinPartie(); j0.FinPartie(); } int main() { // Création des joueurs JMCTS JMCTS joueur1(10.0, 50); // Configuration arbitraire pour le premier joueur // Création du joueur humain JHP4 joueur2; // Création de l'état initial du jeu P4 etatInitial; // Création de la partie entre JMCTS et JHP4 Partie partie(joueur1, joueur2, etatInitial); // Début de la partie partie.Commencer(); return 0; }