Incomplete draft: do not cite!

seagrasssand seagrasssand seagrasssand
seagrasssand seagrasssand seagrasssand
seagrasssand seagrasssand seagrasssand

Now let's change the constraints somewhat.  Let's say that only another grass tile can be to the left of a grass tile.  Then if we place a grass tile on the right side:

seagrasssand seagrasssand seagrasssand
seagrasssand seagrasssand grass
seagrasssand seagrasssand seagrasssand

Then it not only removes water from consideration for its neighbors, as before:

seagrasssand seagrasssand grasssand
seagrasssand grasssand grass
seagrasssand seagrasssand grasssand

But now it also forces the tile to the left to also be grass:

seagrasssand seagrasssand grasssand
seagrasssand grass grass
seagrasssand seagrasssand grasssand

That removes water from consideration for its neighbors:

seagrasssand grasssand grasssand
grasssand grass grass
seagrasssand grasssand grasssand

But then the cell to the left of it also has to be grass:

seagrasssand grasssand grasssand
grass grass grass
seagrasssand grasssand grasssand

which, again, restricts the cells above and below it:

grasssand grasssand grasssand
grass grass grass
grasssand grasssand grasssand

So setting one tile impacted the tiles of every cell on the grid and fully determined the tile of two other cells.

Constraint propagation

This is called constraint propagation: as we narrow the choices of one cell, we update the choices of the neighboring cells.  This will never add new possibilities for the neighbors, but it can potentially remove them; when it does, we recursively update their neighbors, and so on, until no more cells can be narrowed.

There are two important possible outcomes for a cell.  If it is narrowed to a single possibility (aka a singleton set), then we know that cell has to have that tile.  On the other hand, if we remove all possibilities from a cell (we reduce it to the empty set), then we know that the choice that started the propagation process was incorrect, and we fail, meaning the solver has to reconsider one of the previous choices.

That's the basic algorithm for solving constraint satisfaction problems: start by allowing every cell to have every possible value.  Then gradually pick values for cells from among their possible values.  Each time, propagate that narrowing through the network of constraints, potentially narrowing the other cells.  If we narrow a cell to nothing, fail, if we're narrowed all cells to singletons, we're done.