Filed in: Blueprints.ConfigurableRules · Modified on : Mon, 08 Jun 09
Aim of this blueprint is to define a design so that:
Some recommendations can be found at the end of the document to enhance rule system robustness.
0.9 design starts to isolate game's rules, according to a Referee.Rule pattern. But isolation is not complete, and we can find remnants of current active rules elsewhere in the code (e.g. in AI.Camille), in a far-from-configurable way.
Taking as an example the AI.Camille AI, we can see that it is written in a way so that he never fails according to current ruleset. It always proposes to referee a move that is valid. In fact this is good news, we do not want smart AIs to try randomly some moves until one is accepted. The real issue in fact is the way it's implemented: Camille supposes which rules are active, which moves are authorized, and then defines a strategy above those hypotheses. Hypotheses are not highly configurable.
Furthermore, we do not want AI to be impossible to maintain, with such pattern like
Here's the proposal:
So the main difficulty is to find a design of penalties expression. For that we have to list down all kind of penalties that can occur. According to Wikipedia page about "crazy eight"-like games, non regular rules can consist in:
Another thing that sould not be forgotten while talking about rules is that their implementation, particularily the Referee.Rule.check method, shall not depend on which rules have previously fail.
This means that ruleset implementation shall really be considered as a set and not a list. Said differently, if a card play is authorized by referee, there is only one rule of the ruleset for which Referee.Rule.check is True.
Such a ruleset is very difficult to write down indeed. Maybe we can loosen this restriction a little, and impose it on groups of rule instead of stand-alone rules. For example, all rules of level 2 are implemented independently, knowing nothing about upper levels, and can consider that all level-1 rules have failed.
To remove any rule knowledge from the AI, and as far as possible from the UI too, the game protocol is updated to convey no more known game orders like play, draw or pass, but an action. Possible actions are distributed by the referee to each player using one ruleset. This ruleset also provides the effects that can be attached to each action and that are used by the referee to let the game run.
DrawMessage are removed from the protocol. They are replaced by a unique
ActionMessage which can be used by players to send an action to the referee.
On the other way, to allow the referee to carry possible actions to every player, the
HandMessage is updated to convey not only the new hand of the player, but also a set of his possible moves.
referee module now provides a hierarchy of possible actions. Base action types are
CardAction must be inherited in a ruleset by the different kinds of card moves so as to allow a AI to ditinguish them. Future actions can be added to this model without any harm.
Whenever an action is undertaken by a player, the referee proceeds to the following steps:
ai.camille modules are updated to cope with the new protocol. The Camille AI did not change its way of playing. But instead of considering its hand and its own knowledge of the game, it uses the given actions. A new but unfinished
ai.dumb is added to provide the dumbest possible AI, which can become a base to write new ones.
The UI ignores the actions for the moment. It always builds the action matching the player event, like a click on a card or on the Pass button. It is thus still very tighed to the possible actions offered by the ruleset.
Tha Camille AI still prefers to play a card action, which constitues a remanent knowledge of the game. Ideally, the AI should compute its move using heuristics independantly of the ruleset.