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.