using System; using System.Collections.Generic; using System.Linq; using Coord2D = System.Tuple; namespace Chernobyl { /// /// Holds utility code for arrays. /// /// The type of the array that is being worked with. public static class Array { /// /// A static array instance that contains no elements. The MSDN /// guidelines state that null arrays should be avoided and empty arrays /// should be used in their place /// (http://msdn.microsoft.com/en-us/library/k2604h5s.aspx). /// public static readonly T[] Empty = new T[0]; } /// /// Extension and utility methods for 2D arrays. /// public static class Array2D { /// /// Returns the X axis of the vector. /// public static int X(this Coord2D v) => v.Item1; /// /// Returns the Y axis of the vector. /// public static int Y(this Coord2D v) => v.Item2; /// /// Converts a reference tuple coordinate to a value tuple coordinate. /// public static (int x, int y) ToValueTuple(this Coord2D v) => (v.X(), v.Y()); /// /// Converts a value tuple coordinate to a reference tuple coordinate. /// public static Coord2D ToValueTuple(this (int x, int y) v) => Tuple.Create(v.x, v.y); /// /// Attempts to get the value at the specified 2D array coordinate. /// /// The type of the array 2D. /// A 2D array whose values are in column/row order. i.e. array2D[1][2] /// is the value in column 1, row 2. /// The location of the value. /// The instance that is to take the value. /// False if the value could not be retrieved, true if otherwise. public static bool TryGet(this T[][] array2D, Coord2D cell, out T value) { var result = false; value = default; if(array2D.Bounds2D(cell)) { value = array2D[cell.X()][cell.Y()]; result = true; } return result; } /// /// Returns true if is inside , false if /// otherwise. /// public static bool Bounds2D(this T[][] array2D, Coord2D cell) { var result = false; if (0 <= cell.X() && cell.X() < array2D.Length) { var column = array2D[cell.X()]; if (0 <= cell.Y() && cell.Y() < column.Length) result = true; } return result; } static Coord2D Add(Coord2D a, Coord2D b) => Tuple.Create(a.Item1 + b.Item1, a.Item2 + b.Item2); /// /// Calculates the coordinates above . /// public static Coord2D GetNorthCoordinates(this Coord2D point) => Add(point, new Coord2D(0, 1)); /// /// Calculates the coordinates above and to the right of . /// public static Coord2D GetNorthEastCoordinates(this Coord2D point) => Add(point, new Coord2D(1, 1)); /// /// Calculates the coordinates right of . /// public static Coord2D GetEastCoordinates(this Coord2D point) => Add(point, new Coord2D(1, 0)); /// /// Calculates the coordinates right and below . /// public static Coord2D GetSouthEastCoordinates(this Coord2D point) => Add(point, new Coord2D(1, -1)); /// /// Calculates the coordinates below . /// public static Coord2D GetSouthCoordinates(this Coord2D point) => Add(point, new Coord2D(0, -1)); /// /// Calculates the coordinates right and left . /// public static Coord2D GetSouthWestCoordinates(this Coord2D point) => Add(point, new Coord2D(-1, -1)); /// /// Calculates the coordinates left . /// public static Coord2D GetWestCoordinates(this Coord2D point) => Add(point, new Coord2D(-1, 0)); /// /// Calculates the coordinates right and above . /// public static Coord2D GetNorthWestCoordinates(this Coord2D point) => Add(point, new Coord2D(-1, 1)); /// /// Attempts to retrieve the at the point . /// public static bool TryGetNorth(this T[][] array2D, Coord2D relativeTo, out T value) => array2D.TryGet(relativeTo.GetNorthCoordinates(), out value); /// /// Attempts to retrieve the at the point . /// public static bool TryGetNorthEast(this T[][] array2D, Coord2D relativeTo, out T value) => array2D.TryGet(relativeTo.GetNorthEastCoordinates(), out value); /// /// Attempts to retrieve the at the point . /// public static bool TryGetEast(this T[][] array2D, Coord2D relativeTo, out T value) => array2D.TryGet(relativeTo.GetEastCoordinates(), out value); /// /// Attempts to retrieve the at the point . /// public static bool TryGetSouthEast(this T[][] array2D, Coord2D relativeTo, out T value) => array2D.TryGet(relativeTo.GetSouthEastCoordinates(), out value); /// /// Attempts to retrieve the at the point . /// public static bool TryGetSouth(this T[][] array2D, Coord2D relativeTo, out T value) => array2D.TryGet(relativeTo.GetSouthCoordinates(), out value); /// /// Attempts to retrieve the at the point . /// public static bool TryGetSouthWest(this T[][] array2D, Coord2D relativeTo, out T value) => array2D.TryGet(relativeTo.GetSouthWestCoordinates(), out value); /// /// Attempts to retrieve the at the point . /// public static bool TryGetWest(this T[][] array2D, Coord2D relativeTo, out T value) => array2D.TryGet(relativeTo.GetWestCoordinates(), out value); /// /// Attempts to retrieve the at the point . /// public static bool TryGetNorthWest(this T[][] array2D, Coord2D relativeTo, out T value) => array2D.TryGet(relativeTo.GetNorthWestCoordinates(), out value); /// /// Returns the 4 cardinal neighbor values from the 2D array starting from the north and /// going clockwise. If any of the neighbors are non-existent, default(T) will be returned /// in their place. /// public static IEnumerable TryGetCardinalNeighbors(this T[][] array2D, Coord2D relativeTo) { array2D.TryGetNorth(relativeTo, out var result); yield return result; array2D.TryGetEast(relativeTo, out result); yield return result; array2D.TryGetSouth(relativeTo, out result); yield return result; array2D.TryGetWest(relativeTo, out result); yield return result; } /// /// Returns the cardinal neighbor values from the 2D array starting from the north and /// going clockwise. If any of the neighbors are non-existent, they will not be returned. /// public static IEnumerable GetCardinalNeighbors(this T[][] array2D, Coord2D point) => array2D.TryGetCardinalNeighbors(point).Where(g => g != null).ToArray(); /// /// Returns the width of the 2D array assuming that the outer array holds the columns /// (i.e. array2D[0] is column 0). /// public static int Width(this T[][] array2D) => array2D.Length; /// /// Returns the height of the 2D array assuming that the outer array holds the columns /// (i.e. array2D[0] is column 0) and that all columns are of equal length. /// public static int Height(this T[][] array2D) => array2D.Length > 0 ? array2D[0].Length : 0; /// /// Returns all the values in the 2D array, returning the entirety of a column (array2D[X]) /// before moving to the next (array2D[X + 1]), always starting at 0 and moving up. /// public static IEnumerable As1D(this T[][] array2D) => array2D.SelectMany(column => column); /// /// Projects each element of a 2D array into a new form. /// public static TResult[][] Select2D(this TSource[][] array2D, Func selector) => array2D.Select(a2D => a2D.Select(selector).ToArray()).ToArray(); } }