Add project files.

This commit is contained in:
2022-09-13 02:43:55 +03:00
parent 2dec4b1dc5
commit 9e39314500
74 changed files with 2336 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
using System.Reflection;
namespace MartianRobotsSolver
{
public class CommandProcessor
{
private Dictionary<string, IRobotCommand> processors = new Dictionary<string, IRobotCommand>();
public CommandProcessor()
{
Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => !t.IsAbstract && t.IsAssignableTo(typeof(IRobotCommand)))
.Select(t =>
{
IRobotCommand? command = Activator.CreateInstance(t) as IRobotCommand;
if(command != null)
processors.Add(command.Command, command);
return command;
})
.ToList();
}
public void Process(RobotInfo robotInfo, string cmd)
{
if (processors.ContainsKey(cmd))
{
processors[cmd].Process(robotInfo);
} else {
throw new NotSupportedException($"cmd {cmd} is not supported.");
}
}
}
}
+9
View File
@@ -0,0 +1,9 @@
namespace MartianRobotsSolver
{
public interface IRobotCommand
{
public string Command { get; }
public void Process(RobotInfo robotInfo);
}
}
+54
View File
@@ -0,0 +1,54 @@
using Ardalis.GuardClauses;
namespace MartianRobotsSolver
{
public class MarsNavigator
{
private WorldInfo worldInfo;
private CommandProcessor commandProcessor = new CommandProcessor();
public MarsNavigator(WorldInfo worldInfo)
{
this.worldInfo=worldInfo;
}
public string Navigate(RobotInfo robotInfo)
{
//validate robot coordintates in world
Guard.Against.InvalidInput(robotInfo, nameof(robotInfo), ri => {
return ri.PosX<= worldInfo.SizeX || ri.PosY <= worldInfo.SizeY;
});
foreach (var cmd in robotInfo.Commands)
{
//save old coords
var oldPosX = robotInfo.PosX;
var oldPosY = robotInfo.PosY;
//process command
commandProcessor.Process(robotInfo, cmd.ToString());
//check new robot coordintates in world
if (robotInfo.PosX> worldInfo.SizeX || robotInfo.PosY > worldInfo.SizeY ||
robotInfo.PosX<0 || robotInfo.PosY<0)
{
//revert to previous values
robotInfo.PosX = oldPosX;
robotInfo.PosY = oldPosY;
if (!worldInfo.HasScent(oldPosX, oldPosY))
{
robotInfo.IsLost = true;
//add scent
worldInfo.AddScent(robotInfo.PosX, robotInfo.PosY);
//exit loop
break;
}
}
}
return robotInfo.ToString();
}
}
}
+53
View File
@@ -0,0 +1,53 @@
using Ardalis.GuardClauses;
using System.Text;
namespace MartianRobotsSolver
{
public class MarsSolver
{
public RobotSolution Process(string input)
{
var lines = input.Split(new string[] { Environment.NewLine, "\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
//extract world info
var wInfo = lines[0].Split(" ");
var sizeX = Convert.ToInt32(wInfo[0]);
var sizeY = Convert.ToInt32(wInfo[1]);
var worldInfo = new WorldInfo(sizeX, sizeY);
var robotSolution = new RobotSolution()
{
Input = input,
WorldInfo = worldInfo
};
//map robots info and commands
for (int i = 0; i < (lines.Count - 1)/2; i++)
{
var rInfo = lines[1 + i*2].Split(" ");
var rPosX = Convert.ToInt32(rInfo[0]);
var rPosY = Convert.ToInt32(rInfo[1]);
var rHead = rInfo[2];
var robotCommands = lines[2 + i*2];
Guard.Against.InvalidInput(robotCommands, nameof(robotCommands), rc => rc.Length<100);
var robotInfo = new RobotInfo(rPosX, rPosY, rHead, robotCommands);
robotSolution.Robots.Add(robotInfo);
}
//process commands
var navigator = new MarsNavigator(worldInfo);
StringBuilder sb = new StringBuilder();
foreach (var robotInfo in robotSolution.Robots)
{
if (sb.Length>0)
sb.Append(Environment.NewLine);
sb.Append(navigator.Navigate(robotInfo));
}
//store output
robotSolution.Output = sb.ToString();
return robotSolution;
}
}
}
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ardalis.GuardClauses" Version="4.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MartianRobots.Web\Shared\MartianRobots.Web.Shared.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,7 @@
namespace MartianRobotsSolver
{
public class RobotCommandConstants
{
public const string HEADING = "NESW";
}
}
@@ -0,0 +1,30 @@
namespace MartianRobotsSolver
{
public class RobotCommandForward: IRobotCommand
{
public string Command => "F";
public void Process(RobotInfo robotInfo)
{
int deltaX = 0;
int deltaY = 0;
switch (robotInfo.Head)
{
case "N":
deltaY = 1;
break;
case "S":
deltaY = -1;
break;
case "E":
deltaX = 1;
break;
case "W":
deltaX = -1;
break;
}
robotInfo.PosX += deltaX;
robotInfo.PosY += deltaY;
}
}
}
+15
View File
@@ -0,0 +1,15 @@
namespace MartianRobotsSolver
{
public class RobotCommandLeft : IRobotCommand
{
public string Command => "L";
public void Process(RobotInfo robotInfo)
{
var hIndex = RobotCommandConstants.HEADING.IndexOf(robotInfo.Head)-1;
if(hIndex<0)
hIndex = RobotCommandConstants.HEADING.Length-1;
robotInfo.Head = RobotCommandConstants.HEADING[hIndex].ToString();
}
}
}
+15
View File
@@ -0,0 +1,15 @@
namespace MartianRobotsSolver
{
public class RobotCommandRight : IRobotCommand
{
public string Command => "R";
public void Process(RobotInfo robotInfo)
{
var hIndex = RobotCommandConstants.HEADING.IndexOf(robotInfo.Head)+1;
if(hIndex>RobotCommandConstants.HEADING.Length-1)
hIndex = 0;
robotInfo.Head = RobotCommandConstants.HEADING[hIndex].ToString();
}
}
}
+28
View File
@@ -0,0 +1,28 @@
using Ardalis.GuardClauses;
namespace MartianRobotsSolver
{
public class RobotInfo
{
public int PosX { get; set; }
public int PosY { get; set; }
public string Head { get; set; }
public string Commands { get; }
public bool IsLost { get; set; } = false;
public RobotInfo(int posX, int posY, string head, string commands)
{
Guard.Against.Negative(posX, nameof(posX));
Guard.Against.Negative(posY, nameof(posX));
this.PosX = posX;
this.PosY = posY;
this.Head = head;
this.Commands = commands;
}
public override string ToString()
{
return $"{PosX} {PosY} {Head}{ (IsLost ? " LOST" : string.Empty) }";
}
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace MartianRobotsSolver
{
public class RobotSolution
{
public WorldInfo WorldInfo { get; internal set; }
public string Input { get; set; }
public List<RobotInfo> Robots { get; internal set; } = new List<RobotInfo>();
public string Output { get; internal set; }
public DateTime DateTimeStamp { get; }
}
}
+30
View File
@@ -0,0 +1,30 @@
using Ardalis.GuardClauses;
namespace MartianRobotsSolver
{
public class WorldInfo
{
private List<(int X,int Y)> scents = new List<(int X, int Y)>();
public WorldInfo(int sizeX, int sizeY)
{
Guard.Against.OutOfRange(sizeX, nameof(sizeX), 0, 50);
Guard.Against.OutOfRange(sizeY, nameof(sizeY), 0, 50);
this.SizeX=sizeX;
this.SizeY=sizeY;
}
public int SizeX { get; internal set; }
public int SizeY { get; internal set; }
internal void AddScent(int posX, int posY)
{
if(!HasScent(posX, posY))
scents.Add((posX, posY));
}
internal bool HasScent(int posX, int posY)
{
return scents.Contains((posX, posY));
}
}
}