1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
/*
* Atom-4 game engine
* Header file
* ---------------------------------------------------------------------------
* $Id: game.h,v 1.20 2003/04/15 00:24:21 hsteoh Exp hsteoh $
*
* DESIGN
*
* This game engine is supposed to be UI-driven; so it is basically designed
* for an event-driven interface. The UI, whether the testing ncurses-based
* UI or the anticipated X11 UI, will be sending events to class atom4 and
* checking its state to know what to do next, etc.. Basically, this class
* implements the game rules.
*/
#ifndef GAME_H
#define GAME_H
#include <list.h> // MUST be prog/lib version!
#include "board4.h"
#include "color4.h"
#include "triboard.h"
#define STALEMATE 3 // returned by atom4::winner()
#define NUM_COLORS 8
#define NUM_PLAYERS 2
#define WIN_ROW 4 // number of pieces in a row to win
// Internal stuff
#define COLORSEQ_LEN 6
// Callback class for handling allowing async notification of game state
// changes
class atom4; // forward decl
class atom4notifier {
public:
// Notify of all game state changes
virtual void notify_move(atom4 *src, int plr, elist<boardchange> &chg)=0;
virtual void notify_clear(atom4 *src)=0;
};
// Abstract base class
class atom4 {
elist<atom4notifier*> notifylist;
protected:
// Send notification to all registered notifiers. Derived classes must
// call this every time a game state change is detected.
virtual void notify_move(int player, elist<boardchange> &changes);
virtual void notify_clear();
public:
enum mode_t {
DUAL, // both players connected to interface
PEER, // one player connected to interface
WATCH // not actively participating
};
virtual ~atom4();
virtual void reset()=0; // restart game
virtual mode_t game_mode()=0; // return current mode
virtual int local_playernum()=0; // assigned player number if in PEER
// mode; current_player() if DUAL mode,
// -1 if WATCH mode.
virtual int is_local_turn()=0;
void add_notifier(atom4notifier *callback); // [R]
void remove_notifier(atom4notifier *callback); // [R]
virtual int current_player()=0;
virtual celltype current_tile()=0;
// Returns false if move is illegal (not player's turn, bad position, game
// already over, etc.), true otherwise.
virtual int move(int player, int x, int y)=0;
// Checks if move is legal (note: this does NOT guarantee a subsequent
// call to move() will be successful, since this only checks the board
// not the current state of the game)
virtual int check_legal(int x, int y)=0;
virtual int round_over()=0;
virtual int winner()=0;
// Multi-round support
virtual int current_round()=0;
virtual int newround()=0;
virtual int score(int player)=0;
// FIXME: what we REALLY want is to have a way to register an update
// callback with class triboard, that will get called every time a cell
// changes. (This is the REAL answer to the whole mess in the X11 refresh()
// code right now...)
virtual board4 *get_board()=0;
virtual unsigned int board_width()=0;
virtual unsigned int board_height()=0;
};
class atom4local : public atom4 {
board4 *board; // [O] game board
int win_player; // player who won the game; if not -1,
// game is over.
int cur_player; // player to make the next move
int cur_color; // which color is being played
static celltype colorseq[COLORSEQ_LEN];
// Multi-round stuff
int cur_round; // current round
int start_player; // player to move first
int scores[NUM_PLAYERS];
// Internal convenience stuff
inline char plchar(int player) { return 'a' + player-1; }
inline int next_player(int player) { return player%NUM_PLAYERS + 1; }
inline int valid_player(int pl) { return pl>0 && pl<=NUM_PLAYERS; }
inline int next_color(int color) { return (color+1)%COLORSEQ_LEN; }
int splash(int bx, int by, color4 actor, elist<boardchange> &changes);
void reset_scores();
void reset_board();
public:
atom4local(unsigned int width, unsigned int height);
virtual ~atom4local();
virtual void reset(); // restart game
virtual mode_t game_mode(); // return current mode
virtual int local_playernum();
virtual int is_local_turn();
// For UI to know who's supposed to move next. UI should not need to keep
// track of this independently anyway.
int current_player();
// Current marble (which color) being played
celltype current_tile();
// Returns false if move is illegal (not player's turn, bad position, game
// already over, etc.), true otherwise.
int move(int player, int x, int y);
// Checks if move is legal (note: this does NOT guarantee a subsequent
// call to move() will be successful, since this only checks the board
// not the current state of the game)
int check_legal(int x, int y);
int round_over();
int winner();
// Multi-round support
int current_round();
virtual int newround();
int score(int player);
// FIXME: what we REALLY want is to have a way to register an update
// callback with class triboard, that will get called every time a cell
// changes. (This is the REAL answer to the whole mess in the X11 refresh()
// code right now...)
board4 *get_board();
unsigned int board_width();
unsigned int board_height();
};
#endif // GAME_H
|