Metadata-Version: 2.4
Name: citygrid
Version: 0.1.0
Summary: Zone classification, road generation, pathfinding, and urban analytics for a grid of buildings
Project-URL: Homepage, https://github.com/Joetankm/citygrid
Project-URL: Repository, https://github.com/Joetankm/citygrid
Project-URL: Issues, https://github.com/Joetankm/citygrid/issues
Author-email: Joe Tan <jtkmjoe@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: city-simulation,game-dev,gis,grid,pathfinding,urban-planning,walkability,zoning
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Description-Content-Type: text/markdown

# citygrid

Zone classification, road generation, pathfinding, and urban analytics for
a grid of axis-aligned rectangular buildings.

Originally built for a physical LEGO-brick smart-city simulator, extracted
into a standalone library because the underlying logic — "given a bunch of
rectangles on a grid, classify zones, connect them with roads, and score
the layout" — is generic enough to be useful for city-builder games, urban
planning teaching tools, and GIS prototyping.

Zero required dependencies — pure Python, `math`/`heapq`/`dataclasses` only.

## Install

```bash
pip install citygrid
```

## What it does

**Zoning** (`compute_zones`) — connected-component BFS groups nearby
buildings into blocks, then classifies each block as Residential,
Commercial, Industrial, or Mixed based on height/footprint mix; empty
areas become Green space.

**Roads** (`generate_roads`) — two-phase A* generates a closed-circuit
road network along zone-block faces, connecting every block without
cutting through building footprints.

**Pathfinding** (`pathfind`) — shortest walkable route between two
buildings by ID, with real-world distance in meters.

**Analytics** (`compute_all` and friends) — population & per-capita
resource use, walkability score (Dijkstra distance-to-amenity), zone
balance flags (unemployment risk, ghost town, dormitory suburb, etc.),
crucial-service coverage (hospitals/schools/fire/police), an SDG
green-space score, a carbon-neutrality timeline, and rooftop solar
potential.

## Usage

```python
from citygrid import compute_zones, generate_roads, compute_all, GridConfig

# buildings: list of {id, grid_x, grid_y, width_studs, depth_studs,
#                      height_bricks, building_type (optional)}
buildings = [
    {"id": 1, "grid_x": 0, "grid_y": 0, "width_studs": 2, "depth_studs": 2, "height_bricks": 6},
    {"id": 2, "grid_x": 3, "grid_y": 0, "width_studs": 2, "depth_studs": 2, "height_bricks": 6},
    {"id": 3, "grid_x": 0, "grid_y": 3, "width_studs": 2, "depth_studs": 2, "height_bricks": 1},
]

zones = compute_zones(buildings)
roads = generate_roads(buildings)
stats = compute_all(buildings, zones)

print(stats["population"])   # {'total_pop': ..., 'density': ..., 'energy': ..., ...}
print(stats["walkability"])  # {'score': ..., 'avg_dist': ..., 'unreachable': ...}
```

### Custom grid size / thresholds

Every constant — grid dimensions, per-capita resource use, zone-balance
thresholds, walkability distance cap, and more — lives in one overridable
`GridConfig`:

```python
from citygrid import GridConfig, compute_all

config = GridConfig(
    grid_width=32, grid_height=32,   # smaller board
    stud_meters=5.0,                 # different real-world scale
    walk_max_meters=800,             # stricter walkability target
)
stats = compute_all(buildings, zones, config)
```

If you don't pass a `config`, every function uses `GridConfig()`'s
defaults (a 64x64 grid at 10 real-world meters per cell — the values this
library was originally tuned against).

## Development

```bash
pip install -e ".[dev]"
pytest
```

## License

MIT
