You can see the problem clearly here (the red overlays are tiles that were identified as dirtied on the previous frame):
And this is what it should look like:
I made the mistake of assuming that the width of the rect divided by the tileWidth was the number of dirty tiles but that can’t be assumed to be true when they are the same width.
Except even this is wrong, it’s too greedy. Even when perfectly aligned to a tile it still dirties the next column and row.
Here we go:
When the player is perfectly aligned with the tile grid (like when they’re against the left side of the screen) they only dirty a single tile as expected. We got there!