[MY-AL] Implémenter l’algorithme minimax

Pour les scripts écrits en C#
Règles du forum
Merci de respecter la NOMENCLATURE suivante pour vos TITRES de messages :

Commencez par le niveau de vos scripts
DB = Débutant
MY = Moyen
CF = Confirmé

Puis le domaine d'application
-RS = Réseau
-AL = Algorithmie

Exemple :

[DB-RS] Mouvement perso multijoueur
LeGolbuth
Messages : 6
Inscription : 08 Fév 2017 20:42

[MY-AL] Implémenter l’algorithme minimax

Message par LeGolbuth » 08 Fév 2017 20:46

Bonjour,

Comme le sujet l'indique, j'écris un programme sensé implémenter l'algorithme minimax dans le jeu du morpion, sauf quand je l’exécute la grille se remplie instantanément..

Je n'arrive pas à écrire la condition qui me permettrais de détecter le clic du joueur dans un des box collider, afin d'y instancier une croix et d'ensuite appeler l'algorithme minmax pour jouer le coup de l'IA en conséquence.

Si quelqu'un pouvait m'aider , je vous remercie par avance et vous fais part de mon code :

Condition_Victoire :

Code : Tout sélectionner

using System;

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

public class MNode

{

    public int x;

    public int y;

    public int player;

}

public class MovesAndScores

{

    public int score;

    public MNode point;

    public MovesAndScores(int score, MNode point)

    {

        this.score = score;

        this.point = point;

    }

}

public class Condition_Victoire : MonoBehaviour {

    public int nb_coup = 0;

    public Gestion_Click[] case_morpion = new Gestion_Click[9];

    public GameObject text_j1;

    public GameObject text_j2;

    public GameObject Interface_fin_de_partie;

    public Text text_Gagnant;

    public GameObject croix;

    public GameObject rond;

    MNode[,] grid = new MNode[3, 3];

    public List<MovesAndScores> rootsChildrenScores;

    public GameObject ui;

    // Use this for initialization

    void Start () {

}

    public void Gestion_Affichage(int joueur)

    {

        if(joueur != 1)

        {

            text_j1.SetActive(true);

            text_j2.SetActive(false);

        }

        else if(joueur != 2)

        {

            text_j1.SetActive(false);

            text_j2.SetActive(true);

        }

    }

    private void Victoire (int gagnant)

    {

        //Debug.Log("Le joueur " + gagnant + " a gagné ! Bravo !!");

        this.transform.Rotate(-90, 0, 0);

        text_j1.SetActive(false);

        text_j2.SetActive(false);

        if(gagnant == 0)

        {

            text_Gagnant.text = "Match nul ! Il n'y a pas de gagnant..";

        }

        else

        {

            text_Gagnant.text = "Le joueur " + gagnant + " a gagné ! Bravo !!";

        }

        Interface_fin_de_partie.SetActive(true);

    }

    public void Verif_Victoire()

    {

        if(case_morpion[0].etat_joueur == case_morpion[1].etat_joueur && case_morpion[0].etat_joueur == case_morpion[2].etat_joueur && case_morpion[0].etat_joueur != 0)// Ligne 1

        {

            this.Victoire(case_morpion[0].etat_joueur);

        }

        else if (case_morpion[3].etat_joueur == case_morpion[4].etat_joueur && case_morpion[3].etat_joueur == case_morpion[5].etat_joueur && case_morpion[3].etat_joueur != 0)// Ligne 2

        {

            this.Victoire(case_morpion[3].etat_joueur);

        }

        else if (case_morpion[6].etat_joueur == case_morpion[7].etat_joueur && case_morpion[6].etat_joueur == case_morpion[8].etat_joueur && case_morpion[6].etat_joueur != 0)// Ligne 3

        {

            this.Victoire(case_morpion[6].etat_joueur);

        }

        else if (case_morpion[0].etat_joueur == case_morpion[3].etat_joueur && case_morpion[0].etat_joueur == case_morpion[6].etat_joueur && case_morpion[0].etat_joueur != 0)// Colonne 1

        {

            this.Victoire(case_morpion[0].etat_joueur);

        }

        else if (case_morpion[1].etat_joueur == case_morpion[4].etat_joueur && case_morpion[1].etat_joueur == case_morpion[7].etat_joueur && case_morpion[1].etat_joueur != 0)// Colonne 2

        {

            this.Victoire(case_morpion[1].etat_joueur);

        }

        else if (case_morpion[2].etat_joueur == case_morpion[5].etat_joueur && case_morpion[2].etat_joueur == case_morpion[8].etat_joueur && case_morpion[2].etat_joueur != 0)// Colonne 3

        {

            this.Victoire(case_morpion[2].etat_joueur);

        }

        else if (case_morpion[0].etat_joueur == case_morpion[4].etat_joueur && case_morpion[0].etat_joueur == case_morpion[8].etat_joueur && case_morpion[0].etat_joueur != 0)// Diagonnale descendante

        {

            this.Victoire(case_morpion[0].etat_joueur);

        }

        else if (case_morpion[2].etat_joueur == case_morpion[4].etat_joueur && case_morpion[2].etat_joueur == case_morpion[6].etat_joueur && case_morpion[2].etat_joueur != 0)// Diagonale montante

        {

            this.Victoire(case_morpion[2].etat_joueur);

        }

        else if (nb_coup >= 9)

        {

            this.Victoire(0);

        }

    }

// Update is called once per frame

void Update () {

        if (!isGameOver())

        {

            if(case_morpion[0].OnMouseDown()/*GetMouseButtonDown(0)*/ == true && isValidMove(0,0))

            {

                case_morpion[0].GetComponent<BoxCollider>().enabled = false;

                Instantiate(croix, new Vector3((float)- 3.5, (float)-0.5,(float)3.5), Quaternion.identity);

                MNode node = new MNode();

                node.x = 0;

                node.y = 0;

                node.player = 1;

                grid[node.x, node.y] = node;

                callMinimax(0, 1);

                MNode best = returnBestMove();

                if(isValidMove(best.x, best.y))

                {

                    Instantiate(rond, correspondance(best.x, best.y), Quaternion.identity);

                    best.player = 2;

                    grid[best.x, best.y] = best;

                }

            }

            if (case_morpion[1].OnMouseDown()/*GetMouseButtonDown(0)*/ == true && isValidMove(0, 1))

            {

                case_morpion[1].GetComponent<BoxCollider>().enabled = false;

                Instantiate(croix, new Vector3(0, (float)-0.5, (float)3.5), Quaternion.identity);

                MNode node = new MNode();

                node.x = 0;

                node.y = 1;

                node.player = 1;

                grid[node.x, node.y] = node;

                callMinimax(0, 1);

                MNode best = returnBestMove();

                if (isValidMove(best.x, best.y))

                {

                    Instantiate(rond, correspondance(best.x, best.y), Quaternion.identity);

                    best.player = 2;

                    grid[best.x, best.y] = best;

                }

            }

            if (case_morpion[2].OnMouseDown()/*GetMouseButtonDown(0)*/ == true && isValidMove(0, 2))

            {

                case_morpion[2].GetComponent<BoxCollider>().enabled = false;

                Instantiate(croix, new Vector3((float)3.5, (float)-0.5, (float)3.5), Quaternion.identity);

                MNode node = new MNode();

                node.x = 0;

                node.y = 2;

                node.player = 1;

                grid[node.x, node.y] = node;

                callMinimax(0, 1);

                MNode best = returnBestMove();

                if (isValidMove(best.x, best.y))

                {

                    Instantiate(rond, correspondance(best.x, best.y), Quaternion.identity);

                    best.player = 2;

                    grid[best.x, best.y] = best;

                }

            }

            if (case_morpion[3].OnMouseDown()/*GetMouseButtonDown(0)*/ == true && isValidMove(1, 0))

            {

                case_morpion[3].GetComponent<BoxCollider>().enabled = false;

                Instantiate(croix, new Vector3((float)-3.5, (float)-0.5, 0), Quaternion.identity);

                MNode node = new MNode();

                node.x = 1;

                node.y = 0;

                node.player = 1;

                grid[node.x, node.y] = node;

                callMinimax(0, 1);

                MNode best = returnBestMove();

                if (isValidMove(best.x, best.y))

                {

                    Instantiate(rond, correspondance(best.x, best.y), Quaternion.identity);

                    best.player = 2;

                    grid[best.x, best.y] = best;

                }

            }

            if (case_morpion[4].OnMouseDown()/*GetMouseButtonDown(0)*/ == true && isValidMove(1, 1))

            {

                case_morpion[4].GetComponent<BoxCollider>().enabled = false;

                Instantiate(croix, new Vector3(0, (float)-0.5, 0), Quaternion.identity);

                MNode node = new MNode();

                node.x = 1;

                node.y = 1;

                node.player = 1;

                grid[node.x, node.y] = node;

                callMinimax(0, 1);

                MNode best = returnBestMove();

                if (isValidMove(best.x, best.y))

                {

                    Instantiate(rond, correspondance(best.x, best.y), Quaternion.identity);

                    best.player = 2;

                    grid[best.x, best.y] = best;

                }

            }

            if (case_morpion[5].OnMouseDown()/*GetMouseButtonDown(0)*/ == true && isValidMove(1, 2))

            {

                case_morpion[5].GetComponent<BoxCollider>().enabled = false;

                Instantiate(croix, new Vector3((float)3.5, (float)-0.5, 0), Quaternion.identity);

                MNode node = new MNode();

                node.x = 1;

                node.y = 2;

                node.player = 1;

                grid[node.x, node.y] = node;

                callMinimax(0, 1);

                MNode best = returnBestMove();

                if (isValidMove(best.x, best.y))

                {

                    Instantiate(rond, correspondance(best.x, best.y), Quaternion.identity);

                    best.player = 2;

                    grid[best.x, best.y] = best;

                }

            }

            if (case_morpion[6].OnMouseDown()/*GetMouseButtonDown(0)*/ == true && isValidMove(2, 0))

            {

                case_morpion[6].GetComponent<BoxCollider>().enabled = false;

                Instantiate(croix, new Vector3((float)-3.5, (float)-0.5, (float)-3.5), Quaternion.identity);

                MNode node = new MNode();

                node.x = 2;

                node.y = 0;

                node.player = 1;

                grid[node.x, node.y] = node;

                callMinimax(0, 1);

                MNode best = returnBestMove();

                if (isValidMove(best.x, best.y))

                {

                    Instantiate(rond, correspondance(best.x, best.y), Quaternion.identity);

                    best.player = 2;

                    grid[best.x, best.y] = best;

                }

            }

            if (case_morpion[7].OnMouseDown()/*GetMouseButtonDown(0)*/ == true && isValidMove(2, 1))

            {

                case_morpion[7].GetComponent<BoxCollider>().enabled = false;

                Instantiate(croix, new Vector3(0, (float)-0.5, (float)-3.5), Quaternion.identity);

                MNode node = new MNode();

                node.x = 2;

                node.y = 1;

                node.player = 1;

                grid[node.x, node.y] = node;

                callMinimax(0, 1);

                MNode best = returnBestMove();

                if (isValidMove(best.x, best.y))

                {

                    Instantiate(rond, correspondance(best.x, best.y), Quaternion.identity);

                    best.player = 2;

                    grid[best.x, best.y] = best;

                }

            }

            if (case_morpion[8].OnMouseDown()/*GetMouseButtonDown(0)*/ == true && isValidMove(2, 2))

            {

                case_morpion[8].GetComponent<BoxCollider>().enabled = false;

                Instantiate(croix, new Vector3((float)3.5, (float)-0.5, (float)-3.5), Quaternion.identity);

                MNode node = new MNode();

                node.x = 2;

                node.y = 2;

                node.player = 1;

                grid[node.x, node.y] = node;

                callMinimax(0, 1);

                MNode best = returnBestMove();

                if (isValidMove(best.x, best.y))

                {

                    Instantiate(rond, correspondance(best.x, best.y), Quaternion.identity);

                    best.player = 2;

                    grid[best.x, best.y] = best;

                }

            }

        }

}

    private Vector3 correspondance(int a, int b)

    {

        double z = 0;

        double x = 0;

        if(a == 0)

        {

            z = 3.5;

        }

        else if(a == 1)

        {

            z = 0;

        }

        else

        {

            z = -3.5;

        }

        if(b == 0)

        {

            x = -3.5;

        }

        else if(b == 1)

        {

            x = 0;

        }

        else

        {

            x = 3.5;

        }

        return new Vector3((float)x, 0, (float)z);

    }

    public MNode returnBestMove()

    {

        int MAX = -100000;

        int best = -1;

        //iterates through rootsChildrenScores to get the best move

        for (int i = 0; i < rootsChildrenScores.Count; i++)

        {

            //also makes sure that the position in the grid is not occupied

            if (MAX < rootsChildrenScores[i].score && isValidMove(rootsChildrenScores[i].point.x, rootsChildrenScores[i].point.y))

            {

                MAX = rootsChildrenScores[i].score;

                best = i;

            }

        }

        if (best > -1)

            return rootsChildrenScores[best].point;

        MNode blank = new MNode();

        blank.x = 0;

        blank.y = 0;

        return blank;

    }

    private bool isValidMove(int x, int y)

    {

        if (grid[x, y] == null)

            return true;

        return false;

    }

    public bool hasOWon()

    {

        //check to see if the positions you're about to check actually exist in the grid

        if (grid[0, 0] != null && grid[1, 1] != null && grid[2, 2] != null)

        {

            //check to see if there is a diagonal win for the O player

            if (grid[0, 0].player == grid[1, 1].player && grid[0, 0].player == grid[2, 2].player && grid[0, 0].player == 1)

                return true;

        }

        if (grid[0, 2] != null && grid[1, 1] != null && grid[2, 0] != null)

        {

            //diagonal win

            if (grid[0, 2].player == grid[1, 1].player && grid[0, 2].player == grid[2, 0].player && grid[0, 2].player == 1)

                return true;

        }

        //Column Wins

        for (int i = 0; i < 3; ++i)

        {

            if (grid[i, 0] != null && grid[i, 1] != null && grid[i, 2] != null)

            {

                if (grid[i, 0].player == grid[i, 1].player && grid[i, 0].player == grid[i, 2].player && grid[i, 0].player == 1)

                    return true;

            }

            if (grid[0, i] != null && grid[1, i] != null && grid[2, i] != null)

            {

                if (grid[0, i].player == grid[1, i].player && grid[0, i].player == grid[2, i].player && grid[0, i].player == 1)

                    return true;

            }

        }

        return false; //there are no winning solutions on the board for O

    }

    public bool hasXWon()

    {

        if (grid[0, 0] != null && grid[1, 1] != null && grid[2, 2] != null)

        {

            if (grid[0, 0].player == grid[1, 1].player && grid[0, 0].player == grid[2, 2].player && grid[0, 0].player == 2)

                return true;

        }

        if (grid[0, 2] != null && grid[1, 1] != null && grid[2, 0] != null)

        {

            if (grid[0, 2].player == grid[1, 1].player && grid[0, 2].player == grid[2, 0].player && grid[0, 2].player == 2)

                return true;

        }

        for (int i = 0; i < 3; ++i)

        {

            if (grid[i, 0] != null && grid[i, 1] != null && grid[i, 2] != null)

            {

                if (grid[i, 0].player == grid[i, 1].player && grid[i, 0].player == grid[i, 2].player && grid[i, 0].player == 2)

                    return true;

            }

            if (grid[0, i] != null && grid[1, i] != null && grid[2, i] != null)

            {

                if (grid[0, i].player == grid[1, i].player && grid[0, i].player == grid[2, i].player && grid[0, i].player == 2)

                    return true;

            }

        }

        return false; //there are no winning solutions on the board for X

    }

    //game is over is someone has won, or board is full

    public bool isGameOver()

    {

        Text text = ui.GetComponent<Text>();

        if (getMoves().Capacity == 0)

        {

            //this.transform.Rotate(-90, 0, 0);

            //text_j1.SetActive(false);

            //text_j2.SetActive(false);

            //text_Gagnant.text = "Match nul ! Il n'y a pas de gagnant..";

            //Interface_fin_de_partie.SetActive(true);

            //return true;

            text.text = "c'est un match nul !";

            return true;

        }

        if (hasOWon())

        {

            //this.transform.Rotate(-90, 0, 0);

            //text_j1.SetActive(false);

            //text_j2.SetActive(false);

            //text_Gagnant.text = "L'IA a gagné.. Prenez votre revanche !";

            //Interface_fin_de_partie.SetActive(true);

            //return true;

            text.text = "Vous avez gagné !";

            return true;

        }

        if (hasXWon())

        {

            //this.transform.Rotate(-90, 0, 0);

            //text_j1.SetActive(false);

            //text_j2.SetActive(false);

            //text_Gagnant.text = "Bravo vous venez de réaliser l'impossible !";

            //Interface_fin_de_partie.SetActive(true);

            //return true;

            text.text = "Vous avez perdu!";

            return true;

        }

        return false;

    }

    List<MNode> getMoves()

    {

        List<MNode> result = new List<MNode>();

        for (int row = 0; row < 3; row++)

        {

            for (int col = 0; col < 3; col++)

            {

                if (grid[row, col] == null)

                {

                    MNode newNode = new MNode();

                    newNode.x = row;

                    newNode.y = col;

                    result.Add(newNode); //if the space is empty, add it to the list of results

                }

            }

        }

        return result;

    }

    //returns the minimum element of the list passed to it

    public int returnMin(List<int> list)

    {

        int min = 100000;

        int index = -1;

        for (int i = 0; i < list.Count; ++i)

        {

            if (list[i] < min)

            {

                min = list[i];

                index = i;

            }

        }

        return list[index];

    }

    //returns the maximum element of the list passed to it

    public int returnMax(List<int> list)

    {

        int max = -100000;

        int index = -1;

        for (int i = 0; i < list.Count; ++i)

        {

            if (list[i] > max)

            {

                max = list[i];

                index = i;

            }

        }

        return list[index];

    }

    private void callMinimax(int depth, int turn)

    {

        rootsChildrenScores = new List<MovesAndScores>();

        minimax(depth, turn);

    }

    public int minimax(int depth, int turn)

    {

        if (hasXWon()) return +1; //+1 for a player win

        if (hasOWon()) return -1; //-1 for a computer win

        List<MNode> pointsAvailable = getMoves();

        if (pointsAvailable.Capacity == 0) return 0;

        List<int> scores = new List<int>();

        for (int i = 0; i < pointsAvailable.Count; i++)

        {

            MNode point = pointsAvailable[i];

            //Select the highest from the minimax call on X's turn

            if (turn == 1)

            {

                MNode x = new MNode();

                x.x = point.x;

                x.y = point.y;

                x.player = 2;

                grid[point.x, point.y] = x;

                int currentScore = minimax(depth + 1, 2);

                scores.Add(currentScore);

                if (depth == 0)

                {

                    MovesAndScores m = new MovesAndScores(currentScore, point);

                    m.point = point;

                    m.score = currentScore;

                    rootsChildrenScores.Add(m);

                }

            }

            //Select the lowest from the minimax call on O's turn

            else if (turn == 2)

            {

                MNode o = new MNode();

                o.x = point.x;

                o.y = point.y;

                o.player = 1;

                grid[point.x, point.y] = o;

                int currentScore = minimax(depth + 1, 1);

                scores.Add(currentScore);

            }

            grid[point.x, point.y] = null; //reset the point

        }

        return turn == 1 ? returnMax(scores) : returnMin(scores);

    }

}

Gestion_Click :
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gestion_Click : MonoBehaviour {
    public GameObject croix;
    public GameObject rond;
    static public bool joueur1 = true;
    public int etat_joueur = 0; // 0 = case non jouée // 1 = joueur1 // 2 = IA
    public Condition_Victoire lien_scripts;
    public Gestion_Click[] case_morpion;
    public bool IA_enabled = true;
    public int maxi = 0;
    public bool hasClicked = false;
    public bool OnMouseDown()
    {
        Debug.Log("clic gauche détecté !");
        hasClicked = true;
        return hasClicked;
      //  this.GetComponent<BoxCollider>().enabled = false;
        //if (joueur1)
        //{
        // //   Instantiate(croix, this.transform.position, Quaternion.identity);
        //    joueur1 = false;
        //    etat_joueur = 1;
        //    lien_scripts.nb_coup++;
        //    lien_scripts.Gestion_Affichage(etat_joueur);
        //    lien_scripts.Verif_Victoire();
        // }
        //else
        //{
        ////    Instantiate(rond, this.transform.position, Quaternion.identity);
        //    joueur1 = true;
        //    etat_joueur = 2;
        //    lien_scripts.nb_coup++;
        //    lien_scripts.Gestion_Affichage(etat_joueur);
        //    lien_scripts.Verif_Victoire();
        //}
    }
    internal bool GetMouseButtonDown(int v)
    {
        if(v == 0)
        {
            Debug.Log("clic gauche détecté !");
            return true;
        }
        else
        {
            return false;
        }
    }
}
Gestion_Partie :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Gestion_Parties : MonoBehaviour {
    public void Lancer_Partie_1v1()
    {
        SceneManager.LoadScene(1);
    }
    public void Lancer_Partie_1vIA()
    {
        SceneManager.LoadScene(1);
    }
    public void Quitter()
    {
        Application.Quit();
    }
    public void Menu()
    {
        SceneManager.LoadScene(0);
    }
}
:!: Attention à la section où vous postez. :!:
Les balises code SVP :!:
Merci de lire la Netiquette du forum.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6185
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [MY-AL] Implémenter l’algorithme minimax

Message par boubouk50 » 09 Fév 2017 10:51

Salut LeGolbuth,

Peux-tu essayer de cibler un peu s'il te plait.
Ton code est très long, tout lire et tout comprendre prend du temps et risque de ne pas attirer les réponses. Il y a toujours des irréductibles gaulois très motivés mais ce n'est pas garanti.

Je suppose que ton problème vient de Gestion_Click et du OnMouseDown (), non?
Que te renvoie-t-il?
void OnMouseDown () est une fonction de MonoBehaviour , ici tu la redéfinis différemment, je ne suis pas sur du comportement que cela va avoir, mais je ne pense pas qu'elle soit appelée au clic de la souris.
Peut-être est-ce GetMouseButtonDown que tu cherches?
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

Moi 1971
Messages : 727
Inscription : 29 Sep 2015 13:38

Re: [MY-AL] Implémenter l’algorithme minimax

Message par Moi 1971 » 09 Fév 2017 11:32

Bonjour,
Peux-tu nous donner le lien vers la source de ton code?

LeGolbuth
Messages : 6
Inscription : 08 Fév 2017 20:42

Re: [MY-AL] Implémenter l’algorithme minimax

Message par LeGolbuth » 12 Fév 2017 17:21

exactement boubouk50 !
Mon principal problème réside dans l'handler qui devrait s'activer au moment du clic gauche sur une des cases du morpion.
une fois le clic détecté j'aimerais instancier une croix dans la case en question et tout de suite après jouer le tour de l'IA .
Or avec le code présent, dés que j’exécute, la grille de remplie automatiquement , sans même que j'ai besoin de cliquer , et toujours de la même manière :

X X O
X O X
O X X

Ma question était, ou est le problème ? est ce que j'utilise la mauvaise méthode pour recueillir les clics dans les cases du morpion, sachant que j'ai testé avec OnMouseDown() qui renvoie void en temps normal, et GetOnMouseDown(0) qui renvoie un booléen.
Et que les deux méthodes n'aboutissent pas ..
Ou est ce que le problème ne vient pas plutôt de l'IA et de la fonction Update() ?

et désolé mais je n'ai pas encore mit mon code en ligne , je vous ferais part du lien une fois que ce sera fait.

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6185
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [MY-AL] Implémenter l’algorithme minimax

Message par boubouk50 » 13 Fév 2017 10:35

Je dirais que c'est plus une erreur de composition qu'autre chose. Si ton IA valide la grille dès le départ, c'est qu'il n'est pas limité dans ses coups.
Il faut que tu définisses quand il doit jouer et quand il doit attendre. Pour le coup, l'update devrait servir uniquement à cela, attendre que ce soit son tour de jouer et le faire jouer une seule fois. Ça pourrait également marcher aussi sans update puisque ce sont des événements.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

LeGolbuth
Messages : 6
Inscription : 08 Fév 2017 20:42

Re: [MY-AL] Implémenter l’algorithme minimax

Message par LeGolbuth » 14 Fév 2017 01:20

J'ai réussi a faire jouer l'IA correctement a son tour. Or une solution n'arrive jamais seul avec moi .. Mon problème étant maintenant la détection de fin de partie .
J'ai tenté de faire un mixe en mettant la transform de la fonction "victoire" dans la fonction "isGameOver" et mettre le tout dans l'update. Mais vue le résultat, c'était effectivement pas la bonne chose à faire : la camera oscille entre la rotation à 90° et sa position initiale, une fois la partie terminé. Du coup je sais pas si c'est la fonction "isGameOver" qui bug ou si c'est le fait de l'avoir placé dans l'update. Mais j'imagine qu'il y a une solution pour empêcher le retour de la camera à sa position initiale, même si on est dans l'update, non ?

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6185
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [MY-AL] Implémenter l’algorithme minimax

Message par boubouk50 » 14 Fév 2017 10:35

Pour arrêter un bout de code dans un Update, tu n'as pas d'autre choix que de trouver une condition avec un booléen. Sinon, il faut sortir de l'Update et gérer des coroutines ou des événements.
Surtout pour un morpion, qui est du coup par coup, pas besoin d'Update normalement. Tu devrais gérer des moments: Début de jeu -> début et fin de tour -> Fin de jeu.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

LeGolbuth
Messages : 6
Inscription : 08 Fév 2017 20:42

Re: [MY-AL] Implémenter l’algorithme minimax

Message par LeGolbuth » 14 Fév 2017 16:07

Bah je comprends pas parce que dans l'update il y a justement la valeur booléenne de la fonction "isGameOver", quand elle renvoie false, le jeu continue et quand elle renvoie true, j'aimerais justement pouvoir gérer ma fin de partie.
Vous me conseillerez de revoir mon code et de gérer le tour par tour autre part que dans une fonction update ?
Ou peut être qu'il y a une solution avec la méthode que j'ai utilisé ?

LeGolbuth
Messages : 6
Inscription : 08 Fév 2017 20:42

Re: [MY-AL] Implémenter l’algorithme minimax

Message par LeGolbuth » 14 Fév 2017 16:08

Vous voulez peut être que je vous montre la partie de code en question ?

Avatar de l’utilisateur
boubouk50
ModoGenereux
ModoGenereux
Messages : 6185
Inscription : 28 Avr 2014 11:57
Localisation : Saint-Didier-en-Bresse (71)

Re: [MY-AL] Implémenter l’algorithme minimax

Message par boubouk50 » 14 Fév 2017 16:17

Comme je te l'ai dit, tu peux gérer les états de jeu avec l'Update, savoir où tu en es pour lancer l'action suivante. A la fin de chaque coup, tu devrais passer l'état du jeu actuel dans une fonction qui détermine si le jeu est terminé ou non. (Fin par victoire ou match nul). Cette moulinette, déterminera donc si tu dois continuer ou terminer.
Si tu as des actions à interrompre dans l'Update lors de la fin, il faut qu'elles soient encapsulées dans une condition gérée par un booléen que la fonction de détermination de fin switchera en cas de fin. Ainsi, les actions de l'Update seront arrêtées.

Il y a de nombreuses manières de programmer cela, avec des programmations plus ou moins bourrines / rapides / optimisées / efficace. Avec la puissance des machines actuelles (et même les anciennes), un morpion fera rarement ramer un smartphone ou une bouse à ventilateur, au vu du peu de ressources que cela demande.
La question de refaire ou non ne dépend que de toi, de comment tu veux programmer ton morpion.

Je répète également: le morpion est un jeu au coup par coup avec des actions déterminées. Il suit un chemin linéaire d'actions successives. Des événements. Ainsi, tu pourrais gérer le code par de simple fonction qui se suivent, sans passer par l'Update qui lui fera des calculs intermédiaires inutiles.

Exemple: Je lance la partie: 1e joueur doit jouer -> Événement clic -> Positionner la croix ou le rond -> partie finie? -> 2e joueur -> (cette même boucle tant que la partie n'est pas terminée) -> Fin de partie
L'attente n'est pas obligée de passer par l'Update puisqu’une action sera effectuée, action qui pourra lancer la suite.
"Ce n'est pas en améliorant la bougie, que l'on a inventé l'ampoule, c'est en marchant longtemps."
Nétiquette du forum
Savoir faire une recherche
Apprendre la programmation

Répondre

Revenir vers « (C#) CSharp »