using Azimuth; using System; using System.Collections.Generic; using UnitTestSharp; namespace Annulus.UnitTests { public class HexGridTests : TestFixture { public const int Sentinel = -99; public class CtorTests : TestFixture { public void KeepsOrientationRowsAndColumns() { var grid = new HexGrid(HexOrientation.FlatTop, rows: 3, columns: 5, outOfBounds: Sentinel); CheckEqual(HexOrientation.FlatTop, grid.Orientation); CheckEqual(3, grid.Rows); CheckEqual(5, grid.Columns); } public void CountIsRowsTimesColumns() { CheckEqual(15, new HexGrid(HexOrientation.PointyTop, rows: 3, columns: 5, outOfBounds: 0).Count); } public void KeepsTheOutOfBoundsValue() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 2, columns: 2, outOfBounds: Sentinel); CheckEqual(Sentinel, grid.OutOfBounds); } public void CellsStartAtTheTypesDefault() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 2, columns: 2, outOfBounds: Sentinel); CheckEqual(0, grid[new HexIndex(0, 0)]); } public void NoRows_MakesAnEmptyGrid() { CheckEqual(0, new HexGrid(HexOrientation.PointyTop, rows: 0, columns: 4, outOfBounds: 0).Count); } public void NoColumns_MakesAnEmptyGrid() { CheckEqual(0, new HexGrid(HexOrientation.FlatTop, rows: 4, columns: 0, outOfBounds: 0).Count); } public void NegativeRows_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new HexGrid(HexOrientation.PointyTop, rows: -1, columns: 2, outOfBounds: 0); } public void NegativeColumns_Throws() { CheckThrow(typeof(ArgumentOutOfRangeException)); new HexGrid(HexOrientation.PointyTop, rows: 2, columns: -1, outOfBounds: 0); } public void TooManyCells_Throws() { CheckThrow(typeof(OverflowException)); new HexGrid(HexOrientation.PointyTop, rows: 100000, columns: 100000, outOfBounds: 0); } } public class ContainsTests : TestFixture { public void PointyTop_RowsShiftLeftByOneEveryTwoRows() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 3, columns: 4, outOfBounds: Sentinel); CheckTrue(grid.Contains(new HexIndex(0, 0))); CheckTrue(grid.Contains(new HexIndex(3, 0))); CheckFalse(grid.Contains(new HexIndex(-1, 0))); CheckFalse(grid.Contains(new HexIndex(4, 0))); CheckTrue(grid.Contains(new HexIndex(0, 1))); CheckTrue(grid.Contains(new HexIndex(3, 1))); CheckFalse(grid.Contains(new HexIndex(-1, 1))); CheckFalse(grid.Contains(new HexIndex(4, 1))); CheckTrue(grid.Contains(new HexIndex(-1, 2))); CheckTrue(grid.Contains(new HexIndex(2, 2))); CheckFalse(grid.Contains(new HexIndex(-2, 2))); CheckFalse(grid.Contains(new HexIndex(3, 2))); } public void PointyTop_RowsOutsideTheGridAreOut() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 3, columns: 4, outOfBounds: Sentinel); CheckFalse(grid.Contains(new HexIndex(0, -1))); CheckFalse(grid.Contains(new HexIndex(0, 3))); CheckFalse(grid.Contains(new HexIndex(-2, 3))); } public void FlatTop_ColumnsShiftUpByOneEveryTwoColumns() { var grid = new HexGrid(HexOrientation.FlatTop, rows: 3, columns: 4, outOfBounds: Sentinel); CheckTrue(grid.Contains(new HexIndex(0, 0))); CheckTrue(grid.Contains(new HexIndex(0, 2))); CheckFalse(grid.Contains(new HexIndex(0, -1))); CheckFalse(grid.Contains(new HexIndex(0, 3))); CheckTrue(grid.Contains(new HexIndex(1, 0))); CheckTrue(grid.Contains(new HexIndex(1, 2))); CheckFalse(grid.Contains(new HexIndex(1, -1))); CheckFalse(grid.Contains(new HexIndex(1, 3))); CheckTrue(grid.Contains(new HexIndex(2, -1))); CheckTrue(grid.Contains(new HexIndex(2, 1))); CheckFalse(grid.Contains(new HexIndex(2, -2))); CheckFalse(grid.Contains(new HexIndex(2, 2))); } public void FlatTop_ColumnsOutsideTheGridAreOut() { var grid = new HexGrid(HexOrientation.FlatTop, rows: 3, columns: 4, outOfBounds: Sentinel); CheckFalse(grid.Contains(new HexIndex(-1, 0))); CheckFalse(grid.Contains(new HexIndex(4, 0))); CheckFalse(grid.Contains(new HexIndex(4, -2))); } public void AnEmptyGridContainsNothing() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 0, columns: 0, outOfBounds: Sentinel); CheckFalse(grid.Contains(new HexIndex(0, 0))); } } public class IndexerTests : TestFixture { [IgnoreTest] public void CheckEveryCellKeepsItsOwnValue(HexOrientation orientation) { var grid = new HexGrid(orientation, rows: 5, columns: 6, outOfBounds: Sentinel); for (int position = 0; position < grid.Count; ++position) { grid[grid.IndexAt(position)] = position + 1; } for (int position = 0; position < grid.Count; ++position) { CheckEqual(position + 1, grid[grid.IndexAt(position)]); } } public void PointyTop_EveryCellKeepsItsOwnValue() { CheckEveryCellKeepsItsOwnValue(HexOrientation.PointyTop); } public void FlatTop_EveryCellKeepsItsOwnValue() { CheckEveryCellKeepsItsOwnValue(HexOrientation.FlatTop); } public void ReadingOutsideTheGrid_ReturnsTheOutOfBoundsValue() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 2, columns: 2, outOfBounds: Sentinel); CheckEqual(Sentinel, grid[new HexIndex(-5, 0)]); CheckEqual(Sentinel, grid[new HexIndex(0, 7)]); } public void ReadingOutsideAnEmptyGrid_ReturnsTheOutOfBoundsValue() { var grid = new HexGrid(HexOrientation.FlatTop, rows: 0, columns: 3, outOfBounds: Sentinel); CheckEqual(Sentinel, grid[new HexIndex(0, 0)]); } public void WritingOutsideTheGrid_Throws() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 2, columns: 2, outOfBounds: Sentinel); CheckThrow(typeof(ArgumentOutOfRangeException)); grid[new HexIndex(-5, 0)] = 1; } public void WritingOutsideTheGrid_LeavesTheCellsAlone() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 2, columns: 2, outOfBounds: Sentinel); try { grid[new HexIndex(2, 0)] = 1; } catch (ArgumentOutOfRangeException) { } for (int position = 0; position < grid.Count; ++position) { CheckEqual(0, grid[grid.IndexAt(position)]); } } public void ReferenceCellsStartNull() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 1, columns: 1, outOfBounds: "outside"); CheckNull(grid[new HexIndex(0, 0)]); CheckEqual("outside", grid[new HexIndex(1, 0)]); } } public class FlatIndexOfTests : TestFixture { [IgnoreTest] public void CheckInvertsIndexAt(HexOrientation orientation) { var grid = new HexGrid(orientation, rows: 5, columns: 6, outOfBounds: Sentinel); for (int position = 0; position < grid.Count; ++position) { CheckEqual(position, grid.FlatIndexOf(grid.IndexAt(position))); } } public void PointyTop_InvertsIndexAt() { CheckInvertsIndexAt(HexOrientation.PointyTop); } public void FlatTop_InvertsIndexAt() { CheckInvertsIndexAt(HexOrientation.FlatTop); } public void RunsAlongEachRowFromTheTop() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 3, columns: 4, outOfBounds: Sentinel); CheckEqual(0, grid.FlatIndexOf(new HexIndex(0, 0))); CheckEqual(3, grid.FlatIndexOf(new HexIndex(3, 0))); CheckEqual(4, grid.FlatIndexOf(new HexIndex(0, 1))); CheckEqual(8, grid.FlatIndexOf(new HexIndex(-1, 2))); } public void OutsideTheGrid_IsMinusOne() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 3, columns: 4, outOfBounds: Sentinel); CheckEqual(-1, grid.FlatIndexOf(new HexIndex(-1, 0))); CheckEqual(-1, grid.FlatIndexOf(new HexIndex(4, 0))); CheckEqual(-1, grid.FlatIndexOf(new HexIndex(0, -1))); CheckEqual(-1, grid.FlatIndexOf(new HexIndex(0, 3))); } } public class IndexAtTests : TestFixture { [IgnoreTest] public void CheckVisitsEveryHexOnceAndStaysInside(HexOrientation orientation) { var grid = new HexGrid(orientation, rows: 5, columns: 6, outOfBounds: Sentinel); var seen = new HashSet(); for (int position = 0; position < grid.Count; ++position) { HexIndex index = grid.IndexAt(position); CheckTrue(grid.Contains(index)); CheckTrue(seen.Add(index)); } CheckEqual(30, seen.Count); } public void PointyTop_VisitsEveryHexOnceAndStaysInside() { CheckVisitsEveryHexOnceAndStaysInside(HexOrientation.PointyTop); } public void FlatTop_VisitsEveryHexOnceAndStaysInside() { CheckVisitsEveryHexOnceAndStaysInside(HexOrientation.FlatTop); } public void PointyTop_RunsAlongEachRowFromTheTop() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 3, columns: 4, outOfBounds: Sentinel); CheckEqual(new HexIndex(0, 0), grid.IndexAt(0)); CheckEqual(new HexIndex(3, 0), grid.IndexAt(3)); CheckEqual(new HexIndex(0, 1), grid.IndexAt(4)); CheckEqual(new HexIndex(-1, 2), grid.IndexAt(8)); CheckEqual(new HexIndex(2, 2), grid.IndexAt(11)); } public void FlatTop_RunsAlongEachRowFromTheTop() { var grid = new HexGrid(HexOrientation.FlatTop, rows: 3, columns: 4, outOfBounds: Sentinel); CheckEqual(new HexIndex(0, 0), grid.IndexAt(0)); CheckEqual(new HexIndex(1, 0), grid.IndexAt(1)); CheckEqual(new HexIndex(2, -1), grid.IndexAt(2)); CheckEqual(new HexIndex(3, -1), grid.IndexAt(3)); CheckEqual(new HexIndex(0, 1), grid.IndexAt(4)); } public void PointyTop_StaggersOddRowsHalfAHexRight() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 3, columns: 4, outOfBounds: Sentinel); HexLayout layout = HexLayoutTests.Unit(HexOrientation.PointyTop); Scalar firstRowStart = layout.Center(grid.IndexAt(0)).X; Scalar secondRowStart = layout.Center(grid.IndexAt(4)).X; Scalar thirdRowStart = layout.Center(grid.IndexAt(8)).X; CheckEqual(HexLayoutTests.SquareRootOfThree / 2, secondRowStart - firstRowStart); CheckEqual(firstRowStart, thirdRowStart); } public void FlatTop_StaggersOddColumnsHalfAHexDown() { var grid = new HexGrid(HexOrientation.FlatTop, rows: 3, columns: 4, outOfBounds: Sentinel); HexLayout layout = HexLayoutTests.Unit(HexOrientation.FlatTop); Scalar firstColumnTop = layout.Center(grid.IndexAt(0)).Y; Scalar secondColumnTop = layout.Center(grid.IndexAt(1)).Y; Scalar thirdColumnTop = layout.Center(grid.IndexAt(2)).Y; CheckEqual(HexLayoutTests.SquareRootOfThree / 2, secondColumnTop - firstColumnTop); CheckEqual(firstColumnTop, thirdColumnTop); } public void NegativePosition_Throws() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 2, columns: 2, outOfBounds: Sentinel); CheckThrow(typeof(ArgumentOutOfRangeException)); grid.IndexAt(-1); } public void PositionPastTheLastCell_Throws() { var grid = new HexGrid(HexOrientation.PointyTop, rows: 2, columns: 2, outOfBounds: Sentinel); CheckThrow(typeof(ArgumentOutOfRangeException)); grid.IndexAt(4); } public void InAnEmptyGrid_Throws() { var grid = new HexGrid(HexOrientation.FlatTop, rows: 0, columns: 0, outOfBounds: Sentinel); CheckThrow(typeof(ArgumentOutOfRangeException)); grid.IndexAt(0); } } } }