Both the player and the AI have issues with checking for prohibited civic combos.
The idea for a solution is as follows:
-Remove civics from the cache in CvPlayer::isCivicBlocked(). This will allow complete freedom to "simulate" all combos and check if they are valid while keeping the cache to tell if civics are blocked by non-civic CivEffects.
-make a new C++ class.
This class should contain a (const?) pointer to the player in question and an array of length num civic options.
This class can then change the civics chosen and simulate all combos without changing the player. If a change is not confirmed, this class can just be discarded and nothing happens.
-civic screen (python)
The new class should be python exposed and python should not check prohibited settings itself. Instead python should rely on data from the class and ask the class if civics are clickable.
-AI decision:
The AI code is not well designed for prohibited civics. It should be redesigned to do the following:
Calculate the AI value of each civic and cache those values. (remember AI value depends on game data like number of towns and stuff, not xml value)
Try to set the civic with the highest value in each category and see if that works.
If the highest value approach fails due to prohibited combos, try selecting the highest in each category and then "the best" allowed in each of the others. This gives one civic set for each category and the AI should pick the one with the highest combined value.
Caching the value of each civic seems important because the value of each appears to be needed multiple times.
Consider using a 2D cache as in CivicID, CivicOptionID. That or use two cache arrays, one for values and one for civic option. Looking up CivicInfo to get option over and over could also be a slowdown.