/// <summary> /// The SimulationTimerEventHandler method is called when the simulation timer expires. /// It updates the current state of the simulation. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void SimulationTimerEventHandler(object sender, EventArgs e) { try { if (SimulationState == SimulationState.Running) { MazeCell robotLocation = MazeCells.First(x => x.ContainsRobot); // Retrieve the current location of the robot. int cellIndex = MazeCells.IndexOf(robotLocation); // Retrieve the index of the cell. // Determine the indexes for the cell's neighbours. int northNeighbourIndex = cellIndex - MazeWidthHeightCells; int eastNeighbourIndex = cellIndex + 1; int southNeighbourIndex = cellIndex + MazeWidthHeightCells; int westNeighbourIndex = cellIndex - 1; // Determine if the cell is on the north/east/south/west edge of the maze - certain neighbours must be ignored if the current cell is on an edge. bool northEdge = cellIndex < MazeWidthHeightCells ? true : false; bool eastEdge = ((cellIndex + 1) % MazeWidthHeightCells) == 0 ? true : false; bool westEdge = (cellIndex % MazeWidthHeightCells) == 0 ? true : false; bool southEdge = (cellIndex + MazeWidthHeightCells) >= (MazeWidthHeightCells * MazeWidthHeightCells) ? true : false; // Retrieve the cell's neighbours. MazeCell northCell = null; MazeCell eastCell = null; MazeCell southCell = null; MazeCell westCell = null; // North cell. if (!northEdge && IsCellIndexValid(northNeighbourIndex)) { northCell = MazeCells[northNeighbourIndex]; } // East cell. if (!eastEdge && IsCellIndexValid(eastNeighbourIndex)) { eastCell = MazeCells[eastNeighbourIndex]; } // South cell. if (!southEdge && IsCellIndexValid(southNeighbourIndex)) { southCell = MazeCells[southNeighbourIndex]; } // West cell. if (!westEdge && IsCellIndexValid(westNeighbourIndex)) { westCell = MazeCells[westNeighbourIndex]; } // Create a maze segment at the robot's current location. MazeSegment mazeSegment = new MazeSegment(robotLocation, northCell, eastCell, southCell, westCell); _robot.Move(mazeSegment); // Move the robot. SimulationTime = SimulationTime.Add(TimeSpan.FromMilliseconds(Constants.DefaultStepIntervalMilliSeconds)); } } catch (Exception ex) { throw new Exception("Maze.SimulationTimerEventHandler(object sender, EventArgs e): " + ex.ToString()); } }
/// <summary> /// The Move method is called to move the robot. /// The Trémaux's algorithm is used to control the robot. /// https://en.wikipedia.org/wiki/Maze_solving_algorithm#Tr%C3%A9maux's_algorithm /// </summary> /// <param name="mazeSegment"></param> public void Move(MazeSegment mazeSegment) { try { if (mazeSegment == null) { throw new Exception("maze segment can not be null."); } if (CurrentLocation == null) { // The robot is not in the maze - do nothing. return; } // If the robot is NOT at a junction, mark the location. if (mazeSegment.SegmentType != SegmentType.Junction) { CurrentLocation.MarkCell(); } // If the robot is at a dead-end (except for the start of the maze), mark the location a second time. if (mazeSegment.SegmentType == SegmentType.DeadEnd && CurrentLocation.CellRole != CellRole.Start) { CurrentLocation.MarkCell(); } // Turn the robot, based on the type of maze segment. CurrentDirection = mazeSegment.ChooseDirection(CurrentDirection); // Attempt to move the robot forwards. MazeCell newCurrentLocation = null; if (CurrentDirection == Direction.North && mazeSegment.NorthCell.CellMark != CellMark.Twice) { newCurrentLocation = mazeSegment.NorthCell; } else if (CurrentDirection == Direction.East && mazeSegment.EastCell.CellMark != CellMark.Twice) { newCurrentLocation = mazeSegment.EastCell; } else if (CurrentDirection == Direction.South && mazeSegment.SouthCell.CellMark != CellMark.Twice) { newCurrentLocation = mazeSegment.SouthCell; } else if (CurrentDirection == Direction.West && mazeSegment.WestCell.CellMark != CellMark.Twice) { newCurrentLocation = mazeSegment.WestCell; } // Update the current location. CurrentLocation.ContainsRobot = false; CurrentLocation = newCurrentLocation != null ? newCurrentLocation : CurrentLocation; CurrentLocation.ContainsRobot = true; if (CurrentLocation.CellRole == CellRole.End) { OnReachedTheEnd?.Invoke(); // The robot has reached the end of the maze. } } catch (Exception ex) { throw new Exception("Robot.Move(MazeSegment mazeSegment): " + ex.ToString()); } }