-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTileMap.cs
121 lines (106 loc) · 4.09 KB
/
TileMap.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
using System;
using System.Collections.Generic;
namespace AbstractTileGame
{
/// <summary>
/// Represents a map, which contains of titles. The tile map does not handle the actual layout of the titles and can be
/// used for any two dimensional (in terms of each tile has distinct two dimensional integer coordiates) tile array.
/// </summary>
/// <typeparam name="T">The type of the tiles in this map</typeparam>
/// <remarks>
/// The tile map will grow when needed. If it grows it will create a new chunk of n x n titles, where n is the
/// chucksize given in the constructor. The default size is 127.
/// </remarks>
public class TileMap<T>
{
private readonly HashSet<TilePosition> _placedTiles = new HashSet<TilePosition>();
private IRecursiveTileMap<T> _map;
private ChunckSize _size;
/// <summary>
/// Creates a new Tilemap with a chunksize of 127.
/// </summary>
public TileMap() : this(chunksize: 127)
{
}
/// <summary>
/// Creates a nee tile map
/// </summary>
/// <param name="chunksize">The lenght of each side of a chunk. Must be greater than two.</param>
public TileMap(int chunksize)
{
if (chunksize <= 2)
throw new ArgumentException("Chunksize must be greater than 2.", nameof(chunksize));
_map = new TileChunk<T>(chunksize);
_size = new ChunckSize(chunksize);
}
/// <summary>
/// Gets the tile at a specific postion.
/// </summary>
/// <param name="position">The position of a tile</param>
/// <returns>The tile at the specified position.</returns>
public T this[ITilePosition position]
{
get
{
if (position == null) throw new ArgumentNullException(nameof(position));
return this[position.X, position.Y];
}
set
{
if (position == null) throw new ArgumentNullException(nameof(position));
this[position.X, position.Y] = value;
}
}
public T this[int x, int y]
{
get => _size.Contains(x, y) ? _map[x, y] : default;
set
{
while (!_size.Contains(x, y))
{
_map = new RecursiveTileMap<T>(_map, _size.ChunkSize);
_size++;
}
_map[x, y] = value;
OnTilePlaced(x, y, value);
}
}
public IEnumerable<TilePosition> PlacedTilesPositions => _placedTiles;
protected virtual void OnTilePlaced(int x, int y, T tile)
{
if (Equals(tile, default(T)))
_placedTiles.Remove((x,y));
else
_placedTiles.Add((x,y));
}
private struct ChunckSize
{
public int ChunkSize { get; }
private readonly int _min;
private readonly int _max;
private readonly int _upperFactor;
private readonly int _lowerFactor;
public ChunckSize(int chunkSize) : this(chunkSize, min: 0, max: chunkSize, upperFactor: (chunkSize - 1) / 2,
lowerFactor: chunkSize / 2)
{
}
private ChunckSize(int chunkSize, int min, int max, int upperFactor, int lowerFactor)
{
ChunkSize = chunkSize;
_min = min;
_max = max;
_upperFactor = upperFactor;
_lowerFactor = lowerFactor;
}
public bool Contains(int x, int y)
{
return _min <= x && x < _max && _min <= y && y < _max;
}
public static ChunckSize operator ++(ChunckSize other)
{
return new ChunckSize(other.ChunkSize, other._min - other.ChunkSize * other._lowerFactor,
other._max + other.ChunkSize * other._upperFactor, other._upperFactor, other._lowerFactor);
}
}
}
}