/// <summary>
        /// Gets the path length from the start to the target
        /// </summary>
        /// <param name="team">Team</param>
        public int GetPathLength(sbyte team)
        {
            if (From == null)
            {
                return(To.GetBoardIndex(team) - new Square(To.QuadrantValue, 0).GetBoardIndex(team));
            }

            return(To.GetBoardIndex(team) - From.GetBoardIndex(team));
        }
        /// <summary>
        /// Gets the distance to a square
        /// </summary>
        /// <param name="square">Square</param>
        /// <param name="team">Team to use as the path perspective</param>
        public int DistanceTo(Square square, sbyte team)
        {
            int index1 = square.GetBoardIndex(team);
            int index2 = GetBoardIndex(team);

            return(index1 - index2);
        }
        /// <summary>
        /// Gets the chronological path of squares from the start to the target squares
        /// </summary>
        /// <param name="team">Team</param>
        public Square[] GetPath(sbyte team)
        {
            Square from = (From == null) ? new Square(To.QuadrantValue, 0) : From;

            int pathLength = GetPathLength(team);

            Square[] path = new Square[pathLength];

            for (int i = 0; i < path.Length; i++)
            {
                int squareIndex = from.GetBoardIndex(team) + i;

                int targetQuadIndexUnordered = (squareIndex / Board.QUAD_LENGTH);
                int targetQuadIndex          = (targetQuadIndexUnordered < Board.QUAD_COUNT) ? Board.QUAD_ORDER[team][targetQuadIndexUnordered] : team + 4;
                int quad   = (targetQuadIndex < Board.QUAD_COUNT) ? Board.GetQuadIndex(team, targetQuadIndex) : team + 4;
                int square = squareIndex % Board.QUAD_LENGTH;
                path[i] = new Square((quad < Board.QUAD_COUNT) ? Board.QUAD_ORDER[team][quad] : quad, square);
            }

            return(path);
        }
        /// <summary>
        /// Evaluates a teams overall score in units of scored marbles (5 = won)
        /// </summary>
        /// <param name="position">Position to evaluate for a team</param>
        /// <param name="team"></param>
        /// <returns></returns>
        public double EvaluateTeam(Position position, sbyte team, bool rolledDoubles)
        {
            //Score in units of scores (5 = won)
            double score = 0.0;

            const double marbleValue = 0.1;

            //Sorted list of marbles
            Square[] marbles           = GetMarbles(position, team);
            int      activeMarbles     = ActiveMarbles(marbles);
            int      activePathMarbles = ActivePathMarbles(marbles);

            int[]    activeEnemyMarbleCount = null;
            Square[] enemies = GetEnemyMarbles(position, team, out activeEnemyMarbleCount);

            //Evaluation scorelist
            //O-Check for impossible position with roll for 1 to win
            //O-Evaluate distance to goal)
            //O-Evaluate danger (probability of being taken) (Add special case for being on enemy spawn squares?)
            //O-Evaluate scored marbles (Add bonus for being aligned back in a row)

            //-Check for impossible position with roll for 1 to win
            if (activeMarbles == Board.TEAM_SIZE)
            {
                if (MustRollDoubles3x(position, team))
                {
                    return(DiceRoll.P_ROLLING_DOUBLES_3X);
                }
            }

            //-Evaluate distance to goal
            //-Pentalize marbles on own goal (for taking out)
            Square endGoal  = GetEndGoal(position, team);
            double endIndex = endGoal.GetBoardIndex(team);

            double distanceScore = 0.0;

            for (int i = 0; i < marbles.Length; i++)
            {
                if (marbles[i] != null)
                {
                    if (marbles[i].IsInPath())
                    {
                        if (marbles[i].GetBoardIndex(team) == 1)
                        {
                            score -= marbleValue;
                        }

                        double dis = (endIndex - marbles[i].DistanceTo(endGoal, team));
                        distanceScore += dis;
                    }
                }
            }

            //Add score for activity
            score += activeMarbles * marbleValue;

            //Add the distance traveled
            if (activeMarbles > 0)
            {
                score += (distanceScore - 1) / (double)(endIndex * activeMarbles);
            }

            //-Evaluate danger (probability of being taken) (Add special case for being on enemy spawn squares?)
            double dangerScore = 0.0f;

            if (!rolledDoubles)
            {
                //Add special case for being on enemy spawn squares
                for (int m = 0; m < marbles.Length; m++)
                {
                    if (marbles[m] != null)
                    {
                        double weight = 2 * ((endIndex - marbles[m].DistanceTo(endGoal, team)) / endIndex);
                        for (sbyte eT = 0; eT < Board.TEAM_COUNT; eT++)
                        {
                            if (eT != team)
                            {
                                int marbleCount = activeEnemyMarbleCount[eT];
                                if (marbleCount > 0)
                                {
                                    Square enemySpawn = new Square(eT, 0);
                                    if (marbles[m].Equals(enemySpawn))
                                    {
                                        dangerScore += weight * DiceRoll.P_GETTING_OUT;
                                    }
                                }
                            }
                        }
                    }
                }

                for (int x = 0; x < enemies.Length; x++)
                {
                    if (enemies[x] != null)
                    {
                        if (enemies[x].IsInPath())
                        {
                            for (int t = 0; t < marbles.Length; t++)
                            {
                                if (marbles[t] != null)
                                {
                                    if (marbles[t].IsInPath())
                                    {
                                        double weight = (endIndex - marbles[t].DistanceTo(endGoal, team)) / endIndex;

                                        int distance = marbles[t].DistanceTo(enemies[x], team);
                                        if (distance > 0)
                                        {
                                            if (distance <= 6)
                                            {
                                                int marbleTeam         = position.Get(enemies[x]);
                                                int activeEnemyMarbles = activeEnemyMarbleCount[marbleTeam]; //Active in path
                                                if (activeEnemyMarbles >= 2)
                                                {
                                                    dangerScore += weight * DiceRoll.P_ANY_NUM;
                                                }
                                                else if (activeEnemyMarbles >= 1)
                                                {
                                                    dangerScore += weight * (DiceRoll.P_ANY_NUM * DiceRoll.P_GETTING_OUT);
                                                }
                                                else
                                                {
                                                    double probability = DiceRoll.GetProbabilityQuick(distance);
                                                    dangerScore += weight * probability;
                                                }
                                            }
                                            else if (distance < 36) //If greater than, the probability is 0, so no danger
                                            {
                                                double probability = DiceRoll.GetProbabilityQuick(distance);
                                                dangerScore += weight * probability;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                //Subtract danger score
                score -= dangerScore;
            }

            double eDistanceScore = 0.0;
            double eDividendTotal = 0.0;
            int    eCount         = 0;

            //O-Evaluate other marbles
            for (sbyte sEM = 0; sEM < enemies.Length; sEM++)
            {
                if (enemies[sEM] != null)
                {
                    if (enemies[sEM].IsInPath())
                    {
                        sbyte  eTeam    = (sbyte)position.Get(enemies[sEM]);
                        Square eEndGoal = GetEndGoal(position, eTeam);

                        double eDividend = eEndGoal.GetBoardIndex(eTeam);
                        eDistanceScore += (eDividend - enemies[sEM].DistanceTo(eEndGoal, eTeam));

                        eDividendTotal += eDividend;
                        eCount++;
                    }
                }
            }

            if (eCount > 0)
            {
                //We don't want a full negative impact from enemy moves (between 1/2-3/4 scale factor)
                score -= 0.55 * (eDistanceScore / eDividendTotal);
            }

            //-Evaluate scored marbles (Add bonus for being aligned back in a row)
            bool inARow = true;

            int    marblesScored      = 0;
            double marblesScoredScore = 0; //Marbles as far back as possible = 1 score

            Square[] homeSquares = GetHomeSquares(team);
            for (int i = homeSquares.Length - 1; i >= 0; i--)
            {
                int marble = position.Get(homeSquares[i]);
                if (marble == team)
                {
                    if (inARow)
                    {
                        marblesScoredScore++;
                    }
                    else
                    {
                        marblesScoredScore += 0.5 + (0.5 / (double)(homeSquares.Length - i));
                    }

                    marblesScored++;
                }
                else
                {
                    //Gap, stop giving points
                    inARow = false;
                }
            }


            score += marblesScoredScore;

            return(score);
        }