public void GetSwarm_Should_Call_IMazeCrawlerSpawner_Spawn_Based_On_Requestor(Direction direction) { var start = new Coordinates(1, 2); var destination = new Coordinates(3, 4); var floorPlan = new char[1][] { new char[] { Map.OCCPD, Map.MOVEW, Map.START, Map.DESTN } }; var map = new Map(floorPlan); var maskedFloorPlan = new char[1][] { new char[] { Map.OCCPD, Map.OCCPD, Map.EMPTY, Map.EMPTY } }; _queen.ScanMap(start, destination, map); MazeCrawlerContext context = null; _spawner.Spawn(Arg.Do <MazeCrawlerContext>(c => context = c)); var crawlerState = Substitute.For <IMazeCrawlerState>(); crawlerState.CanMove(direction).Returns(true); crawlerState.CurrentX.Returns(8); crawlerState.CurrentY.Returns(9); crawlerState.NavigationMode.Returns(CrawlerNavigationMode.Swarm); _queen.GetSwarm(crawlerState); _spawner.Received(1).Spawn(Arg.Any <MazeCrawlerContext>()); context.Start.X.Should().Be(crawlerState.CurrentX); context.Start.Y.Should().Be(crawlerState.CurrentY); context.Destination.Should().Be(destination); context.NavigationMap.FloorPlan.Should().BeEquivalentTo(maskedFloorPlan, o => o.WithStrictOrdering()); context.NavigationMode.Should().Be(crawlerState.NavigationMode); context.Coordinator.Should().Be(_queen); }
public async void Navigate_On_Swarm_Mode_Should_Call_ISwarmCoordinator_GetSwarm_Only_When_There_Are_Forks(int startX, int startY, int destinationX, int destinationY, int numberOfCalls) { var swarmCoordinator = Substitute.For <ISwarmCoordinator>(); swarmCoordinator.GetSwarm(Arg.Any <IMazeCrawlerState>()).Returns(new IMazeCrawler[0]); var crawlerCoordinator = Substitute.For <IMazeCrawlerCoordinator>(); crawlerCoordinator.RequestSwarm(Arg.Any <IMazeCrawlerState>()).Returns(swarmCoordinator); var context = new MazeCrawlerContext { Start = new Coordinates(startX, startY), Destination = new Coordinates(destinationX, destinationY), NavigationMap = new Map(new char[][] { new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY }, new [] { Map.OCCPD, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY } }), NavigationMode = CrawlerNavigationMode.Swarm, Coordinator = crawlerCoordinator }; var crawler = new MazeCrawler(context); await crawler.Navigate(); swarmCoordinator.Received(numberOfCalls).GetSwarm(crawler); }
public async void Navigate_On_Scout_Mode_Should_Recalibrate_After_Each_Fork(int startX, int startY, int destinationX, int destinationY, string expected) { var context = new MazeCrawlerContext { Start = new Coordinates(startX, startY), Destination = new Coordinates(destinationX, destinationY), NavigationMap = new Map(new char[][] { new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY, Map.EMPTY }, new [] { Map.EMPTY, Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY, Map.EMPTY }, new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY, Map.EMPTY }, new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY, Map.EMPTY } }), NavigationMode = CrawlerNavigationMode.Scout, Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); var response = await crawler.Navigate(); response.Arrived.Should().BeTrue(); response.PathTaken.Should().Be(expected); }
public async void Navigate_Should_Call_IMazeSpawner_Spawn() { var start = new Coordinates(1, 2); var destination = new Coordinates(3, 4); var floorPlan = new char[0][]; var map = new Map(floorPlan); _queen.ScanMap(start, destination, map); var crawler = Substitute.For <IMazeCrawler>(); crawler.Navigate().Returns(new NavigationDetails()); MazeCrawlerContext context = null; _spawner.Spawn(Arg.Do <MazeCrawlerContext>(c => context = c)).Returns(crawler); await _queen.Navigate(); _spawner.Received(1).Spawn(Arg.Any <MazeCrawlerContext>()); context.Start.Should().Be(start); context.Destination.Should().Be(destination); context.NavigationMode.Should().Be(CrawlerNavigationMode.Scout); context.Coordinator.Should().Be(_queen); }
public async void Navigate_On_Scout_Mode_Should_BackTrack_To_Alternate_Routes() { var context = new MazeCrawlerContext { Start = new Coordinates(0, 0), Destination = new Coordinates(1, 7), NavigationMap = new Map(new char[][] { new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.OCCPD, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY } }), NavigationMode = CrawlerNavigationMode.Scout, Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); var response = await crawler.Navigate(); response.Arrived.Should().BeTrue(); response.PathTaken.Should().Be("EESSSSSSSW"); }
public async void Navigate_Should_Handle_Single_Route_Maps(CrawlerNavigationMode mode, int startX, int startY, int destinationX, int destinationY, bool arrived, string path) { var context = new MazeCrawlerContext { Start = new Coordinates(startX, startY), Destination = new Coordinates(destinationX, destinationY), NavigationMap = new Map(new char[][] { new [] { Map.EMPTY, Map.OCCPD, Map.OCCPD, Map.OCCPD, Map.OCCPD }, new [] { Map.OCCPD, Map.OCCPD, Map.EMPTY, Map.EMPTY, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.OCCPD, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY, Map.EMPTY, Map.EMPTY } }), NavigationMode = mode, Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); var response = await crawler.Navigate(); response.Arrived.Should().Be(arrived); response.PathTaken.Should().Be(path); }
public async void Navigate_Should_Mask_Map_Passed_In_MazeCrawlerContext() { var floorPlan = new char[1][] { new char[] { Map.OCCPD, Map.MOVEW, Map.START, Map.DESTN } }; var map = new Map(floorPlan); var maskedFloorPlan = new char[1][] { new char[] { Map.OCCPD, Map.OCCPD, Map.EMPTY, Map.EMPTY } }; _queen.ScanMap(new Coordinates(1, 2), new Coordinates(3, 4), map); var crawler = Substitute.For <IMazeCrawler>(); crawler.Navigate().Returns(new NavigationDetails()); MazeCrawlerContext context = null; _spawner.Spawn(Arg.Do <MazeCrawlerContext>(c => context = c)).Returns(crawler); await _queen.Navigate(); _spawner.Received(1).Spawn(Arg.Any <MazeCrawlerContext>()); context.NavigationMap.FloorPlan.Should().BeEquivalentTo(maskedFloorPlan, o => o.WithStrictOrdering()); }
public void CanMove_Should_Return_Correctly(int startX, int startY, Direction direction, bool expected) { var context = new MazeCrawlerContext { Start = new Coordinates(startX, startY), NavigationMap = _canMoveMap, Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); crawler.CanMove(direction).Should().Be(expected); }
public async void Navigate_On_Swarm_Mode_Should_Return_The_First_Task_That_Completes_With_Arrived_True_Result() { var result1 = new NavigationDetails { Arrived = true, PathTaken = "result1" }; var task1 = Task.Run(() => { Task.Delay(300); return(result1); }); var crawler1 = Substitute.For <IMazeCrawler>(); crawler1.Navigate().Returns(task1); var result2 = new NavigationDetails { Arrived = true, PathTaken = "result2" }; var task2 = Task.Run(() => { Task.Delay(500); return(result2); }); var crawler2 = Substitute.For <IMazeCrawler>(); crawler2.Navigate().Returns(task2); var task3 = Task.Run(() => { Task.Delay(100); return(new NavigationDetails { Arrived = false }); }); var crawler3 = Substitute.For <IMazeCrawler>(); crawler3.Navigate().Returns(task3); var crawlers = new [] { crawler1, crawler2, crawler3 }; var swarmCoordinator = Substitute.For <ISwarmCoordinator>(); swarmCoordinator.GetSwarm(Arg.Any <IMazeCrawlerState>()).Returns(crawlers); var crawlerCoordinator = Substitute.For <IMazeCrawlerCoordinator>(); crawlerCoordinator.RequestSwarm(Arg.Any <IMazeCrawlerState>()).Returns(swarmCoordinator); var context = new MazeCrawlerContext { Start = new Coordinates(0, 0), Destination = new Coordinates(0, 1), NavigationMap = new Map(new char[][] { new [] { Map.EMPTY, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD } }), NavigationMode = CrawlerNavigationMode.Swarm, Coordinator = crawlerCoordinator }; var crawler = new MazeCrawler(context); var response = await crawler.Navigate(); response.Should().BeEquivalentTo(result1); }
public void GetNextRoutes_Should_Return_Null_If_Current_Is_At_Destination() { var context = new MazeCrawlerContext { Start = new Coordinates(6, 4), Destination = new Coordinates(6, 4), NavigationMap = new Map(new char[0][]), Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); crawler.GetNextRoutes().Should().BeNull(); }
public MazeCrawler(MazeCrawlerContext context) { Id = Guid.NewGuid().ToString(); CrawlerMap = context.NavigationMap; NavigationMode = context.NavigationMode; _coordinator = context.Coordinator; _start = _current = context.Start; _destination = context.Destination; _stepsTaken = new Queue <char>(); _preference = DirectionHelper.GetPreferences(_start, _destination); }
public void Constructor_Should_Set_Current_Coordinate() { var x = 1; var y = 3; var context = new MazeCrawlerContext { Start = new Coordinates(x, y), Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); crawler.CurrentX.Should().Be(x); crawler.CurrentY.Should().Be(y); }
public void MoveWest_Should_Move_Current_Coordinate_Appropriately(int currentX, int currentY, bool checkLegality, int expectedX, int expectedY) { var context = new MazeCrawlerContext { Start = new Coordinates(currentX, currentY), NavigationMap = _moveMap, Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); crawler.MoveWest(checkLegality); crawler.CurrentX.Should().Be(expectedX); crawler.CurrentY.Should().Be(expectedY); }
public void Constructor_Should_Set_CrawlerMap() { var map = new Map(new char[][] { new [] { Map.OCCPD } }); var context = new MazeCrawlerContext { NavigationMap = map, Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); crawler.CrawlerMap.Should().Be(map); }
public IEnumerable <IMazeCrawler> GetSwarm(IMazeCrawlerState requestor) { Trace($"Checking possible routes from crawler {requestor.Id} location."); // Determines the next possible Direction that can be done from the requestor's current Coordinates. // Create a MazeCrawler for each Direction. var nextSteps = new List <Direction>(); if (requestor.CanMove(Direction.North)) { Trace($"Crawler {requestor.Id} can move North."); nextSteps.Add(Direction.North); } if (requestor.CanMove(Direction.South)) { Trace($"Crawler {requestor.Id} can move South."); nextSteps.Add(Direction.South); } if (requestor.CanMove(Direction.East)) { Trace($"Crawler {requestor.Id} can move East."); nextSteps.Add(Direction.East); } if (requestor.CanMove(Direction.West)) { Trace($"Crawler {requestor.Id} can move West."); nextSteps.Add(Direction.West); } var newStart = new Coordinates(requestor.CurrentX, requestor.CurrentY); var newMap = MaskMap(); var crawlers = new List <IMazeCrawler>(); foreach (var direction in nextSteps) { var context = new MazeCrawlerContext { Start = newStart, Destination = _destination, NavigationMap = newMap, Coordinator = this, NavigationMode = requestor.NavigationMode }; var crawler = _spawner.Spawn(context); Trace($"Moving crawler {requestor.Id} into position."); crawler.Move(direction); crawlers.Add(crawler); } return(crawlers); }
public void MoveEast_Should_Default_Unsupplied_Parameter_To_True(int x, int expectedX) { var context = new MazeCrawlerContext { Start = new Coordinates(x, 0), NavigationMap = new Map(new char[][] { new [] { Map.EMPTY, Map.EMPTY } }), Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); crawler.MoveEast(); crawler.CurrentX.Should().Be(expectedX); }
public void MoveEast_Should_Not_BackTrack() { var context = new MazeCrawlerContext { Start = new Coordinates(0, 0), NavigationMap = new Map(new char[][] { new [] { Map.EMPTY, Map.EMPTY } }), Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); crawler.MoveEast(); crawler.MoveWest(); crawler.CanMove(Direction.West).Should().BeFalse(); crawler.CurrentX.Should().Be(1); }
public void TraceSteps_Should_Return_Correctly(int startX, int startY, bool checkLegality, string expected) { var context = new MazeCrawlerContext { Start = new Coordinates(startX, startY), Destination = new Coordinates(5, 5), NavigationMap = _canMoveMap, Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); crawler.MoveEast(checkLegality) .MoveNorth(checkLegality) .MoveWest(checkLegality) .MoveWest(checkLegality) .MoveSouth(checkLegality); crawler.TraceSteps().Should().Be(expected); }
public async void Navigate_On_Swarm_Mode_Should_Call_Each_IMazeCrawler_Navigate() { var crawler1 = Substitute.For <IMazeCrawler>(); crawler1.Navigate().Returns(Task.FromResult(new NavigationDetails())); var crawler2 = Substitute.For <IMazeCrawler>(); crawler2.Navigate().Returns(Task.FromResult(new NavigationDetails())); var crawler3 = Substitute.For <IMazeCrawler>(); crawler3.Navigate().Returns(Task.FromResult(new NavigationDetails())); var crawlers = new [] { crawler1, crawler2, crawler3 }; var swarmCoordinator = Substitute.For <ISwarmCoordinator>(); swarmCoordinator.GetSwarm(Arg.Any <IMazeCrawlerState>()).Returns(crawlers); var crawlerCoordinator = Substitute.For <IMazeCrawlerCoordinator>(); crawlerCoordinator.RequestSwarm(Arg.Any <IMazeCrawlerState>()).Returns(swarmCoordinator); var context = new MazeCrawlerContext { Start = new Coordinates(0, 0), Destination = new Coordinates(0, 1), NavigationMap = new Map(new char[][] { new [] { Map.EMPTY, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD } }), NavigationMode = CrawlerNavigationMode.Swarm, Coordinator = crawlerCoordinator }; var crawler = new MazeCrawler(context); await crawler.Navigate(); await crawler1.Received(1).Navigate(); await crawler2.Received(1).Navigate(); await crawler3.Received(1).Navigate(); }
public void Spawn_Should_Set_MazeCrawlerContext_Correctly() { var context = new MazeCrawlerContext { Start = new Coordinates(1, 0), NavigationMap = new Map(new char[1][] { new char[] { Map.OCCPD, Map.EMPTY, Map.EMPTY, Map.OCCPD } }), NavigationMode = CrawlerNavigationMode.Swarm, Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = (MazeCrawler)_spwaner.Spawn(context); crawler.CurrentX.Should().Be(context.Start.X); crawler.CurrentY.Should().Be(context.Start.Y); crawler.CrawlerMap.FloorPlan.Should().BeEquivalentTo(context.NavigationMap.FloorPlan, o => o.WithStrictOrdering()); crawler.NavigationMode.Should().Be(context.NavigationMode); }
public void MoveNorth_Should_Not_BackTrack() { var context = new MazeCrawlerContext { Start = new Coordinates(0, 1), NavigationMap = new Map(new char[][] { new [] { Map.EMPTY }, new [] { Map.EMPTY } }), Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); crawler.MoveNorth(); crawler.MoveSouth(); crawler.CanMove(Direction.South).Should().BeFalse(); crawler.CurrentY.Should().Be(0); }
public async Task <NavigationDetails> Navigate() { var map = MaskMap(); var context = new MazeCrawlerContext { Start = _start, Destination = _destination, NavigationMap = map, NavigationMode = CrawlerNavigationMode.Scout, Coordinator = this }; var crawler = _spawner.Spawn(context); var response = await crawler.Navigate(); if (response.Arrived) { response.PathTaken = MapHelper.SimplifyPath(response.PathTaken); } return(response); }
public void GetNextRoutes_Should_Return_Directions_Based_On_Preference(int startX, int startY, int destinationX, int destinationY, Direction[] expected) { var context = new MazeCrawlerContext { Start = new Coordinates(startX, startY), Destination = new Coordinates(destinationX, destinationY), NavigationMap = new Map(new char[][] { new char[] { Map.EMPTY, Map.EMPTY, Map.EMPTY }, new char[] { Map.EMPTY, Map.EMPTY, Map.EMPTY }, new char[] { Map.EMPTY, Map.EMPTY, Map.EMPTY } }), Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); var routes = crawler.GetNextRoutes(); routes.Should().HaveSameCount(expected); routes.Should().Equal(expected); }
public void GetNextRoutes_Should_Return_Empty_If_There_Are_No_Available_Routes() { var context = new MazeCrawlerContext { Start = new Coordinates(0, 1), Destination = new Coordinates(2, 3), NavigationMap = new Map(new char[][] { new char[] { Map.OCCPD, Map.OCCPD, Map.EMPTY }, new char[] { Map.EMPTY, Map.OCCPD, Map.EMPTY }, new char[] { Map.OCCPD, Map.OCCPD, Map.EMPTY }, new char[] { Map.EMPTY, Map.EMPTY, Map.EMPTY } }), Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); var routes = crawler.GetNextRoutes(); routes.Should().BeEmpty(); }
public async void Navigate_On_Swarm_Mode_Should_Call_IMazeCrawlerCoordinator_Debrief(int startX, int startY, int destinationX, int destinationY) { var task = Task.Run(() => { Task.Delay(500); return(new NavigationDetails { Arrived = false }); }); var crawler = Substitute.For <IMazeCrawler>(); crawler.Navigate().Returns(task); var crawlers = new [] { crawler }; var swarmCoordinator = Substitute.For <ISwarmCoordinator>(); swarmCoordinator.GetSwarm(Arg.Any <IMazeCrawlerState>()).Returns(crawlers); var crawlerCoordinator = Substitute.For <IMazeCrawlerCoordinator>(); crawlerCoordinator.RequestSwarm(Arg.Any <IMazeCrawlerState>()).Returns(swarmCoordinator); var context = new MazeCrawlerContext { Start = new Coordinates(startX, startY), Destination = new Coordinates(destinationX, destinationY), NavigationMap = new Map(new char[][] { new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY }, new [] { Map.OCCPD, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.OCCPD, Map.EMPTY }, new [] { Map.EMPTY, Map.EMPTY, Map.EMPTY } }), NavigationMode = CrawlerNavigationMode.Swarm, Coordinator = crawlerCoordinator }; var mazeCrawler = new MazeCrawler(context); await mazeCrawler.Navigate(); crawlerCoordinator.Received(1).Debrief(mazeCrawler); }
public void GetNextRoutes_Should_Return_Directions_Based_On_Availability(int startX, int startY, int destinationX, int destinationY, Direction expected) { var context = new MazeCrawlerContext { Start = new Coordinates(startX, startY), Destination = new Coordinates(destinationX, destinationY), NavigationMap = new Map(new char[][] { new char[] { Map.OCCPD, Map.OCCPD, Map.EMPTY, Map.OCCPD }, new char[] { Map.EMPTY, Map.EMPTY, Map.EMPTY, Map.OCCPD }, new char[] { Map.OCCPD, Map.EMPTY, Map.EMPTY, Map.EMPTY }, new char[] { Map.OCCPD, Map.EMPTY, Map.OCCPD, Map.OCCPD } }), Coordinator = Substitute.For <IMazeCrawlerCoordinator>() }; var crawler = new MazeCrawler(context); var routes = crawler.GetNextRoutes(); routes.Should().HaveCount(1); routes.First().Should().Be(expected); }
public IMazeCrawler Spawn(MazeCrawlerContext context) { return(new MazeCrawler(context)); }