ASP Net Rest API – Treasure Hunt – Guess checking

As Rest API is set up and basic models are created ASP Net Rest API – Treasure Hunt, let’s now add some functionality to check if a guess is correct.

For this a API Endpoint is needed that gets a location and the Sight to be guessed.

Thanks to https://www.movable-type.co.uk/scripts/latlong.html theres no need to do the geometry and calculus to get distance or direction between 2 locations on a sphere.

So, first add and define these util Methods in Location entity

namespace tryout_blazor_api.Shared;

public class Location
{
  public float Latitude { get; set; } = 0;
  public float Longitude { get; set; } = 0;
  public float Altitude { get; set; } = 0;

  public float Distance(Location loc)
  {
    return Distance(Latitude, Longitude, loc.Latitude, loc.Longitude);
  }

  // https://www.movable-type.co.uk/scripts/latlong.html
  public float Distance(float lat1, float lon1, float lat2, float lon2)
  {
    var R = 6371000; // meters
    var dLat = (lat2-lat1) * MathF.PI / 180;
    var dLon = (lon2-lon1) * MathF.PI / 180;
    lat1 = (lat1) * MathF.PI / 180;
    lat2 = (lat2) * MathF.PI / 180;

    var a = MathF.Sin(dLat/2) * MathF.Sin(dLat/2)
      + MathF.Sin(dLon/2) * MathF.Sin(dLon/2)
        * MathF.Cos(lat1) * MathF.Cos(lat2); 
    var c = 2 * MathF.Atan2(MathF.Sqrt(a), MathF.Sqrt(1-a)); 
    var d = R * c;
    return d;
  }

  public float DirectionTo(Location loc) {
    return DirectionTo(Latitude, Longitude, loc.Latitude, loc.Longitude);
  }

  // https://www.movable-type.co.uk/scripts/latlong.html
  // return direction in degrees
  public float DirectionTo(float lat1, float lon1, float lat2, float lon2)
  {
    var dLon = (lon2-lon1) * MathF.PI / 180;
    lat1 = (lat1) * MathF.PI / 180;
    lat2 = (lat2) * MathF.PI / 180;

    var y = MathF.Sin(dLon) * MathF.Cos(lat2);
    var x = MathF.Cos(lat1)*MathF.Sin(lat2) -
              MathF.Sin(lat1)*MathF.Cos(lat2)*MathF.Cos(dLon);
    var θ = MathF.Atan2(y, x);
    return (θ*180/MathF.PI + 360) % 360;
  }
}

And then add the endpoint to the controller

    [HttpPost]
    [Route("check/{id}")]
    public IActionResult Check(int id, Location location)
    {
        if(id < 0 || id >= sights.Count)
            throw new Exception("Non existing Sight");

        var targetedSight = sights[id];
        var distance = location.Distance(targetedSight.Location!);

        _logger.LogInformation("Checking {location} for sight {id}, distance: {distance}", 
                                    JsonSerializer.Serialize(location), id, distance);

        if(distance < DISTANCE_CLOSE)
        {
            return Ok(new{ Result="You guessed it!" });
        }
        return Ok(new{ Result="Wrong guess" });
    }

The nice thing about ASP .Net is, for a POST call, it’s just writing a Method, adding the [HttpPost] attribute and setting what we expect as method parameter. The framework will then do the rest in background and tries to parse the URL and Post data even into a complex Object.

Playtime

Using Swagger it’s now easy to play with that endpoint.

Swagger already gives minimal values to start with. So we can easily change some values and test the results.

For the above values the expectation is: Far far away 😉

Let’s now take the expected location from example Sight

Yes, we guessed it correctly!

Leave a Reply

Your email address will not be published. Required fields are marked *