This is part of my Minesweeper dev log.

We started building more complex logic for autosolving. I won't give full detail here, because the basic idea was outlined in the first blog.

As we started, we realized we had to fix a couple of things:

By adding these lines, I was able to see the animation move slowly.

       ms().tk.update()
       time.sleep(0.5)

By adding a random seed to the main, I was able to check consistent boards.

After spending so much time rearranging code, I was starting to worry that this was progressing too slowly. (And in retrospect, I might have spent a little less time on cleanup.). But the autosolver bit progressed very quickly.

On the variable solver: Rather than implementing a backtracking approach, I just looped through the full power set of possible solutions, viewing a backtracker as an over-optimization. The resulting code is very sleek.

def solve_pair_of_constraints(x: Coord, y: Coord) -> List[Action]:
   vx, cx = get_variables_constraint(x)
   vy, cy = get_variables_constraint(y)
   v = list(set(vx) | set(vy))


   # We can make this part more efficient later if we need to
   valid = []
   for s in powerset(v):
       # s represents all the 1s, or mines
       meet_x = len([t for t in vx if t in s]) == cx
       meet_y = len([t for t in vy if t in s]) == cy
       if meet_x and meet_y:
           valid.append(s)

   result = []
   for t in v:
       if all([t in s for s in valid]):
           result.append(Action(type=ActionType.FLAG, coord=t))
       if not any([t in s for s in valid]):
           result.append(Action(type=ActionType.CLEAR, coord=t))

   return result

def solve_variable(coord: Coord) -> List[Action]:
   result = []
   constraint_neighbors = list(get_neighbors(coord).filter(lambda c: ms().grid[c].state == State.CLICKED))
   for x, y in itertools.combinations(constraint_neighbors, 2):
       result += solve_pair_of_constraints(x, y)
   return result

It's surprising how easy it'd be to generalize this to solve triple-constraints (perhaps easier than limiting to pairs). However, I don't think this is something I'd do as a human player, so I want to continue to have that not implemented.

And I'm happy to report, it's working as expected. This board was generated from a single click in the top-left.

alt_text

When I look at this board, I don't see any squares that I could click or flag deterministically. This brings me to the point of probabilistic decision-making, as desired.