Pheromone City
I've tried to make a city simulator before, and got quite close (link here), but I recently had an idea that may simplify things:
What if a building that provided housing "emitted" a housing "pheromone" that spread across the road network
This way, an ant/person/car can follow the "pheromone" in increasing strength towards their intended destination. Each frame the pheromone propagates, and if there is no more room in the house, it stops emitting the housing pheromone.
The Simulation
The proof-of-concept started simply:
- Factories provide jobs, and houses provide housing.
- Cars move from one to another
It worked well enough. In the 2D view it was easy enough to diagnose any issues. I noticed that houses near the factories were favoured. Since the people didn't spend more than a few seconds in a house or factory, we could support a lot of people since most of them were commuting one way or another.
Propagating is performed similar to a blur with a front buffer and back buffer that are swapped upon each calculation (each frame). A tile in the back buffer = the maximum value of all of its neighbours in the front buffer, minus a decay amount.
tile.buffers[writeBuffer].housing =
Math.max(cur.housing, left.housing, up.housing, right.housing, down.housing)
- decay;

Of course this is not like the real world. After work, I don't just pick the nearest house to go home to. Its probably more like ants in a colony, but it makes for an interesting-enough simulation.
I added different view modes, to inspect the "pheromones" that propagate along the road network. It simply uses greener colours to highlight tiles with a strong pheromone for that need, and redder colours for weaker values.

To ensure the simulation worked for more than just two needs (with their associated building types) I added a third. The rule was simple
- Sometimes after work, people drive to the shops, then home.
Factories and Houses have different capacities (3 and 2), and a shop can only hold one person. When looking at the view mode for the shopping need, it would flicker off and then on as a person enters then leaves a shop.
Improving Routing
The general rule for cars is to move to the next tile that is closer to their need. To improve car behaviour, it now:
- Only calculates direction changes at intersections, to stop the back-and-forth that sometimes occurs
- Incentivises moving forward, so there are less u-turns
- Traffic volume is approximated on each road tile, and a higher-volume tile results in a higher decay of these needs, leading to cars routing around high-traffic areas if possible.
3D Time
Before making it more complex, I decided to add 3D rendering. Since I've recently been trying three.js I figured this is a good fit and saves a bit of time on boilerplate code compared to vanilla WebGL.
I made a simple scene, with named objects for my different tile types

The scene itself uses some instancing and some cloned objects. I'm still trying to work out the best approach for all. To support the different view modes, I programmatically create some solid-colour textures from green to red, which get assigned to the road depending on the value.
A fair amount of work went into the car animations to make sure they drive on the left side of the road, and turn smoothly. There's still some work to be done but I think it looks nice.

A User Interface
The UI so far has been functional, but ugly. Here I am toying around with a HTML-based interface

Is it fun yet?
It's fun to watch, but I'm not sure I'm patient enough to turn it into a balanced game. Perhaps I can just leave it as a toy that people can mess around with. If you'd like to see continued development, maybe raise a GitHub issue with some ideas.
Here it is to try out: madcoretom.github.io/pheromone-city
And here is a link to the GitHub repo: github.com/MadcoreTom/pheromone-city