-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHexPoint.cs
350 lines (311 loc) · 13.4 KB
/
HexPoint.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
// Ishan Pranav's REBUS: HexPoint.cs
// Copyright (c) 2021-2022 Ishan Pranav. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using MessagePack;
namespace Rebus
{
/// <summary>
/// Represents a cubic coordinate in three dimensions (<em>Q</em>, <em>R</em>, and <em>S</em>) used to identify a location in a grid of hexagons.
/// </summary>
/// <remarks>
/// The implementation of this struct was inspired by and based on <see href="https://www.redblobgames.com/grids/hexagons/">this</see> article by <see href="http://www-cs-students.stanford.edu/~amitp/">Amit Patel</see>.
/// </remarks>
/// <seealso href="https://www.redblobgames.com/grids/hexagons/">Red Blob Games - Hexagonal Grids</seealso>
/// <seealso href="http://www-cs-students.stanford.edu/~amitp/">Amit Patel's Home Page</seealso>
[MessagePackObject]
public readonly struct HexPoint : IComparable, IComparable<HexPoint>, IEquatable<HexPoint>
{
private static readonly HexPoint[] s_directions = new HexPoint[]
{
new HexPoint(1, 0),
new HexPoint(1, -1),
new HexPoint(0, -1),
new HexPoint(-1, 0),
new HexPoint(-1, 1),
new HexPoint(0, 1)
};
/// <summary>
/// Specifies the coordinate whose three axes are zero.
/// </summary>
/// <value>The coordinate (0, 0, 0).</value>
public static readonly HexPoint Empty;
/// <summary>
/// Gets the <em>Q</em> coordinate.
/// </summary>
/// <value>The <em>Q</em> coordinate. The default is 0.</value>
[Key(0)]
public int Q { get; }
/// <summary>
/// Gets the <em>R</em> coordinate.
/// </summary>
/// <value>The <em>R</em> coordinate. The default is 0.</value>
[Key(1)]
public int R { get; }
/// <summary>
/// Gets the <em>S</em> coordinate.
/// </summary>
/// <value>The <em>S</em> coordinate. The default is 0.</value>
[IgnoreMember]
public int S
{
get
{
return -Q - R;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="HexPoint"/> struct.
/// </summary>
/// <param name="q">The <em>Q</em> coordinate.</param>
/// <param name="r">The <em>R</em> coordinate.</param>
public HexPoint(int q, int r)
{
Q = q;
R = r;
}
/// <inheritdoc/>
public override string ToString()
{
return $"({Q}, {R}, {S})";
}
/// <summary>
/// Returns a new <see cref="HexPoint"/> that adds the value of the specified <see cref="HexPoint"/> to the value of this instance.
/// </summary>
/// <param name="other">A positive or negative hexagonal coordinate.</param>
/// <returns>An object whose value is the sum of the hexagonal coordinates represented by this instance and the <paramref name="other"/> value.</returns>
public HexPoint Add(HexPoint other)
{
return new HexPoint(Q + other.Q, R + other.R);
}
/// <summary>
/// Returns the value that results from subtracting the specified hexagonal coordinate from the value of this instance.
/// </summary>
/// <param name="other">The hexagonal coordinate to subtract.</param>
/// <returns>A hexagonal coordinate that is equal to this instance minus the <paramref name="other"/> value.</returns>
public HexPoint Subtract(HexPoint other)
{
return new HexPoint(Q - other.Q, R - other.R);
}
/// <summary>
/// Returns the value that results from multiplying the specified factor by the value of this instance.
/// </summary>
/// <param name="factor">The factor to multiply.</param>
/// <returns>A hexagonal coordinate that is equal to this instance times the <paramref name="factor"/>.</returns>
public HexPoint Multiply(int factor)
{
return new HexPoint(Q * factor, R * factor);
}
/// <summary>
/// Gets the six coordinates adjacent to this instance.
/// </summary>
/// <returns>The neighboring coordinates.</returns>
public IEnumerable<HexPoint> Neighbors()
{
for (int i = 0; i < s_directions.Length; i++)
{
yield return this + s_directions[i];
}
}
/// <summary>
/// Gets the coordinates within a hexagonal range.
/// </summary>
/// <param name="radius">The radius of the range.</param>
/// <returns>The coordinates within the range defined by the given <paramref name="radius"/>.</returns>
public IEnumerable<HexPoint> Range(int radius)
{
for (int q = -radius; q <= radius; q++)
{
for (int r = Math.Max(-radius, -radius - q); r <= Math.Min(radius, radius - q); r++)
{
yield return this + new HexPoint(q, r);
}
}
}
/// <summary>
/// Gets the coordinates within a hexagonal ring.
/// </summary>
/// <param name="radius">The radius of the ring.</param>
/// <returns>The coordinates within the ring defined by the given <paramref name="radius"/>.</returns>
public IEnumerable<HexPoint> Ring(int radius)
{
HexPoint value = this + (s_directions[4] * radius);
foreach (HexPoint direction in s_directions)
{
for (int i = 0; i < radius; i++)
{
yield return value;
value += direction;
}
}
}
/// <summary>
/// Gets the coordinates within a hexagonal spiral.
/// </summary>
/// <param name="radius">The radius of the spiral.</param>
/// <returns>The coordinates within the spiral defined by the given <paramref name="radius"/>.</returns>
public IEnumerable<HexPoint> Spiral(int radius)
{
yield return this;
for (int i = 1; i <= radius; i++)
{
foreach (HexPoint value in Ring(i))
{
yield return value;
}
}
}
/// <summary>
/// Gets the distance between two hexagonal coordinates.
/// </summary>
/// <param name="value1">The first value.</param>
/// <param name="value2">The second value.</param>
/// <returns>The distance between <paramref name="value1"/> and <paramref name="value2"/>.</returns>
public static int Distance(HexPoint value1, HexPoint value2)
{
HexPoint difference = value1 - value2;
return (Math.Abs(difference.Q) + Math.Abs(difference.R) + Math.Abs(difference.S)) / 2;
}
/// <inheritdoc/>
public override bool Equals(object? obj)
{
return obj is HexPoint other && Equals(other);
}
/// <inheritdoc/>
public bool Equals(HexPoint other)
{
return other.Q == Q && other.R == R;
}
/// <inheritdoc/>
public override int GetHashCode()
{
HashCode result = new HashCode();
result.Add(Q);
result.Add(R);
return result.ToHashCode();
}
/// <inheritdoc/>
public int CompareTo(object? obj)
{
if (obj is HexPoint other)
{
return CompareTo(other);
}
else
{
throw new ArgumentException("Argument is not a HexPoint instance.", nameof(obj));
}
}
/// <inheritdoc/>
public int CompareTo(HexPoint other)
{
int result = Q.CompareTo(other.Q);
if (result == 0)
{
result = R.CompareTo(R);
}
return result;
}
/// <summary>
/// Returns a value that indicates whether two coordinates are equal.
/// </summary>
/// <param name="left">The first coordinate to compare.</param>
/// <param name="right">The second coordinate to compare.</param>
/// <returns><see langword="true"/> if <paramref name="left"/> and <paramref name="right"/> are equal; otherwise, <see langword="false"/>.</returns>
public static bool operator ==(HexPoint left, HexPoint right)
{
return left.Equals(right);
}
/// <summary>
/// Returns a value that indicates whether two coordinates are not equal.
/// </summary>
/// <param name="left">The first coordinate to compare.</param>
/// <param name="right">The second coordinate to compare.</param>
/// <returns><see langword="true"/> if <paramref name="left"/> and <paramref name="right"/> are not equal; otherwise, <see langword="false"/>.</returns>
public static bool operator !=(HexPoint left, HexPoint right)
{
return !(left == right);
}
/// <summary>
/// Adds a specified coordinate to another specified coordinate.
/// </summary>
/// <param name="left">The first coordinate to add.</param>
/// <param name="right">The second coordinate to add.</param>
/// <returns>The sum of <paramref name="left"/> and <paramref name="right"/>.</returns>
public static HexPoint operator +(HexPoint left, HexPoint right)
{
return left.Add(right);
}
/// <summary>
/// Subtracts a specified coordinate from another specified coordinate.
/// </summary>
/// <param name="left">The value to subtract from (the minuend).</param>
/// <param name="right">The value to subtract (the subtrahend).</param>
/// <returns>The result of subtracting <paramref name="right"/> from <paramref name="left"/>.</returns>
public static HexPoint operator -(HexPoint left, HexPoint right)
{
return left.Subtract(right);
}
/// <summary>
/// Multiplies a specified coordinate by a number.
/// </summary>
/// <param name="left">The coordinate to multiply.</param>
/// <param name="right">The number to multiply.</param>
/// <returns>The product of <paramref name="left"/> and <paramref name="right"/>, as a hexagonal coordinate.</returns>
public static HexPoint operator *(HexPoint left, int right)
{
return left.Multiply(right);
}
/// <summary>
/// Multiplies a number by a specified coordinate.
/// </summary>
/// <param name="left">The number to multiply.</param>
/// <param name="right">The coordinate to multiply.</param>
/// <returns>The product of <paramref name="left"/> and <paramref name="right"/>, as a hexagonal coordinate.</returns>
public static HexPoint operator *(int left, HexPoint right)
{
return right.Multiply(left);
}
/// <summary>
/// Returns a value that indicates whether a specified value is less than another specified value.
/// </summary>
/// <param name="left">The first value to compare.</param>
/// <param name="right">The second value to compare.</param>
/// <returns><see langword="true"/> if <paramref name="left"/> is less than <paramref name="right"/>; otherwise, <see langword="false"/>.</returns>
public static bool operator <(HexPoint left, HexPoint right)
{
return left.CompareTo(right) < 0;
}
/// <summary>
/// Returns a value that indicates whether a specified value is less than or equal to another specified value.
/// </summary>
/// <param name="left">The first value to compare.</param>
/// <param name="right">The second value to compare.</param>
/// <returns><see langword="true"/> if <paramref name="left"/> is less than or equal to <paramref name="right"/>; otherwise, <see langword="false"/>.</returns>
public static bool operator <=(HexPoint left, HexPoint right)
{
return left.CompareTo(right) <= 0;
}
/// <summary>
/// Returns a value that indicates whether a specified value is greater than another specified value.
/// </summary>
/// <param name="left">The first value to compare.</param>
/// <param name="right">The second value to compare.</param>
/// <returns><see langword="true"/> if <paramref name="left"/> is greater than <paramref name="right"/>; otherwise, <see langword="false"/>.</returns>
public static bool operator >(HexPoint left, HexPoint right)
{
return left.CompareTo(right) > 0;
}
/// <summary>
/// Returns a value that indicates whether a specified value is greater than or equal to another specified value.
/// </summary>
/// <param name="left">The first value to compare.</param>
/// <param name="right">The second value to compare.</param>
/// <returns><see langword="true"/> if <paramref name="left"/> is greater than or equal to <paramref name="right"/>; otherwise, <see langword="false"/>.</returns>
public static bool operator >=(HexPoint left, HexPoint right)
{
return left.CompareTo(right) >= 0;
}
}
}