public bool wormholesOK( Galaxy galaxy, bool bothHoles = true, bool hardHoleLimit = true, int HoleCount = 2, bool allowAdjacentHoles = false) { int MaxRadius = galaxy.MaxRadius; SystemTile[][] tiles = galaxy.tiles; int alphaCount = 0; int betaCount = 0; for (int x = 0; x <= MaxRadius * 2; x++) { for (int y = 0; y <= MaxRadius * 2; y++) { if (tiles[x][y].wormholes == Wormhole.Alpha) { alphaCount++; } if (tiles[x][y].wormholes == Wormhole.Beta) { betaCount++; } } } for (int x = 0; x <= MaxRadius * 2; x++) { for (int y = 0; y <= MaxRadius * 2; y++) { if (tiles[x][y].adjacent.Count() != tiles[x][y].adjacent.Distinct().Count()) { return(false); } } } if (bothHoles && alphaCount == 0 && betaCount == 0) { return(false); } if (hardHoleLimit && alphaCount != HoleCount && betaCount != HoleCount) { return(false); } if (alphaCount < HoleCount || betaCount < HoleCount) { return(false); } if (!allowAdjacentHoles) { for (int x = 0; x <= MaxRadius * 2; x++) { for (int y = 0; y <= MaxRadius * 2; y++) { SystemTile thisTile = tiles[x][y]; if (thisTile.wormholes != Wormhole.None) { foreach (SystemTile adjTile in thisTile.adjacent) { if (adjTile.wormholes != Wormhole.None && adjTile.wormholes != thisTile.wormholes) { return(false); } } } } } } return(true); }
public (List <int>, Dictionary <int, List <SystemTile> >, Dictionary <int, List <SystemTile> >) StakeClaims( Galaxy galaxy, int walk = 10, int emptyWalk = 11, int asteroidWalk = 13, int novaWalk = 100, int nebulaWalk = 50, int riftWalk = 05, int wormWalk = 12) { int MaxRadius = galaxy.MaxRadius; SystemTile[][] tiles = galaxy.tiles; List <Tuple <int, int> > HSLocations = galaxy.HSLocations; foreach (Tuple <int, int> start in HSLocations) { SystemTile startTile = tiles[start.Item1][start.Item2]; int playerNum = startTile.playerNum; startTile.claims[playerNum] = 0; SortedList <int, List <SystemTile> > adjacent = new SortedList <int, List <SystemTile> >(); foreach (SystemTile tile in startTile.adjacent) { int walkDist = walk; if (tile.anomaly == Anomaly.Nova) { walkDist = novaWalk; } else if (tile.anomaly == Anomaly.Nebula) { walkDist = nebulaWalk; } else if (tile.anomaly == Anomaly.Asteroids) { walkDist = asteroidWalk; } else if (tile.anomaly == Anomaly.Rift) { walkDist = riftWalk; } else if (tile.planets.Count() == 0) { walkDist = emptyWalk; } if (!adjacent.ContainsKey(walkDist)) { adjacent.Add(walkDist, new List <SystemTile>()); } adjacent[walkDist].Add(tile); } while (adjacent.Count() > 0) { IList <int> keys = adjacent.Keys; int firstKey = keys.First(); List <SystemTile> firstList = adjacent[firstKey]; SystemTile closestTile = firstList.First(); firstList.Remove(closestTile); if (firstList.Count() == 0) { adjacent.Remove(firstKey); } if (!closestTile.claims.ContainsKey(playerNum)) { closestTile.claims.Add(playerNum, firstKey); foreach (SystemTile next in closestTile.adjacent) { if (!next.claims.ContainsKey(playerNum)) { int walkDist = firstKey; if (next.anomaly == Anomaly.Nova) { walkDist += novaWalk; } else if (next.anomaly == Anomaly.Nebula) { walkDist += nebulaWalk; } else if (next.anomaly == Anomaly.Asteroids) { walkDist += asteroidWalk; } else if (next.anomaly.HasFlag(Anomaly.Rift)) { walkDist += riftWalk; } else if ((closestTile.wormholes & next.wormholes) != Wormhole.None) { walkDist += wormWalk; } else if (next.planets.Count() == 0) { walkDist += emptyWalk; } else { walkDist += walk; } if (!adjacent.ContainsKey(walkDist)) { adjacent.Add(walkDist, new List <SystemTile>()); } adjacent[walkDist].Add(next); } } } } } for (int x = 0; x <= MaxRadius * 2; x++) { for (int y = 0; y <= MaxRadius * 2; y++) { SystemTile tile = tiles[x][y]; if (tile.claims.Count() > 0) { tile.bestClaim = tile.claims.Min(claim => claim.Value); if (tile.claims.Count(claim => claim.Value > tile.bestClaim) > 0) { // TODO: no second best claim if > half players have best claim // TODO: rework code so "top half" of claims are allowed tile.secondBestClaim = tile.claims.Where(claim => claim.Value > tile.bestClaim).Min(claim => claim.Value); } } } } Dictionary <int, List <SystemTile> > sliceClaim = new Dictionary <int, List <SystemTile> >(); Dictionary <int, List <SystemTile> > sliceContest = new Dictionary <int, List <SystemTile> >(); List <int> players = new List <int>(); foreach (Tuple <int, int> start in HSLocations) { SystemTile startTile = tiles[start.Item1][start.Item2]; int playerNum = startTile.playerNum; players.Add(playerNum); List <SystemTile> sliceTiles = new List <SystemTile>(); List <SystemTile> contestedTiles = new List <SystemTile>(); for (int x = 0; x <= MaxRadius * 2; x++) { for (int y = 0; y <= MaxRadius * 2; y++) { SystemTile tile = tiles[x][y]; int bestClaim = tile.bestClaim; if (tile.claims.Count() == 0) { continue; } int playerClaim = tile.claims[playerNum]; int contesting = tile.claims.Count(claim => claim.Value == bestClaim); bool playerHasClaim = playerClaim == bestClaim; bool contestedClaim = contesting > 1; if (playerHasClaim) { tile.contestedBy.Add(playerNum); } if (playerHasClaim && contestedClaim) { contestedTiles.Add(tile); } if (playerHasClaim && !contestedClaim) { sliceTiles.Add(tile); } } } sliceClaim.Add(playerNum, sliceTiles); sliceContest.Add(playerNum, contestedTiles); } return(players, sliceClaim, sliceContest); }
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 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 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)); }
static void Main(string[] args) { DateTime start = DateTime.Now; int batchSize = 1000; double bestScore = double.MinValue; Galaxy bestGal = new Galaxy(GalaxyShape.Standard, new Shuffle(), 3, 6); int totalBatches = 0; Object winnerLock = new object(); Shuffle shuffle = new Shuffle(); int timeLimit = 300; while (bestScore < 1.0 && (DateTime.Now - start).TotalSeconds < timeLimit) { Parallel.For(0, batchSize, i => //for (int i = 0; i < batchSize; i++) { Galaxy genGal = new Galaxy(GalaxyShape.Standard, shuffle, 3, 6); genGal.score = new Scorer().scoreGalaxy(genGal, contestMethod: ContestValue.ClaimSize); if (genGal.score > bestScore) { lock (winnerLock) { bestScore = genGal.score; bestGal = genGal; DateTime total = DateTime.Now; Debug.WriteLine($"t: {(total - start).TotalSeconds} => {Math.Round(genGal.score, 3)}"); //Debug.WriteLine($" {genGal.GetTTSString()}"); } } }); //} totalBatches++; } /*for (int pnum = 1; pnum <= bestGal.players; pnum++) * { * Debug.Write($" {pnum} "); * } * Debug.WriteLine(""); * * for (int x = 0; x <= bestGal.MaxRadius * 2; x++) * { * for (int y = 0; y <= bestGal.MaxRadius * 2; y++) * { * SystemTile tile = bestGal.tiles[x][y]; * if (tile.sysNum > 0) * { * for (int pnum = 1; pnum <= bestGal.players; pnum++) * { * double val = 0.0; * if (tile.adjClaims.ContainsKey(pnum)) * { * val = Math.Round(tile.adjClaims[pnum], 3); * } * string print = $"{val}"; * if (val < 10) * { * print = " " + print; * } * while (print.Length < 6) * { * print = print + "0"; * } * print = print.Substring(0, 6); * Debug.Write($"{print} "); * } * Debug.Write($"{tile.ToString()}\n"); * } * } * Debug.Write("\n"); * }*/ Debug.WriteLine($"\n{bestGal.GetTTSString()}"); Debug.WriteLine($"Done after {totalBatches * batchSize} generations"); }