Skip to content

Instantly share code, notes, and snippets.

@justinmeiners
Last active December 5, 2024 08:07
Show Gist options
  • Save justinmeiners/af58cea12ca476b73d9b195038c4f0f0 to your computer and use it in GitHub Desktop.
Save justinmeiners/af58cea12ca476b73d9b195038c4f0f0 to your computer and use it in GitHub Desktop.
How to iterate neighbors of a grid concisely with a for loop.
#include <algorithm>
#include <iostream>
// Suppose we need to iterate over the neighbors of a cell in a 2D grid:
//
// * * *
// * - *
// * * *
//
// This can be done with the following well known pattern:
void all_neighbors() {
for (int i = -1; i <= 1; ++i) {
for (int j = -1; j <= 1; ++j) {
if (i == 0 && j == 0) continue;
std::cout << i << ", " << j << std::endl;
}
}
}
// But what if we just want to iterate the horizontal and vertical neighbors, skipping the diagonal?
//
// *
// * - *
// *
//
// Most programs explicilty repeat the operation 4 times, or use a table.
// But there is a trick to do it in a loop.
// Think of the neighbor as a vector offset, and then rotate it 90 degrees, 4 times.
template <typename I>
void rotate_2d(I& a, I& b) {
std::swap(a, b);
b = -b;
}
void direct_neighbors() {
int i = 1;
int j = 0;
for (int k = 0; k < 4; ++k) {
std::cout << i << ", " << j << std::endl;
rotate_2d(i, j);
}
}
int main() {
std::cout << "diagonal" << std::endl;
all_neighbors();
std::cout << "square" << std::endl;
direct_neighbors();
}
@nicholaschiasson
Copy link

Since this is coming up in google searches, I think it's worth correcting that the condition i == j yields the wrong output for the diagonal neighbors loop.
You instead want to only skip the iteration where both i and j are 0. By continuing when i == j, you skip -1, -1 and 1, 1, the top left and bottom right.

@justinmeiners
Copy link
Author

justinmeiners commented Dec 5, 2024

@nicholaschiasson thanks! 🤦🏻

How does that look?

@nicholaschiasson
Copy link

Great! 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment