using GlobalClassLib; using ONDServer.Map; namespace ONDServer.Enemies; public class RoamingPathfinder : Pathfinder { public Predicate AdditionalTileFilter{ get; set; } = _ => true; public Predicate AdditionalConnectorFilter{ get; set; } = _ => true; protected int tolerance; public List TakenPath { get; } = new(); private Random random = new(); // private Queue tilesToCrawl = new(); // private Dictionary distances = new(); // private Func defaultConnectorFilter; public RoamingPathfinder(Enemy enemy, int tolerance) : base(enemy) { this.tolerance = tolerance; } protected Dictionary Search(MapTile startingTile) { Dictionary distances = new(){ [startingTile] = 0 }; Queue tilesToSearch = new(); tilesToSearch.Enqueue(startingTile); while (tilesToSearch.Count > 0){ MapTile currentTile = tilesToSearch.Dequeue(); List neighbours = GetNeighbours(currentTile, c => AdditionalConnectorFilter(c) && (!c.Blocked || c.Type == ConnectorType.DOOR_OFFICE) && (!distances.ContainsKey(c.OtherTile(currentTile)) || distances[c.OtherTile(currentTile)] > distances[currentTile] + c.Value), t => AdditionalTileFilter(t) && (!Enemy.BlocksTile || EnemyManager.GetByLocation(t).All(e => !e.BlocksTile || e == Enemy)) && Server.Players.All(p => p.Value.state.officeTileId != t.Id)); neighbours.ForEach(t => { distances[t] = distances[currentTile] + currentTile.GetConnector(t)!.Value; tilesToSearch.Enqueue(t); }); } return distances; } // private void CrawlStep(MapTile tile) { // List neighbours = GetNeighbours(tile, // c => // AdditionalConnectorFilter(c) && // (!c.Blocked || c.Type == ConnectorType.DOOR_OFFICE) && // tile != Enemy.Location && // (!distances.ContainsKey(c.OtherTile(tile)) || distances[c.OtherTile(tile)] > distances[tile] + c.Value), // t => // AdditionalTileFilter(t) && // (!Enemy.BlocksTile || EnemyManager.GetByLocation(t).All(e => !e.BlocksTile || e == Enemy)) && // Server.Players.All(p => p.Value.state.officeTileId != t.Id)); // // neighbours.ForEach(t => distances[t] = distances[tile] + tile.GetConnector(t)!.Value); // // if (neighbours.Count != 0){ // neighbours.ForEach(t => CrawlStep(t)); // } // } public override Decision DecideNext(MapTile goal) { Dictionary distances = Search(goal); List closerTiles = GetNeighbours(Enemy.Location, c => AdditionalConnectorFilter(c) && !c.Blocked || c.Type == ConnectorType.DOOR_OFFICE, t => AdditionalTileFilter(t) && distances.ContainsKey(t) && distances[t] + t.GetConnector(Enemy.Location).Value <= distances[Enemy.Location] + tolerance); if (closerTiles.Contains(goal)){ if (Enemy.Location.GetConnector(goal)!.Blocked){ return Decision.Reset(); } IEnumerable players = Server.Players.Values.Where(p => p.state.officeTileId == goal.Id); if (players.Count() == 1){ return Decision.Attack(players.First()); } return Decision.Move(goal); } if (closerTiles.Count != 0 && closerTiles.All(t => TakenPath.Contains(t))){ TakenPath.Clear(); return DecideNext(goal); } closerTiles.RemoveAll(t => TakenPath.Contains(t)); closerTiles.ForEach(t => distances[t] += Enemy.Location.GetConnector(t)!.Value); double roll = random.NextDouble() * closerTiles.Sum(t => 1.0 / distances[t]); foreach (var tile in closerTiles){ double value = 1.0 / distances[tile]; if (roll <= value){ TakenPath.Add(tile); return Decision.Move(tile); } roll -= value; } return Decision.Wait(); } }