diff --git a/.cproject b/.cproject index e7c89fb..e0e395a 100644 --- a/.cproject +++ b/.cproject @@ -1,44 +1,42 @@ - - + + - + - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - @@ -46,11 +44,11 @@ - - + + - + @@ -59,55 +57,77 @@ - - - - - - - - + + + + + + + + + + + + - - - - - - - - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index d22c8b7..0a0e2a6 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -1,22 +1,22 @@ - + - + - + - + diff --git a/Board.h b/Board.h index c86c77e..3ba39f8 100644 --- a/Board.h +++ b/Board.h @@ -2,214 +2,346 @@ * BaseBoard.h * * Created on: 21/02/2021 - * Author: dongmo + * Author: Dongmo */ #ifndef BOARD_H_ #define BOARD_H_ +#include + class Board { -private: - int boardSize; - int turn; - int **grid; -public: - Board(int bs) - { - boardSize = bs; - grid = new int*[boardSize]; - for (int i = 0; i < boardSize; i++) - grid[i] = new int[boardSize]; - - for (int i = 0; i < boardSize; i++) - for (int j = 0; j < boardSize; j++) - { - grid[i][j] = 0; - } - turn = 1; - } - - virtual ~Board() - { - - for (int i = 0; i < boardSize; i++) - delete[] grid[i]; - - delete[] grid; - } - - Board(Board &cboard) - { - boardSize = cboard.getBoardSize(); - - grid = new int*[boardSize]; - for (int i = 0; i < boardSize; i++) - grid[i] = new int[boardSize]; - - for (int i = 0; i < boardSize; i++) - for (int j = 0; j < boardSize; j++) - grid[i][j] = 0; - - for (int i = 0; i < boardSize; i++) - for (int j = 0; j < boardSize; j++) - { - grid[i][j] = cboard.getGrid(i, j); - } - - turn = cboard.getTurn(); - } - - int getBoardSize() - { - return boardSize; - } - - int getGrid(int x, int y) - { - return grid[x][y]; - } - - int getTurn() - { - return turn; - } - - bool validInput(int, int); - - bool addMove(int playerType, int x, int y); - - int checkWinningStatus(int playerType) - { - //To be implemented - return 0; - } - - void printBoard(); + private: + int boardSize; + int turn; + int **grid; + vector spots; + public: + Board(int bs) + { + boardSize = bs; + grid = new int*[boardSize]; + for (int i = 0; i < boardSize; i++) + grid[i] = new int[boardSize]; + + for (int i = 0; i < boardSize; i++) + for (int j = 0; j < boardSize; j++) + { + grid[i][j] = 0; + } + turn = 1; + } + + virtual ~Board() + { + + for (int i = 0; i < boardSize; i++) + delete[] grid[i]; + + delete[] grid; + } + + Board(Board &cboard) + { + boardSize = cboard.getBoardSize(); + + grid = new int*[boardSize]; + for (int i = 0; i < boardSize; i++) + grid[i] = new int[boardSize]; + + for (int i = 0; i < boardSize; i++) + for (int j = 0; j < boardSize; j++) + grid[i][j] = 0; + + for (int i = 0; i < boardSize; i++) + for (int j = 0; j < boardSize; j++) + { + grid[i][j] = cboard.getGrid(i, j); + } + + turn = cboard.getTurn(); + } + + int getBoardSize() + { + return boardSize; + } + + int getGrid(int x, int y) + { + return grid[x][y]; + } + + int getTurn() + { + return turn; + } + + bool validInput(int, int); + + bool addMove(int playerIndex, int x, int y); + + int checkWinningStatus(int playerIndex); + + void printBoard(); + + bool isBoardFull(); + bool isFullThisTurn(); + + void allSpots(); + void printSpots(); + void removeSpot(int x, int y); + vector getSpots() + { + return spots; + } }; +void Board::allSpots() +{ + for(int x = 0; x < boardSize; x++) + for(int y = 0; y < boardSize; y++) + { + int value = x*boardSize+y; + //cout << x << " " << boardSize << " " << y << endl; + + spots.push_back(value); + + //int i = value/boardSize+1; + //int j = value%boardSize+1; + //cout << i << j << endl; + } +} + +void Board::printSpots() +{ + for(int i = 0; i < spots.size(); i++) + cout << "(" << (spots[i]/boardSize)+1 << "," << (spots[i]%boardSize)+1 << ")" << endl; +} + +void Board::removeSpot(int x, int y) +{ + int value = x*boardSize+y; + + for(int i = 0; i < spots.size(); i++) + { + if(spots[i] == value) + { + spots.erase(spots.begin()+i); + break; + } + } +} + bool Board::validInput(int x, int y) { - if (x < 0 || y < 0 || x >= boardSize || y >= boardSize) - { - cout << "Move (" << x + 1 << ", " << y + 1 << ") out of range!" << endl; - return false; - } - - if (grid[x][y] != 0) - { - cout << "Invalid move. The cell has been occupied." << endl; - return false; - } - - return true; + if (x < 0 || y < 0 || x >= boardSize || y >= boardSize) + { + cout << "Move (" << x + 1 << ", " << y + 1 << ") out of range!" << endl; + return false; + } + + if (grid[x][y] != 0) + { + cout << "Invalid move. The cell has been occupied." << endl; + return false; + } + + return true; } -bool Board::addMove(int playerType, int x, int y) +bool Board::addMove(int playerIndex, int x, int y) { + if (playerIndex != turn) + { + cout << "It is not the player's turn!" << endl; + return false; + } + + if (grid[x][y] != 0) + { + cout << "Invalid move. The cell has been occupied." << endl; + return false; + } + + grid[x][y] = playerIndex; + removeSpot(x,y); + + turn = -1 * turn; + return true; +} - if (playerType != turn) - { - cout << "It is not the player's turn!" << endl; - return false; - } +void Board::printBoard() +{ + //Top X numbers + cout << " "; + for (int j = 0; j < boardSize; j++) + { + if (j < 9) cout << "_" << j + 1 << "_."; + else cout << "_" << j + 1 << "."; + } + cout << endl; + + //RHS Y numbers & grid + for (int i = 0; i < boardSize; i++) + { + for (int k = 0; k < i; k++) + cout << " "; + + if (i < 9) cout << " " << i + 1 << " "; + else cout << i + 1 << " "; + + for (int j = 0; j < boardSize; j++) + { + if (grid[i][j] == 0) + { + if (j == 0) + { + cout << "\\___\\"; + } + else + { + cout << "___\\"; + } + } + else if (grid[i][j] == 1) + { + if (j == 0) + { + cout << "\\_X_\\"; + } + else + { + cout << "_X_\\"; + } + } + else + { + if (j == 0) + { + cout << "\\_O_\\"; + } + else + { + cout << "_O_\\"; + } + } + } + + cout << " " << i + 1; + if (i == boardSize / 2 || i == boardSize / 2 + 0.5) cout << " Y Goal"; + cout << endl; + } + + for (int s = 0; s < boardSize; s++) + cout << " "; + + cout << " "; + for (int e = 0; e < boardSize; e++) + { + if (e < 9) cout << " " << e + 1 << " "; + else cout << " " << e + 1 << " "; + } + cout << endl; + + for (int g = 0; g < boardSize * 3; g++) + cout << " "; + cout << " X Goal" << endl; +} - if (grid[x][y] != 0) - { - cout << "Invalid move. The cell has been occupied." << endl; - return false; - } +bool Board::isBoardFull() +{ + if(spots.size() > 0) + return false; - grid[x][y] = playerType; + cout << "Woops! The board is full and no one has won, looks like it's game over." << endl; + return true; +} - turn = -1 * turn; - return true; +bool Board::isFullThisTurn() +{ + int count = 0; + for(int i = 0; i < boardSize; i++) + { + for(int j = 0; j < boardSize; j++) + { + if(grid[i][j] == 0) + ++count; + } + } + + if(count==1) + { + cout << "Yikes, looks like there's only one free spot. Better make this move count or its game over." << endl; + return true; + } + else + return false; } -void Board::printBoard() +int Board::checkWinningStatus(int playerIndex) { - //Top X numbers - cout << " "; - for (int j = 0; j < boardSize; j++) - { - if (j < 9) - cout << "_" << j + 1 << "_."; - else - cout << "_" << j + 1 << "."; - } - cout << endl; - - //RHS Y numbers & grid - for (int i = 0; i < boardSize; i++) - { - for (int k = 0; k < i; k++) - cout << " "; - - if (i < 9) - cout << " " << i + 1 << " "; - else - cout << i + 1 << " "; - - for (int j = 0; j < boardSize; j++) - { - if (grid[i][j] == 0) - { - if (j == 0) - { - cout << "\\___\\"; - } - else - { - cout << "___\\"; - } - } - else if (grid[i][j] == 1) - { - if (j == 0) - { - cout << "\\_X_\\"; - } - else - { - cout << "_X_\\"; - } - } - else - { - if (j == 0) - { - cout << "\\_O_\\"; - } - else - { - cout << "_O_\\"; - } - } - } - - cout << " " << i + 1; - if(i == boardSize/2 || i == boardSize/2+0.5) - cout << " Y Goal"; - cout << endl; - } - - - for(int s = 0; s < boardSize; s++) - cout << " "; - - cout << " "; - for(int e = 0; e < boardSize; e++) - { - if(e < 9) - cout << " " << e + 1 << " "; - else - cout << " " << e + 1 << " "; - } - cout << endl; - - for(int g = 0; g < boardSize*3; g++) - cout << " "; - cout << " X Goal" << endl; + //Check if a whole row is complete + for (int r=0; r + + + + + diff --git a/Hex.depend b/Hex.depend new file mode 100644 index 0000000..dac7bdb --- /dev/null +++ b/Hex.depend @@ -0,0 +1,24 @@ +# depslib dependency file v1.0 +1616572301 source:c:\users\ascle\desktop\uni\dsa\assignments\assignment 1 - hex game\dsa-hex-game\main.cpp + + + "Board.h" + "Player.h" + "HumanPlayer.h" + "HexGame.h" + "RandomPlayer.h" + +1616577291 c:\users\ascle\desktop\uni\dsa\assignments\assignment 1 - hex game\dsa-hex-game\board.h + + +1613904637 c:\users\ascle\desktop\uni\dsa\assignments\assignment 1 - hex game\dsa-hex-game\player.h + +1616376427 c:\users\ascle\desktop\uni\dsa\assignments\assignment 1 - hex game\dsa-hex-game\humanplayer.h + +1616577125 c:\users\ascle\desktop\uni\dsa\assignments\assignment 1 - hex game\dsa-hex-game\hexgame.h + +1616392894 c:\users\ascle\desktop\uni\dsa\assignments\assignment 1 - hex game\dsa-hex-game\randomplayer.h + + + + diff --git a/Hex.layout b/Hex.layout new file mode 100644 index 0000000..7dc8f04 --- /dev/null +++ b/Hex.layout @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HexGame.h b/HexGame.h index 59abb4d..db271fb 100644 --- a/HexGame.h +++ b/HexGame.h @@ -8,47 +8,56 @@ #ifndef HEXGAME_H_ #define HEXGAME_H_ -class HexGame { -private: - Board *board; - Player *player[2]; -public: - HexGame(Board *b, Player *p1, Player *p2) { - board = b; - player[0] = p1; - player[1] = p2; - } +class HexGame +{ + private: + Board *board; + Player *player[2]; + public: + bool canPlay = true; + + HexGame(Board *b, Player *p1, Player *p2) + { + board = b; + player[0] = p1; + player[1] = p2; + } - void play(); + void play(); }; -void HexGame::play() { +void HexGame::play() +{ int won = 0; - board->printBoard(); - - while (!won) { + board->printBoard(); //Print the game board to the screen + board->allSpots(); //Add all of the free coordinates to the spots vector + //Loop until someone has won or the board has been filled + while (!won && !board->isBoardFull()) + { int playerType = board->getTurn(); int playerIndex = (playerType == player[0]->getType()) ? 0 : 1; int x = -1; int y = -1; - if (!player[playerIndex]->getMove(board, x, y)) { - cout << "No available move" << endl; + if (!player[playerIndex]->getMove(board, x, y)) + { + cout << "ERROR: No available move" << endl; return; } + else + system("CLS"); cout << player[playerIndex]->getPlayerName() << " plays " << " (" - << x + 1 << ", " << y + 1 << "):" << endl; + << x + 1 << ", " << y + 1 << "):" << endl; if (!board->addMove(playerType, x, y)) return; board->printBoard(); won = board->checkWinningStatus(playerType); - if(won == playerType) - cout << player[playerIndex]->getPlayerName() << " player wins!" << endl; - + if(won == playerType) + cout << player[playerIndex]->getPlayerName() << " player wins!" << endl; } } diff --git a/HumanPlayer.h b/HumanPlayer.h index 24c1f14..526b95b 100644 --- a/HumanPlayer.h +++ b/HumanPlayer.h @@ -10,29 +10,41 @@ using namespace std; -class HumanPlayer: public Player { -public: - HumanPlayer(int t, string name = "Human") : - Player(t, name) { - } - bool getMove(Board*, int&, int&); +class HumanPlayer: public Player +{ + public: + HumanPlayer(int t, string name = "Human") : + Player(t, name) + { + } + bool getMove(Board*, int&, int&); }; -bool HumanPlayer::getMove(Board *board, int &x, int &y) { +bool HumanPlayer::getMove(Board *board, int &x, int &y) +{ bool flag = false; + bool lastTurn = false; int bs = board->getBoardSize(); - while (!flag) { + lastTurn = board->isFullThisTurn(); + + do + { cout << "Input row and column (x, y) between 1 to " << bs << " for " - << name << " player:" << endl; + << name << ":" << endl; + board->printSpots(); int row, col; - cin >> col >> row; + cin >> row >> col; x = row - 1; y = col - 1; - flag = board->validInput(x, y); - if (flag == false) + flag = board->validInput(x, y)?false:true; //Flag invalid inout if the board is full or if it isnt a valid input (ie. used spot) + if (flag == true) cout << "Invalid input! Please input again." << endl; } + while (flag); + + //board->emptySpots -= 1; + //cout << board->emptySpots; return true; } diff --git a/Main.cpp b/Main.cpp index 3910216..9478f85 100644 --- a/Main.cpp +++ b/Main.cpp @@ -14,18 +14,45 @@ using namespace std; #include "Player.h" #include "HumanPlayer.h" #include "HexGame.h" +#include "RandomPlayer.h" -int main() { +int main() +{ int boardSize = 5; cout <<"Input the size of board: (Minimum is 3, but boards from 5-12 are best)" << endl; - cin >> boardSize; + cin >> boardSize; + system("CLS"); if (boardSize < 3) boardSize = 3; Board *board = new Board(boardSize); + int p2Type = 1; + cout <<"Who do you want to verse? (0 = another player, 1 = Bad AI, 2 = Better AI)" << endl; + cin >> p2Type; + system("CLS"); + Player *p1 = new HumanPlayer(1, "Crosses (X)"); - Player *p2 = new HumanPlayer(-1, "Naughts (O)"); + Player *p2; + + switch(p2Type) + { + case 0: + { + p2 = new HumanPlayer(-1, "Naughts (O)"); + break; + } + case 1: + { + p2 = new RandomPlayer(-1, "Naughts (O)"); + break; + } + default: + { + p2 = new RandomPlayer(-1, "Naughts (O)"); + break; + } + } HexGame game(board, p1, p2); game.play(); diff --git a/RandomPlayer.h b/RandomPlayer.h new file mode 100644 index 0000000..8d14d64 --- /dev/null +++ b/RandomPlayer.h @@ -0,0 +1,45 @@ +/* + * RandomPlayer.h + * + * Created on: 22/03/2021 + * Author: Broderick Westrope + */ + +#ifndef RANDOMPLAYER_H_ +#define RANDOMPLAYER_H_ + +#include +#include +#include + +using namespace std; + +class RandomPlayer: public Player +{ + public: + RandomPlayer(int t, string name = "Random") : + Player(t, name) + { + } + bool getMove(Board*, int&, int&); +}; + +bool RandomPlayer::getMove(Board *board, int &x, int &y) +{ + if(board->isBoardFull()) + { + cout << "ERROR: Random player can't move cause the board is full!" << endl; + return false; + } + + srand(time(NULL)); + vector spots = board->getSpots(); + int index = rand() % (spots.size()-1) + 0; + + x = spots[index]/board->getBoardSize(); + y = spots[index]%board->getBoardSize(); + + return true; +} + +#endif /* RANDOMPLAYER_H_ */