private int MiniMaxAlgo(Node root, ITeamIdentifier player, ITeamIdentifier opponentPlayer, bool isAdversaryTurn, int depth)
        {
            ITeamIdentifier playingPlayer = isAdversaryTurn ? opponentPlayer : player;
            ITeamIdentifier otherPlayer = !isAdversaryTurn ? opponentPlayer : player;
            Helper.PopulateTree(root, playingPlayer, otherPlayer, 1);
            if (root.Combinaison.NextResolvableState.IsGameOver() || !root.ChildrenNodes.Any() || depth == 0)
            {
                return root.Combinaison.NextResolvableState.GetValueFor(player);
            }
            --depth;

            int bestCurrentValueForCurrentPlayerTurn = isAdversaryTurn ? int.MaxValue : int.MinValue;

            foreach (var node in root.ChildrenNodes)
            {
                int nodeValue = MiniMaxAlgo(node, player, opponentPlayer, !isAdversaryTurn, depth);

                // Find min
                if (isAdversaryTurn)
                {
                    bestCurrentValueForCurrentPlayerTurn = Math.Min(nodeValue, bestCurrentValueForCurrentPlayerTurn);
                }
                // Find max
                else
                {
                    bestCurrentValueForCurrentPlayerTurn = Math.Max(nodeValue, bestCurrentValueForCurrentPlayerTurn);
                }
            }

            return bestCurrentValueForCurrentPlayerTurn;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="root"></param>
        /// <param name="player"></param>
        /// <param name="opponentPlayer"></param>
        /// <param name="alpha">Best already explored option along path to the root for the maximizer</param>
        /// <param name="beta">Best already explored option along path to the root for the minimizer</param>
        /// <param name="isAdversaryTurn"></param>
        /// <returns></returns>
        private int AlphaBetaAlgo(Node root, ITeamIdentifier player, ITeamIdentifier opponentPlayer, int alpha, int beta, bool isAdversaryTurn, int depth)
        {
            ITeamIdentifier playingPlayer = isAdversaryTurn ? opponentPlayer : player;
            ITeamIdentifier otherPlayer = !isAdversaryTurn ? opponentPlayer : player;
            Helper.PopulateTree(root, playingPlayer, otherPlayer, 1);
            if (root.Combinaison.NextResolvableState.IsGameOver() || !root.ChildrenNodes.Any() || depth == 0)
            {
                return root.Combinaison.NextResolvableState.GetValueFor(player);
            }
            --depth;

            int bestCurrentValueForCurrentPlayerTurn = isAdversaryTurn ? int.MaxValue : int.MinValue;

            foreach (var node in root.ChildrenNodes)
            {
                int nodeValue = AlphaBetaAlgo(node, player, opponentPlayer, alpha, beta, !isAdversaryTurn, depth);

                // Minimizer
                if (isAdversaryTurn)
                {
                    bestCurrentValueForCurrentPlayerTurn = Math.Min(nodeValue, bestCurrentValueForCurrentPlayerTurn);

                    beta = Math.Min(bestCurrentValueForCurrentPlayerTurn, beta);

                    if (beta < alpha)
                    {
                        return beta;
                    }
                }
                // Maximizer
                else
                {
                    bestCurrentValueForCurrentPlayerTurn = Math.Max(nodeValue, bestCurrentValueForCurrentPlayerTurn);

                    alpha = Math.Max(bestCurrentValueForCurrentPlayerTurn, alpha);

                    if (alpha > beta)
                    {
                        return alpha;
                    }
                }
            }
            return bestCurrentValueForCurrentPlayerTurn;
        }
        public static void PopulateTree(Node root, ITeamIdentifier playerTurn, ITeamIdentifier opponentPlayer, int depthAvailable)
        {
            if (depthAvailable == 0)
            {
                root.ChildrenNodes = new List<Node>();
                return;
            }

            List<MoveStateCombinaison> childrens = root.Combinaison.NextResolvableState.GetPossibleStates(playerTurn).ToList();
            root.ChildrenNodes = childrens.Select(children => new Node()
            {
                Combinaison = children
            }).ToList();

            foreach (Node children in root.ChildrenNodes.Where(pair => !pair.Combinaison.NextResolvableState.IsGameOver()))
            {
                PopulateTree(children, opponentPlayer, playerTurn, depthAvailable - 1);
            }
        }
        public IMove FindBestMove(IResolvableState resolvableState, ITeamIdentifier player, ITeamIdentifier opponentPlayer)
        {
            Node root = new Node()
            {
                Combinaison = new MoveStateCombinaison()
                {
                    NextResolvableState = resolvableState,
                    Move = null
                }
            };

            Helper.PopulateTree(root, player, opponentPlayer, 1);

            int currentBestValue = Int32.MinValue;
            IMove currentBestMove = null;

            Stopwatch watch = new Stopwatch();
            watch.Start();

            foreach (var node in root.ChildrenNodes)
            {
                // The next turn is the adversary turn
                int nodeValue = NodeSolver.CalculateNodeValue(node, player, opponentPlayer, true, Depth);
                Console.WriteLine("{0} --> {1}", node.Combinaison.Move.GetDescription(), nodeValue);
                if (nodeValue > currentBestValue)
                {
                    currentBestValue = nodeValue;
                    currentBestMove = node.Combinaison.Move;
                }
            }

            watch.Stop();
            Console.WriteLine("Elapse time: {0}", watch.ElapsedMilliseconds);

            return currentBestMove;
        }
 public int CalculateNodeValue(Node root, ITeamIdentifier player, ITeamIdentifier opponentPlayer, bool isAdversaryTurn, int depth)
 {
     return AlphaBetaAlgo(root, player, opponentPlayer, Int32.MinValue, Int32.MaxValue, true, depth);
 }
 public int CalculateNodeValue(Node root, ITeamIdentifier player, ITeamIdentifier opponentPlayer, bool isAdversaryTurn, int depth)
 {
     return MiniMaxAlgo(root, player,opponentPlayer, true, depth);
 }