In order to write a new front-end for Bluff, to extend an existing one, or to add a new AI engine, some guidelines should be followed.
Bluff represents players, either human or computer-controlled, via descendants
of the abstract base class Player. A concrete Player must
implement several operations described below; each method takes a
GameView as parameter, and is expected to interact with the game
only via the GameView's public interface.
In a multiplayer game, Player objects must not block the program flow.
This means that methods must either take a decision immediately, or cache the
GameView and use it at a later time, when the decision has finally
been taken.
The Player interface consists of the following methods.
void start(GameView& view): notify the player that a new game is
      about to start. It is possible to cache view for future use.
void reroll(GameView& view): ask the player to decide which dice
      (if any) to reroll. Either instantly or at a later time,
      view.reroll() should be called to inform the game of the decision.
void cover(GameView& view, unsigned int n): ask the player to
      choose n dice to be hidden from other players. Either instantly
      or afterwards, use view.cover() to commit the list of covered
      dice.
void bid(GameView& view): ask the player's bid, which should be
      delivered via view.bid().
void trust(GameView& view): ask the player to loop over the other
      players, starting from number 1 and proceeding in order up to player
      number view.numPlayers() - 1. Each player's bid should be
      displayed, and a decision to trust or call a bluff taken via
      view.trust().
void wait(GameView& view): player should wait till the others
      have completed their turn.
void endTurn(GameView& view): display the outcome of the turn
      that has just been completed.
void endGame(GameView& view): the game has ended, view is
      about to become invalid and should not be referenced any longer once
      endGame() returns.
The GameView can be used to retrieve any kind of information about the
game status, provided it is available to the current player. So, a player
can inquire about his own dice in the current or previous hands, or about
who trusted whom in a previous hand, but not about some other player's
covered dice.
The GameView is also used to tell the game about the player's decisions,
via the methods listed above: reroll(), cover(), bid() and
trust(). All four methods return true on success, and false if the game
rules are being violated (say, someone tries to play out of turn).
If the new type of Player is controlled by the computer, it should be
registered with the global AIFactory. This does not require any
modification to existing code: it is sufficient to add a registration line
to the AI module, and link it to the game.
Supposing the new AI Player class is called BogoPlayer,
this snippet of code will do the trick:
  #include "AIFactory.hh"
  static AIFactory::type_declaration<BogoPlayer> bogus
  ("bogo",        // Unique identifier for this AI type
   "a short description (about 50 characters or less)",
   "Here should go a more complete description of the AI type.\n"
   "It can span multiple \\n-terminated lines.\n"
  );
New AI modules should generally be placed in the ai/ directory; the
existing Makefile should handle them appropriately. Reusable AI tools
should instead go in tools/.
When writing a new frontend, the game loop should work along these lines:
Game, myGame
myGame.start()
myGame.status() != Game::END_GAME,
GameView
      objects;
myGame.update(): if all the players have completed a phase
      of the game, the game will advance to the next phase and players will
      be prompted.
Player objects should remain alive at least as long
      as the old Game is available.
The game advances to the next phase only during update(), and not
immediately after the last player makes the expected move, in order to spare
the Player coder some consistency checks. If the game were updated
instantly, a Player's GameView could be invalidated within a
call to trust(), because the game reached its conclusion. With a
separate update() phase, view is guaranteed to remain valid
whatever the Player does.
Go to the first, previous, next, last section, table of contents.