private char selectNextDirection(Point[] players, int myPlayerIndex, bool debugMode) { // 2 // . // 0.....1 // . . // . . //start timer var me = players[myPlayerIndex]; var opponents = players.Except(new[] { me }).ToArray(); if (debugMode) Player.Debug("I'm at {0}", Point.From(me.Index, map.Width, map.Height)); MaxiMinState bestPath = null; var queue = new Queue<MaxiMinState>(); var nodes = nodesFrom(map); // push all my exits to queue bundled with opponents current positions queue.Enqueue(new MaxiMinState { Steps = new[] { me.Index }, Me = me.Index, Opponents = opponents.Select(x => x.Index).ToArray(), Score = 0 }); var counter = 0; // foreach position in queue while (queue.Any() && timer.ElapsedMilliseconds < MAX_AI_TIME_MS) { // position me at new position counter++; var state = queue.Dequeue(); var myPath = string.Join("-", state.Steps); // push all new exits to queue (with path) bundled with opponents new positions foreach (var exit in nodes[state.Me].Neighbours.ToArray())//.Where(x => x.Cost == 1.0) { if (timer.ElapsedMilliseconds >= MAX_AI_TIME_MS) { Console.Error.WriteLine("Looping through exits when time is up."); break; //Time is up } //if (debugMode) Console.Error.Write("{0}: Eval {1}->{2} [{3}]: ", counter, myPath, exit.Node.Id, string.Join(", ", state.Opponents)); if (state.Opponents.Any(x => x == exit.Node.Id)) { //if (debugMode) Console.Error.WriteLine("Walked into opponent"); continue; } // move opponents towards my new position var opponentNewPositions = new int[state.Opponents.Length]; for (int i = 0; i < state.Opponents.Length; i++) { if (timer.ElapsedMilliseconds >= MAX_AI_TIME_MS) { Console.Error.WriteLine("Looping through opponents when time is up."); break; //Time is up } var opponentPath = new Dijkstra(nodes, state.Opponents[i]); var newPosition = opponentPath.GetPathTo(exit.Node.Id).Skip(1).First(); if (newPosition == exit.Node.Id) { //if (debugMode) Console.Error.WriteLine("Killed by opponent"); break; } opponentNewPositions[i] = newPosition; } if (opponentNewPositions.Last() == 0) continue; //We were killed by opponent in inner loop or time is up var score = state.Score + valueOf(map[exit.Node.Id]); var newState = new MaxiMinState { Steps = state.Steps.Concat(new[] { exit.Node.Id }).ToArray(), Me = exit.Node.Id, Opponents = opponentNewPositions, Score = score }; if (bestPath == null || bestPath.Score < newState.Score) { bestPath = newState; if (debugMode) Console.Error.Write("{0}: Eval {1}->{2} [{3}]: ", counter, myPath, exit.Node.Id, string.Join(", ", state.Opponents)); if (debugMode) Console.Error.WriteLine("Score {0}", newState.Score); } //else //{ // if (debugMode) Console.Error.WriteLine("----- {0}", newState.Score); //} queue.Enqueue(newState); } // if queue empty or time is up, break } //walk towards the best path Player.Debug("Calculated {0} iterations. Best path is {1} steps.", counter, bestPath == null ? 0 : bestPath.Steps.Length); var nextTile = bestPath == null || bestPath.Steps.Length < 2 ? me.Index : bestPath.Steps.Skip(1).First(); //if (debugMode) Player.Debug("Moving to {0} through {1}", bestPath == null ? nextTile : bestPath.Me, nextTile); return map.DirectionTo(me, nextTile); }