Files
basic-computer-games/84 Super Star Trek/csharp/Utils/DirectionAndDistance.cs
2021-04-15 21:31:53 +10:00

65 lines
2.5 KiB
C#

using System;
using SuperStarTrek.Space;
namespace SuperStarTrek.Utils
{
internal class DirectionAndDistance
{
private readonly float _fromX;
private readonly float _fromY;
private DirectionAndDistance(float fromX, float fromY)
{
_fromX = fromX;
_fromY = fromY;
}
internal static DirectionAndDistance From(Coordinates coordinates) => From(coordinates.X, coordinates.Y);
internal static DirectionAndDistance From(float x, float y) => new DirectionAndDistance(x, y);
internal (float Direction, float Distance) To(Coordinates coordinates) => To(coordinates.X, coordinates.Y);
internal (float Direction, float Distance) To(float x, float y)
{
var deltaX = x - _fromX;
var deltaY = y - _fromY;
return (GetDirection(deltaX, deltaY), GetDistance(deltaX, deltaY));
}
// The algorithm here is mathematically equivalent to the following code in the original,
// where X is deltaY and A is deltaX
// 8220 X=X-A:A=C1-W1:IFX<0THEN8350
// 8250 IFA<0THEN8410
// 8260 IFX>0THEN8280
// 8270 IFA=0THENC1=5:GOTO8290
// 8280 C1=1
// 8290 IFABS(A)<=ABS(X)THEN8330
// 8310 PRINT"DIRECTION =";C1+(((ABS(A)-ABS(X))+ABS(A))/ABS(A)):GOTO8460
// 8330 PRINT"DIRECTION =";C1+(ABS(A)/ABS(X)):GOTO8460
// 8350 IFA>0THENC1=3:GOTO8420
// 8360 IFX<>0THENC1=5:GOTO8290
// 8410 C1=7
// 8420 IFABS(A)>=ABS(X)THEN8450
// 8430 PRINT"DIRECTION =";C1+(((ABS(X)-ABS(A))+ABS(X))/ABS(X)):GOTO8460
// 8450 PRINT"DIRECTION =";C1+(ABS(X)/ABS(A))
// 8460 PRINT"DISTANCE =";SQR(X^2+A^2):IFH8=1THEN1990
private static float GetDirection(float deltaX, float deltaY)
{
var deltaXDominant = Math.Abs(deltaX) > Math.Abs(deltaY);
var fractionalPart = deltaXDominant ? deltaY / deltaX : -deltaX / deltaY;
var nearestCardinal = deltaXDominant switch
{
true => deltaX > 0 ? 7 : 3,
false => deltaY > 0 ? 1 : 5
};
var direction = nearestCardinal + fractionalPart;
return direction < 1 ? direction + 8 : direction;
}
private static float GetDistance(float deltaX, float deltaY) =>
(float)Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2));
}
}