8.8 Othello is played as follows: Each Othello piece is white on one side and black on the other. When a piece is surrounded by its opponents on both the left and right sides, or both the top and bottom, it is said to be captured and its color is flipped. On your turn, you must capture at least one of your opponent's pieces. The game ends when either user has no more valid moves. The win is assigned to the person with the most pieces. Implement the object-oriented design for Othello.
這道題是經典的黑白棋遊戲,我最早接觸到這個遊戲是在文曲星上,當年文曲星很火的時候,上面的各種遊戲我都愛不釋手啊,什麼英雄壇說,華容道,漢諾塔啊,黑白棋啊都是我常玩的遊戲,尤其這道黑白棋,總是玩不過困難模式的電腦,後來想想玩不過也應該,電腦應該可以把所有可以走的步驟都計算一遍,每次都選擇最優的解,下不贏電腦也很正常嘛。今天才算深入瞭解這個遊戲的設計原理啊,可參見下面程式碼:
enum Direction { Left, Right, Up, Down }; enum Color { White, Black }; class Piece { public: Piece(Color c): _color(c) {} void flip() { if (_color == Color::Black) _color = Color::White; else _color = Color::Black; } Color getColor() { return _color; } private: Color _color; }; class Location { public: Location(int r, int c): _row(r), _col(c) {} bool isSameAs(int r, int c) { return _row == r && _col == c; } int getRow() { return _row; } int getCol() { return _col; } private: int _row; int _col; }; class Board { public: Board(int rows, int cols) { _board.resize(rows, vector<Piece*>(cols)); } void initialize() { int midRow = _board.size() / 2; int midCol = _board[midRow].size() / 2; _board[midRow][midCol] = new Piece(Color::White); _board[midRow + 1][midCol] = new Piece(Color::Black); _board[midRow + 1][midCol + 1] = new Piece(Color::White); _board[midRow][midCol + 1] = new Piece(Color::Black); _blackCnt = 2; _whiteCnt = 2; } bool placeColor(int row, int col, Color color) { if (_board[row][col] != nullptr) { return false; } vector<int> res(4, 0); res[0] = flipSection(row - 1, col, color, Direction::Up); res[1] = flipSection(row + 1, col, color, Direction::Down); res[2] = flipSection(row, col + 1, color, Direction::Right); res[3] = flipSection(row, col - 1, color, Direction::Left); int flipped = 0; for (auto a : res) { if (a > 0) flipped += a; } if (flipped < 0) return false; _board[row][col] = new Piece(color); updateScore(color, flipped + 1); return true; } int getScoreForColor(Color c) { if (c == Color::Black) return _blackCnt; else return _whiteCnt; } void updateScore(Color newColor, int newPieces) { if (newColor == Color::Black) { _whiteCnt -= newPieces - 1; _blackCnt += newPieces; } else { _blackCnt -= newPieces - 1; _whiteCnt += newPieces; } } void printBoard() { for (int r = 0; r < _board.size(); ++r) { for (int c = 0; c < _board[r].size(); ++c) { if (_board[r][c] == nullptr) { cout << "_"; } else if (_board[r][c]->getColor() == Color::White) { cout << "W"; } else { cout << "B"; } } cout << endl; } } private: int _blackCnt = 0; int _whiteCnt = 0; vector<vector<Piece*> > _board; int flipSection(int row, int col, Color color, Direction d) { int r = 0, c = 0; switch (d) { case Direction::Up: r = -1; break; case Direction::Down: r = 1; break; case Direction::Left: c = -1; break; case Direction::Right: c = 1; break; } if (row < 0 || row >= _board.size() || col < 0 || col >= _board[row].size() || _board[row][col] == nullptr) { return -1; } if (_board[row][col]->getColor() == color) { return 0; } int flipped = flipSection(row + r, col + c, color, d); if (flipped < 0) return -1; _board[row][col]->flip(); return flipped + 1; } }; class Player { public: Player(Color c): _color(c) {} int getScore() { } // ... bool playPiece(int r, int c) { return Game::getInstance()->getBoard()->placeColor(r, c, _color); } private: Color _color; }; class Game { public: static Game* getInstance() { if (_instance == nullptr) { _instance = new Game(); } return _instance; } Board* getBoard() { return _board; } private: vector<Player*> _players; static Game *_instance; Board *_board; const int _ROWS = 10; const int _COLUMNS = 10; Game() { _board = new Board(_ROWS, _COLUMNS); _players.resize(2, nullptr); _players[0] = new Player(Color::Black); _players[1] = new Player(Color::White); } };