Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags

I'll spare you my code; the pseudocode is something like:

def fill_grid(grid_so_far, known_paths):
    while true:
        if all grid spaces are filled and there are 19 Xs in the grid, print and quit
        if there aren't enough empty spaces left to reach 19 Xs, return
        find the northeastmost space that hasn't been filled
        make a new grid where that space has an X and every space around it has a .
        if <check_for_path> is true:
            fill_grid(new_grid_so_far, new_known_paths)
        # if we get here, that must have failed at some step, so...
        make that space a "." instead
def check_for_path(grid, known_paths):
    for every space in the grid:
        if it's already in known_paths, we're good;
        otherwise, if it's a ".", crawl through the grid and make sure it's either:
            connected by other "." to something that *does* have a known path to the edge
                (in which case, add it to the set of things with known paths),
            or at least is connected to an empty space
    return false if some "." was blocked from the edge, otherwise true

and then run fill_grid() with a grid that has dots along the north and east edge, and all of those dots have (of course) a path to the edge.

Usually I'd guess that there's another symmetric solution, but the "north and east edges only" constraint may prevent that.