SVT Robotics - .NET Core Take Home Recruiting Assessment

Question: One of SVT's microservices calculates which robot should transport a pallet from point A to point B based on which robot is the closest and has the most battery left if there are multiple in the proximity of the load's location. You'll use a provided API endpoint to create a simplified robot routing API.

Read More on the link.

Requirements (demo can be found here:https://api.ernestech.com/swagger/index.html )

  1. .NET Core API with a POST endpoint that accepts and returns data per the above task description i. POST endpoint must be https://localhost:5001/api/robots/closest/ or http://localhost:5000/api/robots/closest/

    https://api.ernestech.com/swagger/index.html
  2. API can be run locally and tested using Postman or other similar tools
    [Verified and Passed]
  3. Description of what features, functionality, etc. you would add next and how you would implement them - you shouldn't spend more than an hour on this project, so we want to know what you'd do next (and how you'd do it) if you had more time

    Answer: Mostly, I followed all the best practices available to my knowledge. If I had to optimize the Endpoint, I would work on the calculateDistance Algorithm. I don't think it is optimized for Big O Notation.

  4. Use git and GitHub for version control
    [Very much familiar with the technology but did not have time]



    Answer Explanation:

    (demo can be found here:https://api.ernestech.com/swagger/index.html 

    1. My approach in solving this Algorithm Problem was to tackle the problem from the Architectural point of view.
         - I create an Interface that defined the methods used to fetch the robot's data from the endpoint.
    namespace ISV.Services.Services.Interfaces
    {
        public interface ISVTRobotics
        {
            public Task<List<Robot>> getRobots();
        }
    }?

    2. I created a Repository Service to consume the Interface, this methodology is great for Unit Testing.

    namespace SVT.Services.Services.RepositoryService
    {
        public class SVTRoboticsRepository : ISVTRobotics
        {
            public async Task<List<Robot>> getRobots()
            {
                HttpClientHandler handler = new()
                {
                    AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate
                };
    
                using var httpClient = new HttpClient(handler);
                Uri url = new("https://60c8ed887dafc90017ffbd56.mockapi.io/robots");
                //set up
                httpClient.BaseAddress = url;
                httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
    
                //make a request
                var response = await httpClient.GetStringAsync(url).ConfigureAwait(false);
                //System.Text.Json is faster than NewtonSoft JsonConvert or Serializer/Deserializer
                //Lists are forgiving than Arrays
                List<Robot> robots = JsonSerializer.Deserialize<List<Robot>>(response);
                handler.Dispose();
                return robots;
            }
        }
    }?

    3. I created a Controller for Routing and included a calculateDistance Function that calculates the distance of a Robot.

    namespace SVT._0.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class SVTRobotsController : Controller
        {
            private readonly ISVTRobotics _robots;
            public SVTRobotsController(ISVTRobotics robots)
            {
                _robots = robots;
            }
            /// <summary>
            /// The provided API returns a list of all 100 robots in our fleet.
            /// It gives their current position on an xy-plane along with their battery life.
            /// Your job is to write a new .NET Core API with an endpoint which accepts 
            /// a payload with a load which needs to be moved including its identifier
            /// and current x,y coordinates and your endpoint should make an HTTP request
            /// to the robots endpoint and return which robot is the best to transport the 
            /// load based on which one is closest the load's location. If there is more than
            /// 1 robot within 10 distance units of the load, return the one with the most
            /// battery remaining.
            /// </summary>
            /// <param name="payload">SVTPayload payload</param>
            /// <returns></returns>
            
            [HttpPost]
            [Route("/robots/closest")]
            public async Task<JsonResult> AvailableRobot(SVTPayload payload)
            {
    
                //base case
                if (payload is null) return null;
    
                //Call API Endpoing
                List<Robot> robocall = await _robots.getRobots();
    
                //Algorithm
                Robot payloadLocation = new()
                {
                    x = payload.x,
                    y = payload.y,
                    IsPayLoad = true,
                    batteryLevel = 0,
                    robotId = "0" //Assuming there can never be a real robot with an id of 0
                    
                };
                robocall.Add(payloadLocation);
                List<SVTRobotsDistanceToGoal> calculated = calculateDistance(robocall);
                calculated = calculated.OrderByDescending(a => a.distanceToGoal).ToList<SVTRobotsDistanceToGoal>();
                //Find the payload object and pick the robot next to it
    
                SVTRobotsDistanceToGoal closest = calculated.Where(a => a.batteryLevel > 0 && a.IsPayLoad == false && (a.next == 0 || a.previous == 0)).FirstOrDefault();
    
                //Check for null exceptions
                return Json(closest);
    
    
            }
    
            private List<SVTRobotsDistanceToGoal> calculateDistance(List<Robot> robots)
            {
                int x2 = 0;
                int y2 = 0;
    
                int x1 = 0;
                int y1 = 0;
                List<SVTRobotsDistanceToGoal> distanceToGoal = new();
    
              for(int i = 0; i <= robots.Count-2; i++)
                {
                   
                    x1 = robots[i].x;
                    y1 = robots[i].y;
                    x2 = robots[i+1].x;
                    y2 = robots[i + 1].y;
                    int hasPrevious = 0;
    
                    double distance = Math.Sqrt(Math.Pow((x2 - x1),2) + Math.Pow((y2 - y1),2));
                    if(i > 0)
                    {
                        hasPrevious = Convert.ToInt32(robots[i - 1].robotId);
                    }
                    SVTRobotsDistanceToGoal calculatedDistance = new()
                    {
                         batteryLevel = robots[i].batteryLevel,
                          distanceToGoal = (float)distance,
                          robotId = Convert.ToInt32(robots[i].robotId),
                          next = Convert.ToInt32(robots[i+1].robotId),
                          previous = hasPrevious,
                          IsPayLoad = robots[i].IsPayLoad,
                    };
                    distanceToGoal.Add(calculatedDistance);
                }
                return distanceToGoal;
            }
    
        }
    }

    4. I then injected the Interface and the Service Repository in the Dependency Container from the Startup.cs.

     services.AddTransient<ISVTRobotics, SVTRoboticsRepository>();

    5. In Addition, I created couple of Robots models for Object Oriented Programming.

     public class SVTPayload
        {
            public int loadId { get; set; }
            public int x { get; set; }
            public int y { get; set; }
        }
    
        public class SVTRobotsDistanceToGoal
        {
            public int robotId { get; set; }
            public float distanceToGoal { get; set; }
            public int batteryLevel { get; set; }
            public int next { get; set; }
            public int previous { get; set; }
            public bool IsPayLoad { get; set; } = false;
        }
    
            public class Robot
            {
                public string robotId { get; set; }
                public int batteryLevel { get; set; }
                public int y { get; set; }
                public int x { get; set; }
          
            [NotMapped]
            public bool IsPayLoad { get; set; } = false;
            }



Edit this Article
If you log in, you will be notified when someone leaves a comment.

Other users would like to know if this solution helped you.

Your Session is Ending
Login to Continue

© 2022 - ErnesTech - Privacy