Skip to content

rsdc2/mars-rover

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

79 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mars Rover

This is a console app to simulate navigating a rover across the Martian surface. The user is first asked to specify the size of the plateau to explore, and then an initial position and facing direction on that surface. The user may then provide instructions:

  • M = move one grid unit
  • L = rotate 90 degrees to the left
  • R = rotate 90 degrees to the right
  • Q = quit the program

Run and test in Visual Studio (2022)

Load MarsRover.sln in Visual Studio, from where the project can be run and tested using Visual Studio's user interface.

Running from the command line

  1. Clone or download the repository.
  2. cd into the repo folder:
cd mars-rover
  1. cd into the MarsRover project.
cd MarsRover
  1. Run the project:
dotnet run

This will build and run the project.

Run the tests from the commandline

  1. cd into the tests folder in the repo:
cd MarsRover.Tests
  1. Run the tests with:
dotnet test

Implementation according to the functional programming paradigm

I've used a pure functional approach to structuring the app. This means inter alia using:

  • Value types instead of reference types. For example, the MissionControl class never changes state when the rover changes position. Instead, a new MissionControl class is created with a new rover each time there is a change.
  • Recursion instead of loops.
  • Monadic types from the excellent LanguageExt library, especially Option and Either. The use of the latter means that it is never necessary to throw and catch exceptions. Instead, functions that may not succeed return an Either<string, T>, where T is the return type of the corresponding non-monadic function. If the function succeeds, T is returned wrapped in the Either monad. If it fails, a string carrying the error message is returned, also wrapped in the Either. (For an introduction to the practice and advantages of functional programming in C#, see Paul's Louth's blog. On monads in particular, see his introduction.)

One of the great benefits of wrapping return values in monadic types, like Either, is that it is possible to use LINQ query expressions with them. Consider the following code from the ConsoleUI of the MarsRover project:

public static Either<string, MissionControl> GetInitialSetup()
{
    return  from plateauSize in GetPlateauSize(None)
            from plateau in Plateau.FromPlateauSize(plateauSize)
            from missionControl in MissionControl.FromPlateau(plateau)
            from position in GetInitialPosition(plateauSize, None)
            from updatedMissionControl in missionControl.AddRover(position)
            select updatedMissionControl;
}

As Paul Louth shows, this structure parallels do notation in Haskell. The equivalent function in Haskell might be written like this:

GetInitialSetup :: Either String MissionControl
GetInitialSetup = do
    plateauSize <- GetPlateauSize Nothing
    plateau <- Plateau.FromPlateauSize plateauSize
    missionControl <- MissionControl.FromPlateau plateau
    position <- GetInitialPosition PlateauSize Nothing
    updatedMissionControl <- AddRover missionControl position
    pure updatedMissionControl

From this the similarity of the structure of the two is readily apparent:

C# Haskell
from x in y x <- y
select x pure x

Acknowledgements

Context

This project was written as a learning exercise as part of the Northcoders bootcamp.

Dependencies and licenses

The main project, MarsRover has one dependency:

The test project depends on:

Releases

No releases published

Packages

No packages published

Languages