Skip to content

Instantly share code, notes, and snippets.

@MerlinTwi
Last active August 7, 2019 12:55
Show Gist options
  • Save MerlinTwi/39061a7427bf6e2537ccc666a5768931 to your computer and use it in GitHub Desktop.
Save MerlinTwi/39061a7427bf6e2537ccc666a5768931 to your computer and use it in GitHub Desktop.
// Перебор координат по спирали против часовой стрелки:
// (0:0), (1:0), (1:1), (0:1), (-1:1), (-1:0), (-1:-1), (0:-1), (1:-1), (2:-1), (2:0), (2:1), (2:2), (1:2), (0:2), (-1:2), (-2:2), (-2:1), (-2:0), (-2:-1), (-2:-2), (-1:-2), (0:-2), (1:-2), (2:-2), (3:-2), ...
// Для полной спирали до (1:-1) цикл до 8, (2:-2)=24, (3:-3)=48, (4:-4)=80, (5:-5)=120, (10:-10)=440, (15:-15)=960
// https://i.stack.imgur.com/NE82F.png
int x = 0, y = 0, dx = 0, dy = -1;
for (var i=0; i <= 48; i++){
Console.Write("("+x+":"+y+"), ");
// do stuff...
// Если нужны какие-то действия после совершения очередного полного оборота:
// if (x > 0 && x == -y) { /* текущая координата в правом нижнем углу */ do stuff... }
if ((x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1-y))) {
var t = dx;
dx = -dy;
dy = t;
}
x += dx;
y += dy;
}
using UnityEngine;
namespace Common {
/// <summary>
/// Перебор координат по спирали против часовой стрелки:
/// (0:0),
/// (1:0), (1:1), (0:1), (-1:1), (-1:0), (-1:-1), (0:-1), (1:-1),
/// (2:-1), (2:0), (2:1), (2:2), (1:2), (0:2), (-1:2), (-2:2), (-2:1), (-2:0), (-2:-1), (-2:-2), (-1:-2), (0:-2), (1:-2), (2:-2),
/// (3:-2), ...
/// Смещение maxOffset => количество итераций:
/// 0 => 1
/// 1 => 9
/// 2 => 25
/// 3 => 49
/// 4 => 81
/// 5 => 121
/// 10 => 441
/// 15 => 961
/// 16 => 1089
/// https://i.stack.imgur.com/NE82F.png
/// </summary>
/// <example>
/// foreach (Vector2Int v in new LoopSpiralEnumerator(maxDistance)) { ... }
/// </example>
public struct LoopSpiralEnumerator {
private readonly int _maxX;
private Vector2Int _current;
private sbyte _dx, _dy;
/// <summary>
/// Перебор координат по спирали против часовой стрелки
/// Закончится целым количеством оборотов, когда Current.x >= maxOffset
/// </summary>
public LoopSpiralEnumerator(int maxOffset) {
_maxX = maxOffset;
_current = new Vector2Int();
_dx = 0;
_dy = 0;
}
public Vector2Int Current {
get { return _current; }
}
public bool MoveNext() {
if (_dx == 0 && _dy == 0) {
_current = new Vector2Int();
_dx = 0;
_dy = -1;
return true;
}
var x = _current.x;
var y = _current.y;
if (x >= 0 && x == -y) {
// сделали полный оборот, текущая координата в правом нижнем углу
if (x >= _maxX) return false;
}
if ((x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1 - y))) {
var t = _dx;
_dx = (sbyte) -_dy;
_dy = t;
}
_current.Set(x+_dx, y+_dy);
return true;
}
public void Reset() {
_dx = 0;
_dy = 0;
}
public LoopSpiralEnumerator GetEnumerator() {
return this;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment