Finish Day 08
This commit is contained in:
parent
d9bc639366
commit
00bfb7d46e
11 changed files with 308 additions and 1 deletions
126
src/core/SymbolGrid.cs
Normal file
126
src/core/SymbolGrid.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.Numerics;
|
||||
|
||||
namespace core;
|
||||
|
||||
public class SymbolGrid
|
||||
{
|
||||
private char[]? _map;
|
||||
|
||||
[DisallowNull]
|
||||
public char? this[int x, int y]
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureMap();
|
||||
return IsValid(x, y) ? _map[y * Height + x] : null;
|
||||
}
|
||||
set
|
||||
{
|
||||
EnsureMap();
|
||||
if (IsValid(x, y))
|
||||
{
|
||||
_map[y * Height + x] = value.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DisallowNull]
|
||||
public char? this[Vector2I i]
|
||||
{
|
||||
get => this[i.X, i.Y];
|
||||
set => this[i.X, i.Y] = value;
|
||||
}
|
||||
|
||||
public int Width { get; private set; }
|
||||
|
||||
public int Height { get; private set; }
|
||||
|
||||
public void Load(string file)
|
||||
{
|
||||
using var fileView = MemoryMappedFile.CreateFromFile(file, FileMode.Open);
|
||||
using var accessor = fileView.CreateViewAccessor();
|
||||
(Width, var stride, Height) = Parse(accessor);
|
||||
_map = new char[Width * Height];
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
for (int y = 0; y < Height; y++)
|
||||
{
|
||||
_map[y * Height + x] = (char)accessor.ReadByte(y * stride + x);
|
||||
}
|
||||
}
|
||||
|
||||
static (int Width, int Stride, int Height) Parse(MemoryMappedViewAccessor map)
|
||||
{
|
||||
bool hasNewLine = false;
|
||||
int? width = null, stride = null;
|
||||
for (int i = 0; i < map.Capacity; i++)
|
||||
{
|
||||
if ((char)map.ReadByte(i) is '\r' or '\n')
|
||||
{
|
||||
if (!hasNewLine)
|
||||
{
|
||||
width = i;
|
||||
}
|
||||
|
||||
hasNewLine = true;
|
||||
}
|
||||
else if (hasNewLine)
|
||||
{
|
||||
stride = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (width!.Value, stride!.Value, (int)((map.Capacity + width.Value) / stride.Value));
|
||||
}
|
||||
}
|
||||
|
||||
public SymbolEnumerator GetEnumerator() => new(this);
|
||||
|
||||
public bool IsValid(Vector2I p) => IsValid(p.X, p.Y);
|
||||
|
||||
public bool IsValid(int x, int y)
|
||||
{
|
||||
EnsureMap();
|
||||
return x >= 0 && x < Width && y >= 0 && y < Height;
|
||||
}
|
||||
|
||||
public ref struct SymbolEnumerator
|
||||
{
|
||||
private readonly SymbolGrid _grid;
|
||||
private readonly int _length;
|
||||
private int? _current;
|
||||
|
||||
internal SymbolEnumerator(SymbolGrid grid)
|
||||
{
|
||||
_grid = grid;
|
||||
_length = grid.Width * grid.Height;
|
||||
}
|
||||
|
||||
public (Vector2I Position, char Symbol) Current { get; private set; }
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
_current = _current.HasValue ? _current + 1 : 0;
|
||||
if (_current == _length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Current = (_grid.ToVector(_current.Value), _grid._map![_current.Value]);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2I ToVector(int index) => new()
|
||||
{
|
||||
Y = index / Height,
|
||||
X = index % Height
|
||||
};
|
||||
|
||||
[MemberNotNull(nameof(_map))]
|
||||
private void EnsureMap() => ArgumentNullException.ThrowIfNull(_map);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue