The way you are thinking about what qualifies for a disc to be stable right now
For it to be stable in any direction, either the direction can be full
of discs so that no more can be placed, it can be next to the edge of
the board, or it is adjacent to a stable disc of the same color.
makes it extremely hard to design a correct and reliable method to find stability for all discs. Let's instead think about what qualifies for a disc to be stable from a basic standpoint and work our way from there.
There are 8 directions around any square in the board with 4 pairs of opposing directions, i.e. up and down. In order for a disc to be marked as stable, then for each pair of opposing directions, it cannot have a blank square on either side that the opponent can potentially place at to capture that disc. This is only the case when at least one of the directions for each pair hits a border for the board (by passing through discs of the same color) — which is why corner discs are always going to be stable, they are "protected" for all 4 directional pairs. Likewise, edge discs by themselves are not stable since they have a non-protected directional pair parallel to the border they are adjacent to even though the other 3 pairs are protected.
So the brute force method seems to be to go through each disc currently on the board, go through all the directional pairs for that disc, and check to see if all of them hit the border at least once (when allowed to travel through discs of the same color); if that's the case, then we would mark that disc as stable.
However, this can be optimized in two major ways.
- Notice that the only way any discs are going to be stable is if any of the corners are occupied. So if none of the corners are occupied by a disc, automatically return the number of stable discs as 0.
- We can also notice that for adjacent discs going in a certain direction, for that corresponding direction pair, all the discs of that color will either be protected or not protected. So rather than checking whether that direction pair is protected for every disc (of that color), you could reuse that value after determining it for only one.
To summarize, a disc is only stable if for every pair of directions, at least one of the directions in the pair is able to reach the border (and thus an opponent's disc can't "get behind" it) or it is already between two opposing color discs. Then to get all the stable discs, first determine if any of the discs are in the corners. If there are, then recursively check all 4 direction pairs of that disc, updating directional pairs for discs that are adjacent to it, making sure to reuse protected values for discs when applicable. Then at the end, for every disc whose 4 directional pairs are protected, mark that disc as stable.
Pseudocode to calculate this would look like the following:
calculate_protection(board, discs, index):
for each pair of directions that is marked as None:
calculate what squares it passes through for that pair of directions
i.e. either a border, blank square, or disc of opposing color
(Take note of what it passes through)
if for both directions in the pair at least one reaches a border
mark that direction pair as protected
else if both directions in the pair hits an opposing color disc
mark that direction pair as protected
else
mark that direction pair as not protected
for every disc that it passed through for that pair of directions (including an opposing color disc if it reached it):
if that disc is the same color:
mark that disc's direction pair as the same value for this one
call calculate_protection for that disc and update discs
return discs
calculate_stable_discs(board, color):
create a dictionary of discs where the key is the index of the disc, and it has a dictionary of direction pairs and their values (initially set as None)
if none of the corners have a disc:
return None
call calculate_protection on the first index that has a token
for every disc in the dictionary keys:
if all the numbers in the direction pairs are 1:
increment number of stable discs by 1
return number of stable discs
Note that to return the number of semi-stable and unstable discs as well, you would have to update what calculate_stable_discs
checks for in the dictionary, as well as what calculate_protection
marks directional pairs as, however the overall algorithm would remain the same.