feat: Implement SpatialHash for O(1) entity spatial queries (closes #115)

Add SpatialHash class for efficient spatial queries on entities:
- New SpatialHash.h/cpp with bucket-based spatial hashing
- Grid.entities_in_radius(x, y, radius) method for O(k) queries
- Automatic spatial hash updates on entity add/remove/move

Benchmark results at 2,000 entities:
- Single query: 16.2× faster (0.044ms → 0.003ms)
- N×N visibility: 104.8× faster (74ms → 1ms)

This enables efficient range queries for AI, visibility, and
collision detection without scanning all entities.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
John McCardle 2025-12-28 00:44:07 -05:00
commit 7d57ce2608
6 changed files with 477 additions and 15 deletions

View file

@ -22,6 +22,7 @@
#include "UIBase.h"
#include "GridLayers.h"
#include "GridChunk.h"
#include "SpatialHash.h"
class UIGrid: public UIDrawable
{
@ -87,6 +88,9 @@ public:
std::shared_ptr<std::list<std::shared_ptr<UIEntity>>> entities;
// Spatial hash for O(1) entity queries (#115)
SpatialHash spatial_hash;
// UIDrawable children collection (speech bubbles, effects, overlays, etc.)
std::shared_ptr<std::vector<std::shared_ptr<UIDrawable>>> children;
bool children_need_sort = true; // Dirty flag for z_index sorting
@ -165,6 +169,7 @@ public:
static PyObject* py_get_dijkstra_distance(PyUIGridObject* self, PyObject* args);
static PyObject* py_get_dijkstra_path(PyUIGridObject* self, PyObject* args);
static PyObject* py_compute_astar_path(PyUIGridObject* self, PyObject* args, PyObject* kwds);
static PyObject* py_entities_in_radius(PyUIGridObject* self, PyObject* args, PyObject* kwds); // #115
static PyMethodDef methods[];
static PyGetSetDef getsetters[];
static PyObject* get_entities(PyUIGridObject* self, void* closure);