I'm working on a solo game project that uses procedural generation to create maps (let's consider only one layer for now, which uses Cellular Automata).
The map is 2D so I'm just modeling a layer as a 2D array with 0 (no tile) and 1 (tile) values.
I'm using Godot 4.2 so its terrain system is handling connections between tiles for me (picking the right tile base on connections).
Technical context
In 2D, each tile can be connected to up to 8 tiles (in all 8 directions), which means that there's a total of 64 possible connection patterns, which means that in order to be able to generate a map from this, I'd have to have a TileSet that's composed of 64 tiles per layer of a map (so 64 light grass, 64 dark grass, 64 sand and so on...).
My goal is to reduce this, even if it means having more "square-ish" layers, the cost reduction here is very important. So I decided on going with 17 patterns, which are represented in this screenshot (basically direct side junctions, inner corners and outer corners):
This reduces the cost of a single map by 73% (whether it's time or money, whatever), as 73% less tiles need to be created.
The problem
So I modeled every single pattern using a byte mask (there's 8 sides, perfect to fit in a byte), stored them, and then iterating on every single tile that has a 1 to check if it's using one of the "approved" pattern, removing it if it doesn't.
But yeah, removing a tile means that it's quite possible that you're breaking the pattern of the tiles next to it too, and guess what, it's what's happening, the layer ends up empty.
So I'm thinking maybe I should not always remove the tile but maybe add one instead to transform the pattern into one that is "approved" but that's where I'm stuck, it also means modifying the pattern for the tiles next to it which means that the same issue will appear.
Example case:
I'm going to represent grids using basic 0 and 1, 1 is "filled" and 0 is "empty".
This example grid (obviously made small for the purpose of this question):
0 1 0 1 0 0 0 0 0
1 1 1 1 1 1 1 1 0
0 1 1 0 1 1 1 0 1
0 1 0 0 0 1 1 0 0
0 0 0 0 1 1 1 0 0
0 0 0 0 1 1 1 1 0
0 0 0 0 1 1 1 0 0
0 0 0 1 1 1 1 1 0
0 0 0 0 0 1 1 0 1
Theere's many patterns that aren't supported, for instance taking coords (1,1) as center, we get this:
0 1 0
1 1 1
0 1 1
This is an unsupported pattern because we don't have a tile that can fit the center of the pattern (no tile matches the case of this pattern), meaning that we could want to remove it, meaning that everything around would be removed.
Another approach could be to try to fill the pattern in order to make it fit an approved pattern, resulting in something like this for instance:
0 0 0
0 1 1
0 1 1
Which means that the center tile of this pattern can be an "outer corner". Another pattern could also be used instead as the base one can be used to create many patterns from it without adding or removing too many 1 or 0.
Question
Is there a better approach to this kind of issue? I feel like I'm just missing knowledge on the topic and there's a simple way to do it.
