public double GetResourceScoreSlice(
            Galaxy galaxy,
            List <int> players,
            Dictionary <int, List <SystemTile> > sliceClaim,
            Dictionary <int, List <SystemTile> > sliceContest,
            ResourceScoreMethod resMethod = ResourceScoreMethod.MaxVal,
            double ResInfRatio            = 1.0,
            double ResScaling             = 2.0)
        {
            double resourceScore = 0;

            switch (resMethod)
            {
            case ResourceScoreMethod.Separate:

                double bestRes  = double.MinValue;
                double worstRes = double.MaxValue;

                double bestInf  = double.MinValue;
                double worstInf = double.MaxValue;

                foreach (int player in players)
                {
                    double res = sliceVal(sliceClaim[player], sliceContest[player], res: true);

                    bestRes  = res > bestRes ? res : bestRes;
                    worstRes = res < worstRes ? res : worstRes;

                    double inf = sliceVal(sliceClaim[player], sliceContest[player], res: false);

                    bestInf  = inf > bestInf ? inf : bestInf;
                    worstInf = inf < worstInf ? inf : worstInf;
                }

                resourceScore =
                    (Math.Pow(worstRes / bestRes, ResScaling) +
                     ResInfRatio * Math.Pow(worstInf / bestInf, ResScaling));

                resourceScore /= (1 + ResInfRatio);

                break;

            case ResourceScoreMethod.DirectSum:

                double best  = double.MinValue;
                double worst = double.MaxValue;
                foreach (int player in players)
                {
                    double resValue = sliceVal(sliceClaim[player], sliceContest[player], res: true);
                    double infValue = sliceVal(sliceClaim[player], sliceContest[player], res: true);

                    double value = resValue + ResInfRatio * infValue;
                    best  = value > best ? value : best;
                    worst = value < worst ? value : worst;
                }
                resourceScore = Math.Pow(worst / best, ResScaling);

                break;

            case ResourceScoreMethod.MaxVal:
            default:

                double bestVal  = double.MinValue;
                double worstVal = double.MaxValue;

                foreach (int player in players)
                {
                    double maxVal = 0;
                    if (sliceClaim[player].Where(tile => tile.planets.Count > 0).Count() > 0)
                    {
                        maxVal +=
                            sliceClaim[player].Where(tile => tile.planets.Count > 0).Select(tile =>
                                                                                            tile.planets.Select(planet =>
                                                                                                                Math.Max(planet.resources, ResInfRatio * planet.influence)
                                                                                                                ).Aggregate((i, j) => i + j)
                                                                                            ).Aggregate((i, j) => i + j);
                    }
                    if (sliceContest[player].Where(tile => tile.planets.Count > 0).Count() > 0)
                    {
                        maxVal +=
                            sliceContest[player].Where(tile => tile.planets.Count > 0).Select(tile =>
                                                                                              (double)(tile.planets.Select(planet =>
                                                                                                                           Math.Max(planet.resources, ResInfRatio * planet.influence)
                                                                                                                           ).Aggregate((i, j) => i + j)) / tile.contestedBy.Count()
                                                                                              ).Aggregate((i, j) => i + j);
                    }

                    bestVal  = maxVal > bestVal ? maxVal : bestVal;
                    worstVal = maxVal < worstVal ? maxVal : worstVal;
                }

                resourceScore = Math.Pow(worstVal / bestVal, ResScaling);
                break;
            }

            return(resourceScore);
        }
        public double scoreGalaxy(
            Galaxy galaxy,
            bool bothHoles                = true,
            bool hardHoleLimit            = true,
            int HoleCount                 = 2,
            bool allowAdjacentHoles       = false,
            bool allowAdjacentAnomalies   = false,
            ContestValue contestMethod    = ContestValue.ClaimSize,
            ResourceScoreMethod resMethod = ResourceScoreMethod.MaxVal,
            double ResInfRatio            = 1.0,
            double ResScaling             = 2.0,
            double claimExponent          = -3.0)
        {
            double score         = 0.0;
            double resourceScore = 0.0;

            int MaxRadius = galaxy.MaxRadius;

            SystemTile[][]           tiles       = galaxy.tiles;
            List <Tuple <int, int> > HSLocations = galaxy.HSLocations;

            if (!wormholesOK(
                    galaxy,
                    bothHoles,
                    hardHoleLimit,
                    HoleCount,
                    allowAdjacentHoles))
            {
                return(0.0);
            }

            if (!AnomaliesOK(galaxy, allowAdjacentAnomalies))
            {
                return(0.0);
            }

            List <int> players;
            Dictionary <int, List <SystemTile> > sliceClaim;
            Dictionary <int, List <SystemTile> > sliceContest;


            (players, sliceClaim, sliceContest) = StakeClaims(galaxy);
            if (contestMethod == ContestValue.Slices)
            {
                resourceScore =
                    GetResourceScoreSlice(
                        galaxy,
                        players,
                        sliceClaim,
                        sliceContest,
                        resMethod,
                        ResInfRatio,
                        ResScaling);
            }
            else
            {
                resourceScore =
                    GetResourceScoreClaims(
                        galaxy,
                        players,
                        resMethod,
                        contestMethod,
                        ResInfRatio,
                        ResScaling,
                        claimExponent);
            }

            score = resourceScore;

            return(score);
        }
        public double GetResourceScoreClaims(
            Galaxy galaxy,
            List <int> players,
            ResourceScoreMethod resMethod = ResourceScoreMethod.MaxVal,
            ContestValue contestMethod    = ContestValue.TopAndRunnerUp,
            double ResInfRatio            = 1.0,
            double ResScaling             = 2.0,
            double claimExponent          = -2.0)
        {
            Dictionary <int, double> resourceClaims = new Dictionary <int, double>();

            foreach (int pnum in players)
            {
                resourceClaims.Add(pnum, 0);
            }

            int MaxRadius = galaxy.MaxRadius;

            for (int x = 0; x <= 2 * MaxRadius; x++)
            {
                for (int y = 0; y <= 2 * MaxRadius; y++)
                {
                    SystemTile tile = galaxy.tiles[x][y];
                    if (tile.sysNum > 0 && tile.planets.Count() > 0)
                    {
                        Dictionary <int, double> claims = new Dictionary <int, double>();
                        foreach (int pnum in tile.claims.Keys)
                        {
                            switch (contestMethod)
                            {
                            case ContestValue.Slices:
                                if (claims[pnum] == tile.bestClaim)
                                {
                                    claims.Add(pnum, 1.0);
                                }
                                break;

                            case ContestValue.ClaimSize:
                                if (tile.bestClaim > 0)
                                {
                                    claims.Add(pnum, Math.Pow(tile.claims[pnum], claimExponent));
                                }
                                else if (claims[pnum] == tile.bestClaim)
                                {
                                    claims.Add(pnum, 1.0);
                                }
                                break;

                            case ContestValue.TopAndRunnerUp:
                                if (tile.bestClaim == 0 && claims[pnum] == tile.bestClaim)
                                {
                                    claims.Add(pnum, 1.0);
                                }
                                else if (claims[pnum] == tile.bestClaim || claims[pnum] == tile.secondBestClaim)
                                {
                                    claims.Add(pnum, Math.Pow(tile.claims[pnum], claimExponent));
                                }
                                break;
                            }
                        }
                        if (claims.Count() == 0)
                        {
                            throw new Exception("Every system should have at least one claim, right?");
                        }
                        double claimScale = claims.Sum(claim => claim.Value);
                        foreach (KeyValuePair <int, double> claim in claims)
                        {
                            double val = 0.0;
                            switch (resMethod)
                            {
                            case ResourceScoreMethod.DirectSum:
                                val = tile.GetResources() + ResInfRatio * tile.GetInfluence();
                                break;

                            case ResourceScoreMethod.Separate:
                                throw new Exception("Not supporting \"separate\" for claim method");

                            case ResourceScoreMethod.MaxVal:
                                val = tile.planets.Sum(planet => Math.Max(planet.resources, ResInfRatio * planet.influence));
                                break;
                            }
                            tile.adjClaims.Add(claim.Key, claim.Value / claimScale);
                            resourceClaims[claim.Key] += val * claim.Value / claimScale;
                        }
                    }
                }
            }

            double minSlice = resourceClaims.Min(claim => claim.Value);
            double maxSlice = resourceClaims.Max(claim => claim.Value);

            return(Math.Pow(minSlice / maxSlice, ResScaling));
        }