Duo Wiki

A crazy eight card game


Filed in: Blueprints.ConfigurableRules · Modified on : Mon, 08 Jun 09

Title: Design proposal for rules to be user-configurable
Version: 2008-06-08
Prerequisites: -
Status: Implemented
Maintainer: seventh
Contributors: d_rol, seventh
Categories: game protocol


Aim of this blueprint is to define a design so that:

  • Active rules are user-configurable (among a predefined set)
  • AI writing does not become a nightmare considering rules'variety

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

if ruleA:
->if ruleB:
->elsif not ruleC:

Here's the proposal:

  • When a card is stacked on the heap, Referee, as he informs all players with a HeapMessage, also informs them of valid moves, and their consequences.
  • AI then analyzes what it can play, and if it wants to play, do so.

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:

  • choose one card (not pick) in an opponent game and swap it with one of yours.
  • swap your game with some opponent's one
  • play over again (not really a penalty in fact)
  • force some opponent to pick one card in your game
  • interrupt normal cycle between players and take your turn in priority
  • cancel a card picking penalty, and choose new colour
  • play all cards of the same colour if it contains a specific value (e.g. '0B' allows to play all your blue cards in a row)

Benefits and drawbacks


  • AI strategy becomes very clear, and independent of the mechanics of the game.
  • New rules can be added, AI won't have to be updated.
  • One implementation of the TurnRule could be to emit the message only when players are authorized to play (whenever or only at their own turn)


  • AI cannot make long-view predictions as it does not really know which rules are active. But writing AI with such capacity is always possible, even if complicated (not more than with current implementation)
  • AI variety is then very restricted


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.

Protocol Level

PlayMessage, PassMessage and 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 Side

The referee module now provides a hierarchy of possible actions. Base action types are CardAction, DrawAction and PassAction. 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:

  • It computes the effect of the action using the ruleset.
  • It generates a new set of actions for all the players.
  • It sends to the players the results of the commited action and then their new hand and set of possible actions.

Client Side

The ui.tk and 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.

Current Limitations

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.

Powered by PmWiki