Skip to content

Commit

Permalink
Giving more control to what types can be specified for shapes and add…
Browse files Browse the repository at this point in the history
…ing in a basic idea of a generator for the grid
  • Loading branch information
tspayne87 committed Oct 27, 2022
1 parent ac1d3dc commit 32cc163
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 55 deletions.
44 changes: 31 additions & 13 deletions MonoGame.Grid.Test/GridTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ public void NoShapesFoundTest()
{ "O", "X", "O" }
};

var shapes = grid.FindShapes(new List<IShape<string>>() { new SquareShape(), new LineShape() });

var shapes = grid.FindShapes(new SquareShape(), new LineShape());
Assert.Empty(shapes);
}

Expand All @@ -30,10 +29,10 @@ public void ShapeTests()
{ "O", "X", "O" }
};

var shapes = grid.FindShapes(new List<IShape<string>>() { new SquareShape(), new LineShape() });
var shapes = grid.FindShapes(new SquareShape(), new LineShape());

Assert.Single(shapes);
Assert.Equal("square", shapes[0].Name);
Assert.Equal("square", shapes[0].Type);

grid = new Grid<string>()
{
Expand All @@ -42,10 +41,10 @@ public void ShapeTests()
{ "O", "O", "O" }
};

shapes = grid.FindShapes(new List<IShape<string>>() { new SquareShape(), new LineShape() });
shapes = grid.FindShapes(new SquareShape(), new LineShape());

Assert.Single(shapes);
Assert.Equal("square", shapes[0].Name);
Assert.Equal("square", shapes[0].Type);

grid = new Grid<string>()
{
Expand All @@ -54,9 +53,9 @@ public void ShapeTests()
{ "O", "O", "O" }
};

shapes = grid.FindShapes(new List<IShape<string>>() { new SquareShape(), new LineShape() });
shapes = grid.FindShapes(new SquareShape(), new LineShape());
Assert.Single(shapes);
Assert.Equal("square", shapes[0].Name);
Assert.Equal("square", shapes[0].Type);

grid = new Grid<string>()
{
Expand All @@ -65,9 +64,9 @@ public void ShapeTests()
{ "X", "X", "O" }
};

shapes = grid.FindShapes(new List<IShape<string>>() { new SquareShape(), new LineShape() });
shapes = grid.FindShapes(new SquareShape(), new LineShape());
Assert.Single(shapes);
Assert.Equal("square", shapes[0].Name);
Assert.Equal("square", shapes[0].Type);
}

[Fact]
Expand All @@ -87,11 +86,30 @@ public void MultipleShapeTests()
{ "O", "O", "X", "X", "O", "O", "O", "X", "O", "O" }
};

var shapes = grid.FindShapes(new List<IShape<string>>() { new SquareShape(), new LineShape() });
var shapes = grid.FindShapes(new SquareShape(), new LineShape());

Assert.Equal(7, shapes.Count);
Assert.Equal(2, shapes.Count(x => x.Name == "square"));
Assert.Equal(5, shapes.Count(x => x.Name == "line"));
Assert.Equal(2, shapes.Count(x => x.Type == "square"));
Assert.Equal(5, shapes.Count(x => x.Type == "line"));
}

[Fact]
public void GeneratorTests()
{
for (var i = 0; i < 100; ++i)
{
var grid = new Grid<string>(100, 100);
var rand = new Random();
var values = new List<string>() { "O", "X" };

grid.CreateGenerator()
.WithoutShapes(new SquareShape(), new LineShape())
.WithRandomValue(() => values[rand.Next(0, values.Count)])
.Generate();

var shapes = grid.FindShapes(new SquareShape(), new LineShape());
Assert.Empty(shapes);
}
}
}
}
6 changes: 3 additions & 3 deletions MonoGame.Grid.Test/Shapes/LineShape.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

namespace MonoGame.Grid.Test.Shapes
{
internal class LineShape : IShape<string>
internal class LineShape : IShape<string, string>
{
private int _size = 2;

/// <inheritdoc />
public string Name => "line";
public string Type => "line";

/// <inheritdoc />
public List<Point>? HasShapeOnPoint(Point point, Grid<string> grid)
public List<Point>? HasShapeOnPoint(Point point, IGrid<string> grid)
{
var checks = new List<List<Point>>();
if (point.X + _size < grid.Width)
Expand Down
6 changes: 3 additions & 3 deletions MonoGame.Grid.Test/Shapes/SquareShape.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

namespace MonoGame.Grid.Test.Shapes
{
internal class SquareShape : IShape<string>
internal class SquareShape : IShape<string, string>
{
private Point[] _checks = new Point[] { new Point(0, 0), new Point(0, 1), new Point(1, 0), new Point(1, 1) };

/// <inheritdoc />
public string Name => "square";
public string Type => "square";

/// <inheritdoc />
public List<Point>? HasShapeOnPoint(Point point, Grid<string> grid)
public List<Point>? HasShapeOnPoint(Point point, IGrid<string> grid)
{
foreach(var check in _checks)
if (!grid.Contains(check + point) || grid[check + point] != "X")
Expand Down
23 changes: 23 additions & 0 deletions MonoGame.Grid/Extensions/CreateGeneratorGridExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace MonoGame.Grid.Extensions
{
public static class CreateGeneratorGridExtensions
{
/// <summary>
/// Will create a genertor to define how the grid will be generated with
/// </summary>
/// <typeparam name="TValue">The type of object that will be assigned in the grid</typeparam>
/// <param name="grid">The current grid we need to generate values in</param>
/// <returns>Will return a generator to fill in a grid</returns>
public static IGridGenerator<TValue> CreateGenerator<TValue>(this IGrid<TValue> grid)
{
return new GridGenerator<TValue>(grid);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@

namespace MonoGame.Grid.Extensions
{
public static class FindGroupGridExtensions
public static class FindShapesIGridExtensions
{
/// <summary>
/// Method is meant to find all shapes in a grid
/// </summary>
/// <typeparam name="TValue">The type of object that is stored in the grid</typeparam>
/// <typeparam name="TType">The type of the shapes being given</typeparam>
/// <param name="grid">The grid we are finding shapes in</param>
/// <param name="shapes">The shapes we are looking for</param>
/// <returns>Will return a list of shape results found in the grid</returns>
public static List<FindShapesResult> FindShapes<TValue>(this Grid<TValue> grid, List<IShape<TValue>> shapes)
public static List<FindShapesResult<TType>> FindShapes<TValue, TType>(this IGrid<TValue> grid, params IShape<TValue, TType>[] shapes)
{
var result = new List<FindShapesResult>();
var result = new List<FindShapesResult<TType>>();

var foundGrid = new Grid<bool>(grid.Width, grid.Height);
var span = grid.AsSpan();
Expand All @@ -32,7 +33,7 @@ public static List<FindShapesResult> FindShapes<TValue>(this Grid<TValue> grid,
{
foreach (var x in CollectionsMarshal.AsSpan(points))
foundGrid[x] = true;
result.Add(new FindShapesResult(shape.Name, points));
result.Add(new FindShapesResult<TType>(shape.Type, points));
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions MonoGame.Grid/Extensions/Models/FindShapesResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ namespace MonoGame.Grid.Extensions
/// <summary>
/// Result object meant to group results together to give information on what shapes were found
/// </summary>
public sealed class FindShapesResult
public sealed class FindShapesResult<TShapeType>
{
/// <summary>
/// The name of the of the shape that was found
/// The type of shape that was found
/// </summary>
public string Name { get; set; }
public TShapeType Type { get; set; }

/// <summary>
/// The points on the grid that make up the shape
Expand All @@ -20,11 +20,11 @@ public sealed class FindShapesResult
/// <summary>
/// Will create a find result that specifies what type of shape was found during the search
/// </summary>
/// <param name="name">The name of the of the shape that was found</param>
/// <param name="type">The type of shape that was found</param>
/// <param name="points">The points on the grid that make up the shape</param>
internal FindShapesResult(string name, List<Point> points)
internal FindShapesResult(TShapeType type, List<Point> points)
{
Name = name;
Type = type;
Points = points;
}
}
Expand Down
78 changes: 78 additions & 0 deletions MonoGame.Grid/Extensions/Models/GridGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
namespace MonoGame.Grid.Extensions
{
/// <summary>
/// Implmentation of <see cref="IGridGenerator{TValue}" />
/// </summary>
/// <typeparam name="TValue">The current value that is stored in the grid</typeparam>
internal class GridGenerator<TValue> : IGridGenerator<TValue>
{
/// <summary>
/// The current grid we are filling in
/// </summary>
private readonly IGrid<TValue> _grid;

/// <summary>
/// The current shapes we are currently trying to avoid making
/// </summary>
private readonly List<IBaseShape<TValue>> _shapesToAvoid;

/// <summary>
/// The getter function to get a random value to be put in the grid
/// </summary>
private Func<TValue>? _randomGetter;

/// <summary>
/// Builds the generator constructor to fill a grid in
/// </summary>
/// <param name="grid">The current grid we are filling in</param>
public GridGenerator(IGrid<TValue> grid)
{
_grid = grid;
_shapesToAvoid = new List<IBaseShape<TValue>>();
_randomGetter = null;
}

/// <inheritdoc />
public void Generate()
{
if (_randomGetter == null)
throw new ArgumentNullException("randomGetter", "Cannot fill a grid if values are not configured");

var span = _grid.AsSpan();
for (var i = span.Length - 1; i >=0; --i)
{
if (span[i] == null)
{
var point = i.ToPoint(_grid.Width);

do
{ // TODO: Figure out a better way to calculate the new item that should be put on the grid
// Right now this is very inefficient
_grid[point] = _randomGetter();
} while (_shapesToAvoid.Count > 0 && _shapesToAvoid.Any(x => x.HasShapeOnPoint(point, _grid) != null));
}
}
}

/// <inheritdoc />
public IGridGenerator<TValue> WithoutShapes<TType>(params IShape<TValue, TType>[] shapes)
{
_shapesToAvoid.AddRange(shapes);
return this;
}

/// <inheritdoc />
public IGridGenerator<TValue> OverwriteNoneNulls()
{
_grid.Clear();
return this;
}

/// <inheritdoc />
public IGridGenerator<TValue> WithRandomValue(Func<TValue> randomGetter)
{
_randomGetter = randomGetter;
return this;
}
}
}
35 changes: 35 additions & 0 deletions MonoGame.Grid/Extensions/Models/IGridGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace MonoGame.Grid.Extensions
{
/// <summary>
/// Grid generator to fill in a grid with values
/// </summary>
/// <typeparam name="TValue">The type of value that will fill the grid with</typeparam>
public interface IGridGenerator<TValue>
{
/// <summary>
/// Adds a set of shapes that we want avoid adding to the grid when filling it in
/// </summary>
/// <typeparam name="TType">The type of shape we are working with</typeparam>
/// <param name="shapes">The shapes we are avoiding when creating the grid</param>
/// <returns>Will return the generator for chaining</returns>
public IGridGenerator<TValue> WithoutShapes<TType>(params IShape<TValue, TType>[] shapes);

/// <summary>
/// Adds a getter to randomly set a value on the grid based on the value type
/// </summary>
/// <param name="randomGetter">The value getter to call when creating a new object</param>
/// <returns>Will return the generator for chaining</returns>
public IGridGenerator<TValue> WithRandomValue(Func<TValue> randomGetter);

/// <summary>
/// Will tell the generator to overwrite the whole grid and ignore nulls completely
/// </summary>
/// <returns>Will return the generator for chaining</returns>
public IGridGenerator<TValue> OverwriteNoneNulls();

/// <summary>
/// Will generate the grid with values
/// </summary>
public void Generate();
}
}
24 changes: 14 additions & 10 deletions MonoGame.Grid/Extensions/Models/IShape.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,27 @@

namespace MonoGame.Grid.Extensions
{
public interface IBaseShape<TValue>
{
/// <summary>
/// Helper method is meant to calculate a list of points that come from top right corner of the shape
/// </summary>
/// <param name="point">The starting top right corner of the shape</param>
/// <param name="grid">The grid we are checking against</param>
/// <returns>Will return a list of points that represent this shape or null if none was found</returns>
public List<Point>? HasShapeOnPoint(Point point, IGrid<TValue> grid);
}

/// <summary>
/// The shape we are searching for when looking on a grid
/// </summary>
/// <typeparam name="TValue">The type of value that exists in the grid that we want to find a shape for</typeparam>
public interface IShape<TValue>
/// <typeparam name="TType">The type of shape this is</typeparam>
public interface IShape<TValue, TType> : IBaseShape<TValue>
{
/// <summary>
/// The name of the shape we found
/// </summary>
public string Name { get; }

/// <summary>
/// Helper method is meant to calculate a list of points that come from top right corner of the shape
/// </summary>
/// <param name="point">The starting top right corner of the shape</param>
/// <param name="grid">The grid we are checking against</param>
/// <returns>Will return a list of points that represent this shape or null if none was found</returns>
public List<Point>? HasShapeOnPoint(Point point, Grid<TValue> grid);
public TType Type { get; }
}
}
Loading

0 comments on commit 32cc163

Please sign in to comment.