#pragma once #include #include #include #include #include #include #include typedef unsigned int idx_t; /* * Potential values for the pieces on the board. */ enum FieldType { EMPTY, PLAYER_1, PLAYER_2, OUT_OF_BOUNDS }; /* * direction flags are used by the algorithms below to validate * and perform moves. */ enum direction { LEFT, RIGHT, UP, DOWN, UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT }; class OthelloBoard { protected: idx_t _rows; // no. of rows idx_t _cols; // no. of columns bool _last_player_skipped; // remember if last player skipped bool _both_skipped; // termination condition FieldType *_field; // array storing the types of stones set on the board FieldType _player; // whose turn is it? /* make object non-assignable */ OthelloBoard& operator=(OthelloBoard&) { return *this; } private: /* * Depending on a given direction, we need to setup up to four * variables in different types of algorithms. This convenience * function does so. */ void setup_directions(unsigned &row_idx, unsigned &col_idx, int &inc_row, int &inc_col, direction const dir) const; /* * Check if a position is reachable from a given direction. * * Reachability means, that from the target position given by * (row, col) there are only non-empty stones of type != _player until * we find a stone of type _player. */ bool position_reachable(unsigned row, unsigned col, direction const dir) const; /* * Really make a move */ void make_move(unsigned row, unsigned col, direction dir); /* * Validate correctness of a move. * * \param row, col coordinates to move to * * \return true if move is valid */ bool validate(unsigned row, unsigned col, bool silent=false) const; public: /* * Get the number of rows. */ unsigned rows() const { return _rows; } /* * Get the number of columns */ unsigned columns() const { return _cols; } /* * Construct a default OthelloBoard */ OthelloBoard(unsigned r = 8, unsigned c = 8) : _rows(r), _cols(c), _last_player_skipped(false), _both_skipped(false), _field(0), _player(PLAYER_1) { _field = new FieldType[rows()*columns()]; for (unsigned idx = 0; idx < rows() * columns(); ++idx) _field[idx] = EMPTY; set(rows()/2, columns()/2, PLAYER_1); set(rows()/2+1, columns()/2+1, PLAYER_1); set(rows()/2, columns()/2 + 1, PLAYER_2); set(rows()/2+1, columns()/2, PLAYER_2); } /* * Copy constructor. * * XXX: If you plan to use it, go and implement it! */ OthelloBoard(const OthelloBoard& copy); /* Destructor */ virtual ~OthelloBoard() { delete [] _field; } /* Get current player type */ FieldType player() const { return _player; } /* Set current player */ void player(int no) { switch(no) { case 0: _player = PLAYER_1; break; case 1: _player = PLAYER_2; break; default: assert(false); break; } } /* * Dump the current board state to a file */ bool dump_to_fd(int fd, bool fancy = false) const { FILE *file = fdopen(dup(fd), "w"); if (!file) return false; // print head line if (fancy) ::fprintf(file, " %c ", type_to_str(_player)); else ::fprintf(file, "%c", type_to_str(_player)); if (fancy) { for (unsigned c = 0; c < columns(); ++c) ::fprintf(file, "%d ", c+1); ::fprintf(file,"\n"); } for (unsigned r = 0; r < rows(); ++r) { if (fancy) ::fprintf(file, "%2d ", r+1); for (unsigned c = 0; c < columns(); ++c) { if (fancy) ::fprintf(file, "%s ", type_to_str_fancy(get(r+1, c+1))); else { ::fprintf(file, "%c", type_to_str(get(r+1,c+1))); } } if (fancy) ::fprintf(file,"\n"); } fclose(file); return true; } /* Special case: dump to stdout */ bool dump_to_stdio() const { return dump_to_fd(STDOUT_FILENO, true); } /* * Get element at location. * * Location coordinates are * row with 0 < row <= rows() * col with 0 < col <= columns() * * Otherwise, returns OUT_OF_BOUNDS field type. */ FieldType get(unsigned row, unsigned col) const { if ((row <= 0) || (col <= 0) || (row > rows()) || (col > columns())) return OUT_OF_BOUNDS; return _field[(row-1)*columns() + col - 1]; } /* * Set element at certain location. * * Location coordinates are * row with 0 < row <= rows() * col with 0 < col <= columns() */ void set(unsigned row, unsigned col, FieldType type) { assert(row > 0); assert(row <= rows()); assert(col > 0); assert(col <= columns()); _field[(row-1)*columns() + col - 1] = type; } /* * Perform a move. * * First, validates the move. Then performs all necessary * field type conversions. */ bool move(unsigned row, unsigned col); /* * Count the number of fields that contain a stone * of the given type. */ unsigned count_of_type(FieldType t) const { unsigned res = 0; for (unsigned i = 0; i < rows() * columns(); ++i) if (_field[i] == t) res += 1; return res; } void skipped() { if (_last_player_skipped) _both_skipped = true; else _last_player_skipped = true; } /* * Determine whether the game is done. */ bool finished() const { unsigned c1 = count_of_type(PLAYER_1); unsigned c2 = count_of_type(PLAYER_2); return ( _both_skipped || (c1 == 0) || (c2 == 0) || (c1 + c2 >= 64) ); } /* * Transform field type into fancy print version (for stdio). */ char const *type_to_str_fancy(FieldType t) const { switch (t) { case EMPTY: return "\033[34;1m.\033[0m"; case PLAYER_1: return "\033[31mO\033[0m"; case PLAYER_2: return "\033[33mX\033[0m"; case OUT_OF_BOUNDS: return "/"; default: __builtin_unreachable(); } } /* * Transform field type into print version. */ char type_to_str(FieldType t) const { switch (t) { case EMPTY: return '.'; case PLAYER_1: return 'O'; case PLAYER_2: return 'X'; case OUT_OF_BOUNDS: return '/'; default: __builtin_unreachable(); } } /* * Check, whether the given player can make any move at the moment. */ bool can_move() const { for (unsigned r = 1; r <= rows(); ++r) for (unsigned c = 1; c <= columns(); ++c) if (validate(r, c, true)) return true; return false; } /* * Invalidate all stones belonging to a player. * * The engine uses this as a penalty for making more than 3 * illegal moves in a row. */ void invalidate_stones(FieldType t) { for (unsigned idx = 0; idx < rows() * columns(); ++idx) if (_field[idx] == t) _field[idx] = EMPTY; } }; struct OthelloMove { idx_t row; idx_t col; OthelloMove(idx_t r=0, idx_t c=0) : row(r), col(c) { } }; /*************************************** * MCP adaptor definitions & functions * ***************************************/ typedef OthelloBoard game_state; typedef OthelloMove game_move; /** * Game state is serialized into a human-readable string. */ bool serialize_state(int fd, const game_state *state); /** * Game state is parsed from a string written by serialize_state. */ bool deserialize_state(int fd, game_state *state); bool serialize_move (int fd, const game_move *move); bool deserialize_move(int fd, game_move *move); /** * Generate the initial board. */ void initialize_state(game_state *state, char const *init); /** * Returns true, if this is a final game state. */ bool is_final_state(game_state const *state); /** * Tries to apply a move to the given state. Returns false, if the * move was invalid. */ bool apply_move(game_state *state, const game_move *move);