using System; using System.Numerics; namespace RobotAndDonkey.Game.Utils; public record struct Hex(int X, int Y) { public static int Distance(Hex a, Hex b) { var (acx, acy, acz) = OffsetToCube(a); var (bcx, bcy, bcz) = OffsetToCube(b); return Math.Max(Math.Max(Math.Abs(acx - bcx), Math.Abs(acy - bcy)), Math.Abs(acz - bcz)); static (int, int, int) OffsetToCube(Hex hex) { var x = hex.X - (hex.Y - (hex.Y & 1)) / 2; var z = hex.Y; var y = -x - z; return (x, y, z); } } public static Hex FromWorld(Vector2 coords) { var cx = coords.X * MathF.Sqrt(3) / 3 - coords.Y / 3; var cz = coords.Y * 2 / 3; var cy = -cx - cz; var rx = (int)MathF.Round(cx); var ry = (int)MathF.Round(cy); var rz = (int)MathF.Round(cz); var xDiff = MathF.Abs(rx - cx); var yDiff = MathF.Abs(ry - cy); var zDiff = MathF.Abs(rz - cz); if (xDiff > yDiff && xDiff > zDiff) rx = -ry - rz; else if (yDiff > zDiff) ry = -rx - rz; else rz = -rx - ry; var col = rx + (rz - (rz & 1)) / 2; var row = rz; return new(col, row); } public static Hex FromPixel(Vector2 coords, float size) { return FromWorld(new(coords.X / size, coords.Y / size)); } public Hex GetNeighbour(EDirection direction) { var parity = Y & 1; var dir = offsetDirections[parity, (int)direction]; return new(X + dir.X, Y + dir.Y); } public Vector2 ToWorld() { var x = MathF.Sqrt(3) * (X + 0.5f * (Y & 1)); var y = 3.0f / 2 * Y; return new(x, y); } public Vector2 ToPixel(float size) { var w = ToWorld(); return new(w.X * size, w.Y * size); } public override string ToString() { return $"({X}, {Y})"; } private static readonly Hex[,] offsetDirections = { { new(+1, 0), new(0, -1), new(-1, -1), new(-1, 0), new(-1, +1), new(0, +1) }, { new(+1, 0), new(+1, -1), new(0, -1), new(-1, 0), new(0, +1), new(+1, +1) } }; }