// //fonction de base du minimax qui va s'occuper de la profondeur itérative. // override public Move GetNextMove(Grille grille, int profondeur) { double valeurOptimal = Double.MinValue; Move moveOptimal = null; stopwatch = new Stopwatch(); stopwatch.Start(); HashSet <Move> possibleMoves = grille.ListPossibleMoves(); while (true) { foreach (var possibleMove in possibleMoves) { Grille moveGrille = new Grille(grille); moveGrille.UpdateGrille(possibleMove); moveGrille.ReverseBoard(); double valeurTest = Execute(moveGrille, profondeur - 1, valeurOptimal, Double.MaxValue); if (valeurTest > valeurOptimal) { valeurOptimal = valeurTest; moveOptimal = possibleMove; } if (stopwatch.Elapsed.TotalMilliseconds > Settings.TIME_TO_MOVE) { stopwatch.Stop(); return(moveOptimal); } } profondeur++; } }
public override double Calculer(Grille grille) { double valeurHeuristique = 0; double coefficient = 1.0; // parcours toute le board for (int i = 0; i < 24; i++) { if (grille.board[i] == 1) // si on a un pion non protegé { valeurHeuristique -= 1 * coefficient; } else if (grille.board[i] >= 2) // si on a un pion protegé { valeurHeuristique += 1 * coefficient * grille.board[i]; } coefficient -= 0.01; } valeurHeuristique += grille.oppBar * 1.3; // On check pour quel joueur on est. if (grille.player) { return(valeurHeuristique); } return(-valeurHeuristique); }
// // Cette fonction retourne la liste de tous les moves possible pour la grille. // private void GetPossibleMoves(Grille grille, List <Tuple <int, int> > listeMoves) { bool foundPossibleMove = false; for (int i = 0; i < grille.dice.Count; i++) { var possibleMovesForDie = GetPossibleMovesForDie(grille, grille.dice[i]); if (possibleMovesForDie.Count != 0) { foundPossibleMove = true; foreach (var move in possibleMovesForDie) { Grille moveGrille = new Grille(grille); moveGrille.UpdateGrille(move); List <Tuple <int, int> > moveListe = new List <Tuple <int, int> >(listeMoves); moveListe.Add(move); GetPossibleMoves(moveGrille, moveListe); } } } if (!foundPossibleMove && listeMoves.Count > 0)// on est dans une feuille, on ajoute le move a la liste. { Move move = new Move(listeMoves); if (maxDice <= move.DiceUsed && maxStep <= move.Step) { listPossibleMoves.Add(move); maxStep = move.Step; maxDice = move.DiceUsed; } } }
// // constructeur par copie // public Grille(Grille grille) { grille.board.CopyTo(board, 0); dice = new List <int>(grille.dice); bar = grille.bar; oppBar = grille.oppBar; player = grille.player; }
// // Retourne la liste des moves possibles pour un dé // private List <Tuple <int, int> > GetPossibleMovesForDie(Grille grille, int die) { var moves = new List <Tuple <int, int> >(); //si l'on doit vider le bar. if (grille.bar != 0) { if (grille.board[25 - die - 1] >= -1) { moves.Add(new Tuple <int, int>(25, 25 - die)); } } else if (grille.IsFinalStage()) // si on est rendu a vider la planche. { int pionLePlusEloigne = 0; for (int i = 0; i < 6; i++) { if (grille.board[i] > 0) { pionLePlusEloigne = i + 1; } } for (int i = 0; i < 6; i++) { if (grille.board[i] > 0) { if (i + 1 - die == 0) { moves.Add(new Tuple <int, int>(i + 1, i + 1 - die)); } else if (i + 1 - die < 0 && die >= pionLePlusEloigne) { moves.Add(new Tuple <int, int>(i + 1, i + 1 - die)); } else if (i - die >= 0 && grille.board[i - die] >= -1) { moves.Add(new Tuple <int, int>(i + 1, i + 1 - die)); } } } } else // on peut jouer n'importequoi { for (int i = 0; i < 24; i++) { if (grille.board[i] > 0 && i - die >= 0 && grille.board[i - die] >= -1) //on peut jouer sur cette case. { moves.Add(new Tuple <int, int>(i + 1, i + 1 - die)); } } } return(moves); }
override public Move GetNextMove(Grille grille, int profondeur) { double valeurOptimal = Double.MinValue; Move moveOptimal = null; HashSet <Move> possibleMoves = grille.ListPossibleMoves(); foreach (var possibleMove in possibleMoves) { Grille moveGrille = new Grille(grille); moveGrille.UpdateGrille(possibleMove); moveGrille.ReverseBoard(); double valeurTest = Execute(moveGrille, profondeur - 1); if (valeurTest > valeurOptimal) { valeurOptimal = valeurTest; moveOptimal = possibleMove; } } return(moveOptimal); }
override public double Calculer(Grille grille) { double valeurHeuristique = 0; // Aucune menace: http://i.imgur.com/ktuiqfY.jpg // Menace ennemie: http://i.imgur.com/oBM4sIj.jpg bool menaceEnnemie = false; // TODO: à vérifier pour l'ennemi (dans l'autre direction?) for (int i = 0; i < grille.board.Length; i++) { int nbPionsJoueur = 0; if (grille.board[i] < 0) { menaceEnnemie = true; break; } if (grille.board[i] > 0) { nbPionsJoueur += grille.board[i]; if (nbPionsJoueur == 15) { break; } } } // S'il n'y a aucune menace ennemie, c'est free-for-all if (menaceEnnemie) { int nbPairsColles = 0; double multiplicateurRecompense = 0; int nbGroupesPairs = 0; for (int i = 0; i < grille.board.Length; i++) { // On pénalise tous les checkers non protégés if (grille.board[i] == 1) { bool ennemiEnAvant = grille.EnnemiEnAvantDuPoint(i); if (ennemiEnAvant) { // Plus pénalisant si on est proche de la fin valeurHeuristique -= 2000 / (double)(i + 1); } // Moins grave s'il y a aucun checker ennemi en avant, mais quand même risqué else { valeurHeuristique -= 200 / (double)(i + 1); } } // On récompense les pairs (bloquent le point) if (grille.board[i] >= 2) { if (i >= 1 && grille.board[i - 1] < 2) { nbPairsColles = 0; nbGroupesPairs++; } bool ennemiEnAvant = grille.EnnemiEnAvantDuPoint(i); nbPairsColles++; if (ennemiEnAvant) { multiplicateurRecompense += 2 + (0.1 * i); } // Se trouve dans les 6 derniers points if (i <= 5) { multiplicateurRecompense += 2 + (0.1 * i); } } } double valeurHeuristiquePairs = 0; switch (nbPairsColles) { case 0: break; case 1: valeurHeuristiquePairs += (5 * multiplicateurRecompense); break; case 2: valeurHeuristiquePairs += (15 * multiplicateurRecompense); break; case 3: valeurHeuristiquePairs += (40 * multiplicateurRecompense); break; case 4: valeurHeuristiquePairs += (70 * multiplicateurRecompense); break; case 5: valeurHeuristiquePairs += (110 * multiplicateurRecompense); break; case 6: valeurHeuristiquePairs += (200 * multiplicateurRecompense); break; default: valeurHeuristiquePairs += (200 * multiplicateurRecompense); break; } valeurHeuristiquePairs *= nbGroupesPairs; valeurHeuristique += valeurHeuristiquePairs; } // Plus on peut manger de checkers, mieux c'est valeurHeuristique += 1000 * grille.oppBar; // Plus on peut bear-off (rentrer) de checkers, mieux c'est valeurHeuristique += grille.GetNbPionsJoueurRentres() * 10000; if (grille.player) { return(valeurHeuristique); } return(-valeurHeuristique); }
override public double Execute(Grille grille, int profondeur) { if (profondeur == 0) // on est au bout. { Grille grillePourEnnemi = new Grille(grille); grillePourEnnemi.ReverseBoard(); double test = this.heuristique.Calculer(grille) - this.heuristique.Calculer(grillePourEnnemi); if (grille.player) { return(test); } else { return(-test); } } if (grille.dice.Count > 0) // un joueur peut jouer. { if (grille.player) // on joue { HashSet <Move> possibleMoves = grille.ListPossibleMoves(); double value = double.MinValue; foreach (var possibleMove in possibleMoves) { Grille moveGrille = new Grille(grille); moveGrille.UpdateGrille(possibleMove); moveGrille.ReverseBoard(); value = Math.Max(value, Execute(moveGrille, profondeur - 1)); } return(value); } else //l'adversaire joue. { HashSet <Move> possibleMoves = grille.ListPossibleMoves(); double value = double.MaxValue; foreach (var possibleMove in possibleMoves) { Grille moveGrille = new Grille(grille); moveGrille.UpdateGrille(possibleMove); moveGrille.ReverseBoard(); value = Math.Max(value, Execute(moveGrille, profondeur - 1)); } return(value); } } else // on est dans notre cas random. { double value = 0; double[] values = new double[Player.possibleDiceRoll.Count + 1]; Thread[] threads = new Thread[Player.possibleDiceRoll.Count + 1]; int i = 0; for (i = 0; i < Player.possibleDiceRoll.Count; i++) { Grille diceGrille = new Grille(grille); diceGrille.dice = Player.possibleDiceRoll[i].Item2; int num = i; threads[i] = new Thread(delegate() { values[num] = Player.possibleDiceRoll[num].Item1 * Execute(diceGrille, profondeur); }); threads[i].Start(); } for (int j = 0; j < Player.possibleDiceRoll.Count; j++) { threads[j].Join(); value += values[j]; } return(value); } }
abstract public Move GetNextMove(Grille pos, int depth);
abstract public double Execute(Grille grille, int profondeur);
public double Execute(Grille grille, int profondeur, double alpha, double beta) { if (profondeur == 0) // on est au bout. { Grille grillePourEnnemi = new Grille(grille); grillePourEnnemi.ReverseBoard(); double test = this.heuristique.Calculer(grille) - this.heuristique.Calculer(grillePourEnnemi); if (grille.player) { return(test); } else { return(-test); } } if (grille.dice.Count > 0) // un joueur peut jouer. { if (grille.player) // on joue { HashSet <Move> possibleMoves = grille.ListPossibleMoves(); foreach (var possibleMove in possibleMoves) { Grille moveGrille = new Grille(grille); moveGrille.UpdateGrille(possibleMove); moveGrille.ReverseBoard(); alpha = Math.Max(alpha, Execute(moveGrille, profondeur - 1, alpha, beta)); if (beta <= alpha) { break; } if (stopwatch.Elapsed.TotalMilliseconds > Settings.TIME_TO_MOVE) { stopwatch.Stop(); return(alpha); } } return(alpha); } else //l'adversaire joue. { HashSet <Move> possibleMoves = grille.ListPossibleMoves(); foreach (var possibleMove in possibleMoves) { Grille moveGrille = new Grille(grille); moveGrille.UpdateGrille(possibleMove); moveGrille.ReverseBoard(); beta = Math.Min(beta, Execute(moveGrille, profondeur - 1, alpha, beta)); if (beta <= alpha) { break; } if (stopwatch.Elapsed.TotalMilliseconds > Settings.TIME_TO_MOVE) { stopwatch.Stop(); return(beta); } } return(beta); } } else // on est dans notre cas random. { double value = 0; double[] values = new double[Player.possibleDiceRoll.Count + 1]; Thread[] threads = new Thread[Player.possibleDiceRoll.Count + 1]; int i = 0; for (i = 0; i < Player.possibleDiceRoll.Count; i++) { if (stopwatch.Elapsed.TotalMilliseconds > Settings.TIME_TO_MOVE) { stopwatch.Stop(); return(value); } Grille diceGrille = new Grille(grille); diceGrille.dice = Player.possibleDiceRoll[i].Item2; int num = i; threads[i] = new Thread(delegate() { values[num] = Player.possibleDiceRoll[num].Item1 * Execute(diceGrille, profondeur, alpha, beta); }); threads[i].Start(); } for (int j = 0; j < Player.possibleDiceRoll.Count; j++) { threads[j].Join(); value += values[j]; } return(value); } }
// Stub method because we use header with alpha and beta vars override public double Execute(Grille grille, int profondeur) { return(0.0); }
abstract public double Calculer(Grille grille);
static void Main(string[] args) { ProcessStartInfo startInfo; String EXPORT_PATH; //check if linux int p = (int)Environment.OSVersion.Platform; if ((p == 4) || (p == 6) || (p == 128)) { //is linux startInfo = new ProcessStartInfo("gnubg", "-t"); EXPORT_PATH = Directory.GetCurrentDirectory() + "/"; } else { //is windows //startInfo = new ProcessStartInfo("D:\\Games\\gnubg\\gnubg-cli.exe", "-t"); startInfo = new ProcessStartInfo(args[0], "-t"); EXPORT_PATH = Directory.GetCurrentDirectory() + "\\"; } startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardError = true; startInfo.RedirectStandardInput = true; startInfo.UseShellExecute = false; Process process = Process.Start(startInfo); process.BeginOutputReadLine(); process.BeginErrorReadLine(); //process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data); process.OutputDataReceived += (s, e) => checkForEndGame(e.Data); process.OutputDataReceived += (s, e) => checkForBoard(e.Data); process.OutputDataReceived += (s, e) => checkForRolledDice(e.Data); process.OutputDataReceived += (s, e) => checkForResignation(e.Data, process); process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data); process.ErrorDataReceived += (s, e) => checkForError(e.Data); process.StandardInput.WriteLine("set matchlength 1001"); process.StandardInput.WriteLine("set cube use off"); process.StandardInput.WriteLine("set output rawboard on"); // start a new game process.StandardInput.WriteLine("new game"); Player player = new Player(); int test = Properties.Settings.Default.totalGames; TimeSpan tempsTotal = new TimeSpan(); double nbCoups = 0.0; while (CountGame < Settings.TOTAL_GAMES)// boucle pour chaque coup qu'on doit jouer. { // on se prépare à jouer le prochain coup. Ready = false; process.StandardInput.WriteLine("roll"); // on roll les dés. int counterTime = 0; while (!Ready) { Thread.Sleep(5); counterTime++; if (counterTime > 100) { process.StandardInput.WriteLine("roll"); // on roll les dés. counterTime = 0; } } Grille grille = new Grille(Rawboard); Stopwatch stopWatch = new Stopwatch(); if (Settings.MESURE_MOVE_TIME) { stopWatch.Start(); } Move nextMove = player.minimax.GetNextMove(grille, Settings.DEPTH);// we ask for the next move to make. nbCoups++; if (Settings.MESURE_MOVE_TIME) { stopWatch.Stop(); tempsTotal = tempsTotal.Add(stopWatch.Elapsed); } process.StandardInput.WriteLine(nextMove.GetCmd()); } process.StandardInput.WriteLine("save match " + EXPORT_PATH + "tester.sgf"); Console.WriteLine("********** finished : " + CountWin + " games won ******************"); if (Settings.MESURE_MOVE_TIME) { Console.WriteLine("Temps de CPU moyen par coup: " + tempsTotal.TotalMilliseconds / nbCoups + "ms."); } Console.ReadLine(); }