Here's the best solution I could come up with:
Some details:
- The bottom floor is one block off the ground; in hard mode this prevents zombies from breaking down the doorsthis prevents zombies from breaking down the doors.
- The buildings are 7x7 with a 1 block ledge on the higher levels, so each has a 9x9 footprint. (The footprint expands to 11x11 when you consider the mandatory airspace that must exist about the complex for the village code to register the door properly.)
- There are a series of staircases inside the buildings to access the higher levels.
- I built columns between doors because I found in practice the villagers had a hard time navigating through doors touching each other.
- Each floor is 12 doors, yielding > 4 villagers per floor
- There's a 3-block gap between buildings which gives a 1-block gap between ledges. This ensures the 'outside' is computed properly by the village code.
- On higher levels I have connecting blocks between ledges at the intersection of buildings; these do not interfere with the 'outside' computations, as they aren't directly in line with any doors.
Now that I have plenty of villagers it's a matter of pruning out the bad onespruning out the bad ones.