public int ComputeScore(MineDistances distances) { return(distances.GetMines().Sum(mine => this.Trees.Sum(tree => tree.Contains(mine) ? tree.Sum(site => distances.GetSquaredDistance(mine, site)) : 0))); }
static Move V4Strategy( MoveMessage message, SolverState solverState) { var startTime = DateTime.UtcNow; var deadLine = startTime.AddMilliseconds(900); var myId = solverState.initialState.punter.Value; var initialMap = solverState.initialState.map; var takenRivers = Utils.ConvertMovesToRivers(initialMap, solverState.moves, (id) => true) .ToLookup(river => river, river => true); var availableRivers = initialMap.rivers .Where(river => !takenRivers.Contains(river)) .ToList(); var canUseOptions = solverState.initialState.settings.options && solverState.moves.Count(move => move.option != null && move.option.punter == myId) < initialMap.mines.Count; var adjacencyMap = new AdjacencyMap(initialMap.rivers); var mineDistances = new MineDistances(initialMap, adjacencyMap); var setupDoneTime = DateTime.UtcNow; // if we see a choke, take it var chokeFindTask = Task.Run(() => { var punters = new List <int>() { myId }; if (solverState.initialState.punters.Value == 2) { punters.Add(1 - myId); } foreach (var punter in punters) { var availableOptions = new List <River>(); if (canUseOptions && punter == myId) { var takenOptions = Utils.ConvertMovesToRivers(initialMap, solverState.moves.Where(move => move.option != null), (id) => true) .ToLookup(river => river, river => true); availableOptions = Utils.ConvertMovesToRivers(initialMap, solverState.moves, (id) => id != myId) .Where(river => !takenOptions.Contains(river)) .ToList(); } var chokes = FindChokes( initialMap.mines, Utils.ConvertMovesToRivers(initialMap, solverState.moves, (id) => id == punter).ToList(), availableRivers.Concat(availableOptions).ToList(), deadLine.AddMilliseconds(-100)); if (chokes.Any()) { var river = chokes[0][0]; var chokeAnalysisDoneTime = DateTime.UtcNow; Log(myId, string.Format("[{0}] [{1}] [{2}/{3}]", punter == myId ? "TakeChoke " : "BlockChoke", (int)(chokeAnalysisDoneTime - startTime).TotalMilliseconds, (int)(setupDoneTime - startTime).TotalMilliseconds, (int)(chokeAnalysisDoneTime - setupDoneTime).TotalMilliseconds)); return(availableOptions.Contains(river) ? CreateOptionMove(myId, river) : CreateClaimMove(myId, river)); } } return(null); }); // otherwise just play a move that joins two trees, increases liberty, or increases score var trees = new TreeSet( Utils.ConvertMovesToRivers(initialMap, solverState.moves, (id) => id == myId), initialMap.mines); var riversToConsider = availableRivers .Where(river => trees.Contains(river.source) || trees.Contains(river.target)) .DefaultIfEmpty(availableRivers.First()); var riversConsidered = from river in riversToConsider where DateTime.UtcNow < deadLine let newTrees = trees.AddRiver(river) let treeCount = newTrees.Trees.Count let liberty = newTrees.ComputeLiberty(availableRivers, adjacencyMap) let score = newTrees.ComputeScore(mineDistances) select new { river = river, liberty = liberty, score = score, treeCount = treeCount }; var rankedRivers = riversConsidered .ToList() .OrderBy(i => i.treeCount) .ThenByDescending(i => i.liberty) .ThenByDescending(i => i.score); var ans = CreateClaimMove(myId, rankedRivers.First().river); var analysisDoneTime = DateTime.UtcNow; var zero = TimeSpan.FromTicks(0); var waitTime = deadLine - DateTime.UtcNow; waitTime = waitTime < zero ? zero : waitTime; chokeFindTask.Wait(waitTime); if (chokeFindTask.IsCompleted && chokeFindTask.Result != null) { return(chokeFindTask.Result); } var doneTime = DateTime.UtcNow; Log(myId, string.Format("[NormalMove] [{0}] [{1}/{2}/{3}] [Trees:{4}] [Liberties:{5}] [Score:{6}]", (int)(doneTime - startTime).TotalMilliseconds, (int)(setupDoneTime - startTime).TotalMilliseconds, (int)(analysisDoneTime - setupDoneTime).TotalMilliseconds, (int)(doneTime - analysisDoneTime).TotalMilliseconds, rankedRivers.First().treeCount, rankedRivers.First().liberty, rankedRivers.First().score)); return(ans); }
static void Main(string[] args) { var mapFile = Path.Combine(RootPath, "maps", args[0] + ".json"); var ais = args.Skip(1).ToList(); var map = JsonConvert.DeserializeObject <Map>(File.ReadAllText(mapFile)); var states = Enumerable.Range(0, ais.Count) .Select(idx => RunAi <ReadyMessage>( 0, ais[idx], new ServerMessage() { punter = idx, punters = ais.Count, map = map, settings = new Settings() { options = true } }).state) .ToList(); var lastMoves = Enumerable.Range(0, ais.Count) .Select(idx => new Move() { pass = new PassMove() { punter = idx } }) .ToList(); var allMoves = new List <Move>(); foreach (var moveNumber in Enumerable.Range(0, map.rivers.Count)) { var aiIdx = moveNumber % ais.Count; var ch = aiIdx == 0 ? '.' : aiIdx == 1 ? ':' : '*'; Console.Error.Write(ch); Console.Error.Flush(); var move = RunAi <Move>( moveNumber, ais[aiIdx], new ServerMessage() { move = new MoveMessage() { moves = lastMoves }, state = states[aiIdx] }); states[aiIdx] = move.state; move.state = null; lastMoves[aiIdx] = move; allMoves.Add(move); } var mineDistances = new MineDistances(map, new AdjacencyMap(map.rivers)); var scores = Enumerable.Range(0, ais.Count) .Select(idx => (new TreeSet(Utils.ConvertMovesToRivers(map, allMoves, (id) => id == idx))).ComputeScore(mineDistances)) .ToList(); var output = new Output() { score = Math.Sign(scores[0] - scores[1]), scores = scores, map = args[0], verbose = new VerboseOutput() { moves = allMoves } }; Console.Error.WriteLine(); Console.WriteLine(JsonConvert.SerializeObject(output, Formatting.Indented, Parser.SerializerSettings)); }