diff --git a/AIplayer.cpp b/AIplayer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de894d8d294f769aaec4eea89c9e1d1ebb351016 --- /dev/null +++ b/AIplayer.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include "AIplayer.h" +#include "Board.h" +#include "Cell.h" + +using namespace std; + +pair AIplayer::move1(displayBoard AImove) { + // declare variables + Cell check; + int x = 0, y = 0; + pair AIpair; + + + // loop until valid move is found + for (int row = 0; row < 8; ++row) { + for (int col = 0; col < 8; ++col) { + if (check.isLegalPlacementfor(row, col, AImove.board, 'O', 'X')) { + x = row; + y = col; + } + } + } + AIpair.first = x; + AIpair.second = y; + return AIpair; +} + + +pair AIplayer::move2(displayBoard AImove) { + // declare variables + Cell check; + pair AIpair; + int x = 0; + int y = 0; + + // chip gain + int chips = 0; + int temp = 0; + // check each position for valid move + for (int row = 0; row < 8; ++row) { + for (int col = 0; col < 8; ++col) { + if (check.isLegalPlacementfor(row, col, AImove.board, 'O', 'X')) { + AImove.upCheck(row, col, 'O', false); + temp = AImove.getDifference(); + AImove.downCheck(row, col, 'O', false); + temp += AImove.getDifference(); + AImove.leftCheck(row, col, 'O', false); + temp += AImove.getDifference(); + AImove.rightCheck(row, col, 'O', false); + temp += AImove.getDifference(); + AImove.uprightCheck(row, col,'O', false); + temp += AImove.getDifference(); + AImove.upleftCheck(row, col,'O', false); + temp += AImove.getDifference(); + AImove.downrightCheck(row, col,'O', false); + temp += AImove.getDifference(); + AImove.downleftCheck(row, col,'O', false); + temp += AImove.getDifference(); + if (temp > chips) { + chips = temp; + y = row; + x = col; + } + } + } + } + AIpair.first = x; + AIpair.second = y; + return AIpair; +} diff --git a/AIplayer.h b/AIplayer.h new file mode 100644 index 0000000000000000000000000000000000000000..3bf94aa517053b6377b884a61e7858d4e1df29e0 --- /dev/null +++ b/AIplayer.h @@ -0,0 +1,16 @@ +#include +#include +#include "Board.h" +#include "Cell.h" +using namespace std; + +class displayBoard; +class Cell; +class AIplayer { + public: + pair move1(displayBoard AImove); // easy move + pair move2(displayBoard AImove); // hard move mutator + private: // not used + + +}; diff --git a/Board.cpp b/Board.cpp new file mode 100644 index 0000000000000000000000000000000000000000..edfd1c9cd33c090de354418b0bd40e7287a9b926 --- /dev/null +++ b/Board.cpp @@ -0,0 +1,404 @@ +#include +#include +#include "Board.h" + +using namespace std; + +// Place starting pieces +void displayBoard::start() { + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { + board[i][j] = ' '; + } + } + // The rest of the board has random data in it possible including X and O + board[4-1][4-1] = {'X'}; + board[5-1][4-1] = {'O'}; + board[5-1][5-1] = {'X'}; + board[4-1][5-1] = {'O'}; +} + +// Place X's pieces +void displayBoard::playerMove1(int x, int y) { + board[x-1][y-1] = {'X'}; + +} + +// Place O's pieces +void displayBoard::playerMove2(int x, int y) { + board[x-1][y-1] = {'O'}; + +} + +// Prints the board +void displayBoard::printBoard() { + cout << " 1 2 3 4 5 6 7 8 " << endl; + cout << " +---+---+---+---+---+---+---+---+ "<< endl; + for (int j=0; j<8; j++) { + cout << j+1 << " |"; + + for (int i=0; i<8; i++) { + if (isalpha(board[i][j])) { + cout << " " << board[i][j] << " |"; + } else { + cout << board[i][j] << " |"; + } + } + cout << endl << " +---+---+---+---+---+---+---+---+ "<< endl; + } +} + + +void displayBoard::downCheck(int x, int y, char chip, bool change) { // function for checking and changing chips in a line going down + x -= 1; + y -= 1; + int firstY = y; + int secondY; + bool addChip = false; + this->difference = 0; + + for (int i = firstY + 1; i < 8; i++) { // loop that goes down from the origin and finds the first chip of the same character + if (board[x][i] == chip) { + secondY = i; + if (0 <= secondY < 8) { + addChip = true; + } + break; + } + } + + if (addChip == true) { + this->difference = (secondY - firstY) - 1; // the difference will be the amount of chips that are being flipped + + for (int i = firstY; i <= secondY; i++) { + if (board[x][i] == 'X' || board[x][i] == 'O') { // loop that checks if there are any spaces between the two points that + // doesnt have a chip in it + } else { + change = false; + } + } + + if (change == true) { + for (int i = firstY; i <= secondY; i++) { // loop that goes through the line, changing the chips + if (board[x][i] == 'X' || board[x][i] == 'O') { + board[x][i] = {chip}; + } + } + } + } +} + +void displayBoard::upCheck(int x, int y, char chip, bool change) { // function for checking and changing chips in a line going up + x -= 1; + y -= 1; + int firstY; + int secondY = y; + bool addChip = false; + this->difference = 0; + + for (int i = secondY - 1; i >= 0; i--) { // loop that goes down from the origin and finds the first chip of the same character + if (board[x][i] == chip) { + firstY = i; + if (0 <= firstY < 8) { + addChip = true; + } + break; + } + } + + if (addChip == true) { + this->difference = (secondY - firstY) - 1; // the difference will be the amount of chips that are being flipped + + for (int i = firstY; i <= secondY; i++) { + if (board[x][i] == 'X' || board[x][i] == 'O') { // loop that checks if there are any spaces between the two points that + // doesnt have a chip in it + } else { + change = false; + } + } + + if (change == true) { + + for (int i = firstY; i <= secondY; i++) { // loop that goes through the line, changing the chips + if (board[x][i] == 'X' || board[x][i] == 'O') { + board[x][i] = {chip}; + } + } + } + } +} + +void displayBoard::leftCheck(int x, int y, char chip, bool change) { // function for checking and changing chips in a line going left + x -= 1; + y -= 1; + int firstX; + int secondX = x; + bool addChip = false; + this->difference = 0; + + + for (int i = secondX - 1; i >= 0; i--) { // loop that goes down from the origin and finds the first chip of the same character + if (board[i][y] == chip) { + firstX = i; + if (0 <= firstX < 8) { + addChip = true; + } + break; + } + } + + if (addChip == true) { + this->difference = (secondX - firstX) - 1; // the difference will be the amount of chips that are being flipped + + for (int i = firstX; i <= secondX; i++) { + if (board[i][y] == 'X' || board[i][y] == 'O') { // loop that checks if there are any spaces between the two points that + // doesnt have a chip in it + } else { + change = false; + } + } + + if (change == true) { + + for (int i = firstX; i <= secondX; i++) { // loop that goes through the line, changing the chips + if (board[i][y] == 'X' || board[i][y] == 'O') { + board[i][y] = {chip}; + } + } + } + } +} + +void displayBoard::rightCheck(int x, int y, char chip, bool change) { // function for checking and changing chips in a line going right + x -= 1; + y -= 1; + int firstX = x; + int secondX; + bool addChip = false; + this->difference = 0; + + + + for (int i = firstX + 1; i < 8; i++) { // loop that goes down from the origin and finds the first chip of the same character + if (board[i][y] == chip) { + secondX = i; + if (0 <= secondX < 8) { + addChip = true; + } + break; + } + } + + if (addChip == true) { + this->difference = (secondX - firstX) - 1; // the difference will be the amount of chips that are being flipped + + for (int i = firstX; i <= secondX; i++) { + if (board[i][y] == 'X' || board[i][y] == 'O') { // loop that checks if there are any spaces between the two points that + // doesnt have a chip in it + } else { + change = false; + } + } + + if (change == true) { + + for (int i = firstX; i <= secondX; i++) { // loop that goes through the line, changing the chips + if (board[i][y] == 'X' || board[i][y] == 'O') { + board[i][y] = {chip}; + } + } + } + } +} + +void displayBoard::downleftCheck(int x,int y,char chip, bool change) { // function for checking and changing chips in a line going diagonally down and to the left + x -= 1; + y -= 1; + int firstX = x; + int firstY = y; + int secondX; + int secondY; + bool addChip = false; + this->difference = 0; + + + for (int i = 1; i < 8; i++) { + if (board[firstX - i][firstY + i] == chip) { // loop that goes down from the origin and finds the first chip of the same character + secondX = firstX - i; + secondY = firstY + i; + if (secondX >= 0 && secondX < 8 && secondY >= 0 && secondY < 8) { + addChip = true; + } + break; + } + } + + if (addChip == true) { + this->difference = (firstX - secondX) - 1; // the difference will be the amount of chips that are being flipped + + int temp = firstX - secondX; + + for(int i = 1; i < temp; i++) { // loop that checks if there are any spaces between the two points that doesnt have a chip in it + if (board[firstX - i][firstY + i] == 'X' || board[firstX - i][firstY + i] == 'O') { + + } else { + change = false; + } + } + + if (change == true){ + int temp = firstX - secondX; + + for(int i = 1; i < temp; i++) { // loop that goes through the line, changing the chips + if (board[firstX - i][firstY + i] == 'X' || board[firstX - i][firstY + i] == 'O') { + board[firstX - i][firstY + i] = {chip}; + } + } + } + } +} + +void displayBoard::upleftCheck(int x, int y, char chip, bool change) { // function for checking and changing chips in a line going up and to the left + x -= 1; + y -= 1; + int firstX = x; + int firstY = y; + int secondX; + int secondY; + bool addChip = false; + this->difference = 0; + + + for (int i = 1; i < 8; i++) { + if (board[firstX - i][firstY - i] == chip) { // loop that goes down from the origin and finds the first chip of the same character + secondX = firstX - i; + secondY = firstY - i; + if (secondX >= 0 && secondX < 8 && secondY >= 0 && secondY < 8) { + addChip = true; + } + break; + } + } + + if (addChip == true) { + this->difference = (firstX - secondX) - 1; // the difference will be the amount of chips that are being flipped + + int temp = firstX - secondX; + + for(int i = 1; i < temp; i++) { // loop that checks if there are any spaces between the two points that doesnt have a chip in it + if (board[firstX - i][firstY - i] == 'X' || board[firstX - i][firstY - i] == 'O') { + + } else { + change = false; + } + } + + if (change == true){ + int temp = firstX - secondX; + + for(int i = 1; i < temp; i++) { // loop that goes through the line, changing the chips + if (board[firstX - i][firstY - i] == 'X' || board[firstX - i][firstY - i] == 'O') { + board[firstX - i][firstY - i] = {chip}; + } + } + } + } +} + +void displayBoard::downrightCheck(int x, int y, char chip, bool change) { // function for checking and changing chips in a line going down and to the right + x -= 1; + y -= 1; + int firstX = x; + int firstY = y; + int secondX; + int secondY; + bool addChip = false; + this->difference = 0; + + + for (int i = 1; i < 8; i++) { + if (board[firstX + i][firstY + i] == chip) { // loop that goes down from the origin and finds the first chip of the same character + secondX = firstX + i; + secondY = firstY + i; + if (secondX >= 0 && secondX < 8 && secondY >= 0 && secondY < 8) { + addChip = true; + } + break; + } + } + + if (addChip == true) { + this->difference = (secondX - firstX) - 1; // the difference will be the amount of chips that are being flipped + + int temp = secondX - firstX; + + for(int i = 1; i < temp; i++) { // loop that checks if there are any spaces between the two points that doesnt have a chip in it + if (board[firstX + i][firstY + i] == 'X' || board[firstX + i][firstY + i] == 'O') { + + } else { + change = false; + } + } + + if (change == true){ + int temp = secondX - firstX; + + for(int i = 1; i < temp; i++) { // loop that goes through the line, changing the chips + if (board[firstX + i][firstY + i] == 'X' || board[firstX + i][firstY + i] == 'O') { + board[firstX + i][firstY + i] = {chip}; + } + } + } + } +} + +void displayBoard::uprightCheck(int x,int y,char chip, bool change) { // function for checking and changing chips in a line going up and to the right + x -= 1; + y -= 1; + int firstX = x; + int firstY = y; + int secondX; + int secondY; + bool addChip = false; + this->difference = 0; + + + for (int i = 1; i < 8; i++) { + if (board[firstX + i][firstY - i] == chip) { // loop that goes down from the origin and finds the first chip of the same character + secondX = firstX + i; + secondY = firstY - i; + if (secondX >= 0 && secondX < 8 && secondY >= 0 && secondY < 8) { + addChip = true; + } + break; + } + } + + if (addChip == true) { + this->difference = (secondX - firstX) - 1; // the difference will be the amount of chips that are being flipped + + int temp = secondX - firstX; + + for(int i = 1; i < temp; i++) { // loop that checks if there are any spaces between the two points that doesnt have a chip in it + if (board[firstX + i][firstY - i] == 'X' || board[firstX + i][firstY - i] == 'O') { + + } else { + change = false; + } + } + + if (change == true){ + int temp = secondX - firstX; + + for(int i = 1; i < temp; i++) { // loop that goes through the line, changing the chips + if (board[firstX + i][firstY - i] == 'X' || board[firstX + i][firstY - i] == 'O') { + board[firstX + i][firstY - i] = {chip}; + } + } + } + } +} + + + + diff --git a/Board.h b/Board.h new file mode 100644 index 0000000000000000000000000000000000000000..22221aaffc42be54d750936385fca3ccaf377e66 --- /dev/null +++ b/Board.h @@ -0,0 +1,37 @@ +#ifndef BOARD_H +#define BOARD_H +#include +#include +using namespace std; + +class displayBoard { + + public: + void start(); + void playerMove1(int x, int y); + void playerMove2(int x, int y); + void printBoard(); + int getDifference() { return difference; } + + // Vertical and horizontal checks + void downCheck(int x, int y, char chip, bool change); + void upCheck(int x, int y, char chip, bool change); + void leftCheck(int x, int y, char chip, bool change); + void rightCheck(int x, int y, char chip, bool change); + + // diagonal checks + void upleftCheck(int x, int y, char chip, bool change); + void downleftCheck(int x, int y, char chip, bool change); + void uprightCheck(int x, int y, char chip, bool change); + void downrightCheck(int x, int y, char chip, bool change); + char board[8][8] = {}; + + private: + int difference = 0; // count for the total chips being turned in a move + int x; + int y; + + + +}; +#endif \ No newline at end of file diff --git a/Cell.cpp b/Cell.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95b934c8cbc570b5f3bc7cba176f01b3260297c6 --- /dev/null +++ b/Cell.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include "Cell.h" +using namespace std; + +bool Cell::isLegalPlacementfor(int x, int y, char board[][8], char playDisc, char oppDisc) { + vector directions; + + Cell current(x - 1, y - 1); + + if (current.isOccupied(board, playDisc) || current.isOccupied(board, oppDisc)) { + return false; + } + Cell north(x - 1, y - 2); + if (north.isOccupied(board, oppDisc)) { + directions.push_back(north.NORTH); + } + Cell northEast(x, y - 2); + if (northEast.isOccupied(board, oppDisc)) { + directions.push_back(northEast.NORTHEAST); + } + Cell east(x, y - 1); + if (east.isOccupied(board, oppDisc)) { + directions.push_back(EAST); + + } + Cell southEast(x, y); + if (southEast.isOccupied(board, oppDisc)) { + directions.push_back(SOUTHEAST); + + } + Cell south(x - 1, y); + if (south.isOccupied(board, oppDisc)) { + directions.push_back(SOUTH); + + } + Cell southWest(x - 2, y); + if (southWest.isOccupied(board, oppDisc)) { + directions.push_back(SOUTHWEST); + + } + Cell west(x - 2, y - 1); + if (west.isOccupied(board, oppDisc)) { + directions.push_back(WEST); + } + Cell northWest(x - 2, y - 2); + if (northWest.isOccupied(board, oppDisc)) { + directions.push_back(NORTHWEST); + + } + // for (int i = 0; i < directions.size(); i++) { + // cout << directions.at(i) << endl; + // } + for (auto direction : directions) { + + try{ + int value = current.sequenceLength(direction, board, oppDisc, ""); + if (value > 0) { + return true; + } + } + catch(runtime_error &excpt) { + //cout << excpt.what() << endl; + } + } + return false; +} + +int Cell::sequenceLength(Directions direction, char board[][8], char playDisc, string indent) { + int x1, y1; + switch (direction) { + case NORTH: + x1 = x; + y1 = y - 1; + break; + case NORTHEAST: + x1 = x + 1; + y1 = y - 1; + break; + case EAST: + x1 = x + 1; + y1 = y; + break; + case SOUTHEAST: + y1 = y + 1; + x1 = x + 1; + break; + case SOUTH: + x1 = x; + y1 = y + 1; + break; + case SOUTHWEST: + y1 = y + 1; + x1 = x - 1; + case WEST: + x1 = x - 1; + y1 = y; + break; + case NORTHWEST: + y1 = y - 1; + x1 = x - 1; + break; + default: + exit(1); + } + + if (x1 < 0 || x1 >= 8 || y1 < 0 || y1 >= 8) { + throw runtime_error("Invalid Sequence"); + } + Cell sequence(x1, y1); + if (board[x1][y1] == ' ') { + throw runtime_error("Invalid Input"); + } + + if (board[x1][y1] != playDisc) { + return 0; + } + int result = (1 + sequence.sequenceLength(direction, board, playDisc, " " + indent)); + return result; +} + +bool Cell::isOccupied(char board[][8], char disc) { + return (board[x][y] == disc); +} diff --git a/Cell.h b/Cell.h new file mode 100644 index 0000000000000000000000000000000000000000..8889e75d06adbc3adeebd89714032ca3b6818544 --- /dev/null +++ b/Cell.h @@ -0,0 +1,19 @@ +#ifndef CELL_H +#define CELL_H + +#include +using namespace std; + +class Cell { + public: + Cell(int x, int y) {this->x = x; this->y = y;} + Cell() {this->x = 0; this->y = 0;} + enum Directions{NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST}; + bool isLegalPlacementfor(int x, int y, char board[][8], char playDisc, char oppDisc); + int sequenceLength(Directions direction, char board[][8], char playDisc, string indent); + bool isOccupied(char board[][8], char disc); + int x, y; + +}; + +#endif diff --git a/mainOthello.cpp b/mainOthello.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a71c26538d1b7250a87b4100cd9d01a02c477d8 --- /dev/null +++ b/mainOthello.cpp @@ -0,0 +1,263 @@ +#include // For cin and cout +#include +#include "Board.h" +#include "AIplayer.h" +#include "Cell.h" +using namespace std; + + +int main() { + int seed = 0; + int turn = 1; + int difficulty = 0; + int x, y; + int aiX, aiY; + pair AImove; + bool winner = false; + + // Creates AI + AIplayer AIturn; + + // Header + cout << "Welcome to Othello!" << endl; + cout << "the game of Reversi" << endl; + cout << endl; + + // ask for difficulty level + cout << "What difficulty would you like to play against:" << endl; + cout << "1) Easy" << endl; + cout << "2) Hard" << endl; + cout << "3) 2 Player" << endl; + cout << "Enter your choice: "; + cin >> difficulty; + + // Error checking for difficulty + while(cin.fail()){ + + cin.clear(); + cin.ignore(100, '\n'); + cout << "Invalid selection."<> difficulty; + + } + + // start the game + displayBoard board;// Brand new board + + board.start(); + board.printBoard(); + Cell check; + cout << "X goes first."<> x >> y; + // Check fo valid move + if(check.isLegalPlacementfor(x, y, board.board, 'X', 'O')){ + // Player moves + board.playerMove1(x,y); + // Check for flips in every direction + board.upCheck(x, y, 'X', true); + board.downCheck(x, y, 'X', true); + board.leftCheck(x, y, 'X', true); + board.rightCheck(x, y, 'X', true); + + board.uprightCheck(x, y,'X', true); + board.upleftCheck(x, y,'X', true); + board.downrightCheck(x, y,'X', true); + board.downleftCheck(x, y,'X', true); + + // Change to player 2 + turn++; + + }else{ + cout << "Invalid Move!"<> x >> y; + // Check fo valid move + if(check.isLegalPlacementfor(x, y, board.board, 'X', 'O')){ + // Player moves + board.playerMove1(x,y); + // Check for flips in every direction + board.upCheck(x, y, 'X', true); + board.downCheck(x, y, 'X', true); + board.leftCheck(x, y, 'X', true); + board.rightCheck(x, y, 'X', true); + + board.uprightCheck(x, y,'X', true); + board.upleftCheck(x, y,'X', true); + board.downrightCheck(x, y,'X', true); + board.downleftCheck(x, y,'X', true); + + // Change to player 2 + turn++; + + }else{ + cout << "Invalid Move!"<> x >> y; + + // Player one's move + if (turn == 1) { + // Check fo valid move + if(check.isLegalPlacementfor(x, y, board.board, 'X', 'O')){ + // Player moves + board.playerMove1(x,y); + // Check for flips in every direction + board.upCheck(x, y, 'X', true); + board.downCheck(x, y, 'X', true); + board.leftCheck(x, y, 'X', true); + board.rightCheck(x, y, 'X', true); + + board.uprightCheck(x, y,'X', true); + board.upleftCheck(x, y,'X', true); + board.downrightCheck(x, y,'X', true); + board.downleftCheck(x, y,'X', true); + + // Change to player 2 + turn++; + + }else{ + cout << "Invalid Move!"<