From da2a1aec2ba1f8f08c92b743244889c114f29bf1 Mon Sep 17 00:00:00 2001 From: Rebecca Schofield Date: Wed, 28 Oct 2015 17:12:44 -0500 Subject: [PATCH 1/2] stable AI --- Board.cpp | 127 +++++++++++++++++++++++------------------------------ Board.h | 9 ++-- Engine.cpp | 57 +++++++----------------- Engine.h | 4 +- test.cpp | 11 ----- 5 files changed, 77 insertions(+), 131 deletions(-) diff --git a/Board.cpp b/Board.cpp index 93252c9..c3b5902 100644 --- a/Board.cpp +++ b/Board.cpp @@ -45,18 +45,6 @@ Board::Board(const Board& b) { } } -void Board::setValidFalse() { - valid = false; -} - -void Board::setValidTrue() { - valid = true; -} - -bool Board::isValid() { - return valid; -} - //make this efficient! bool Board::isPiece(int r, int c){ for (int i = 0; i < pieces.size(); ++i){ @@ -68,31 +56,6 @@ bool Board::isPiece(int r, int c){ return false; } -void Board::isTaken(int r, int c) { - for (int i = 0; i < pieces.size(); ++i){ - if (pieces[i]->getX() == r && pieces[i]->getY() == c){ - if(pieces[i]->getType() == 'O') { - for(int x = 0; x < opieces.size(); ++x) { - if (opieces[x]->getX() == r && opieces[x]->getY() == c) { - opieces.erase(opieces.begin() + x); - //break; - } - } - } - else { - for(int x = 0; x < xpieces.size(); ++x) { - if (xpieces[x]->getX() == r && xpieces[x]->getY() == c) { - xpieces.erase(xpieces.begin() + x); - //break; - } - } - } - pieces.erase(pieces.begin() + i); - break; - } - } -} - //make this efficient! Piece* Board::getPiece(int r, int c){ for (int i = 0; i < pieces.size(); ++i){ @@ -104,6 +67,29 @@ Piece* Board::getPiece(int r, int c){ return new Piece(); } +void Board::isTaken(int r, int c) { + for (int i = 0; i < pieces.size(); ++i){ + if (pieces[i]->getX() == r && pieces[i]->getY() == c){ + if(pieces[i]->getType() == 'O') { + for(int x = 0; x < opieces.size(); ++x) { + if (opieces[x]->getX() == r && opieces[x]->getY() == c) { + opieces.erase(opieces.begin() + x); + } + } + } + else { + for(int x = 0; x < xpieces.size(); ++x) { + if (xpieces[x]->getX() == r && xpieces[x]->getY() == c) { + xpieces.erase(xpieces.begin() + x); + } + } + } + pieces.erase(pieces.begin() + i); + break; + } + } +} + moves Board::parse(string input){ input = myToUpper(input); @@ -137,17 +123,33 @@ moves Board::parse(string input){ bool Board::isGameOver(){ for (int i = 0; i < xpieces.size(); ++i){ if (xpieces[i]->getX() == 7){ - cout<<"\n\n\nPlayer X wins!\n\n\n"<getX() == 0){ - cout<<"\n\n\nPlayer O wins!\n\n\n"<getX() == 7){ + return "Player X wins!"; + } + } + + for (int i = 0; i < opieces.size(); ++i){ + if (opieces[i]->getX() == 0){ + return "Player O wins!"; + } + } + + return "ERROR: function whoWon() called incorrectly."; } void Board::changeTurns(){ @@ -156,15 +158,6 @@ void Board::changeTurns(){ } void Board::displayBoard(){ - /* - cout << "Debugging:\n"; - for (int i = 0; i < pieces.size(); ++i){ - if(i%8 == 0) - cout << "\n"; - cout << pieces[i]->getX() << " " << pieces[i]->getY() << " " << pieces[i]->getType() << "\t"; - } - cout << "Debugging:\n\n"; - */ cout << "; A B C D E F G H"< Board::viewPossibleMoves(){ } else if (turn == 'O') { - //cout << "\nTESTING\n\n"; for (int i = 0; i < opieces.size(); ++i){ r = opieces[i]->getX(); c = opieces[i]->getY(); @@ -483,7 +475,7 @@ string Board::myToUpper(string input){ if ((input[i] - 0 >= 97) && (input[i] - 0 <= 122)) { numeric = input[i] - 32; - output.push_back((char)numeric);// = 'Q';//(char) numeric; + output.push_back((char)numeric); } else output.push_back(input[i]); } @@ -495,17 +487,13 @@ string Board::myToUpper(string input){ void Board::undo(Board& tablero){ vector record; - if (record.size() < 2) - { + if (record.size() < 2){ cout<<"nothing to undo"< record; input = myToUpper(input); - //cout << "MOVE: " << input << "\n\n"; - if (input == "UNDO") - { + if (input == "UNDO"){ undo(tablero); } - else if (input == "DISPLAYRECORD") //for debugging purposes - { + else if (input == "DISPLAYRECORD"){ cout<<"record: "<& inputVec, Board inputBoard){ - if (inputVec.size() == 10) - { + if (inputVec.size() == 10){ inputVec.erase(inputVec.begin()); } - else if (inputVec.size() > 10) - { + else if (inputVec.size() > 10){ cout<<"QUEUE OVERFLOW!"< getXPieces() const { return xpieces; } vector getOPieces() const { return opieces; } char getTurnPls() const { return turn; } moves parse(string input); char getTurn() { return turn; } bool isGameOver(); + string whoWon(); void changeTurns(); void displayBoard(); string boardToString(); diff --git a/Engine.cpp b/Engine.cpp index 5bf1da1..3ba0753 100644 --- a/Engine.cpp +++ b/Engine.cpp @@ -26,27 +26,23 @@ void Engine::startGame(){ vector record; b->snapshot(record, *b); - while (gameOver != true) - { + while (gameOver != true){ gameOver = b->isGameOver(); - while(b->getTurn() == 'O' && !b->isValid()) - { + while(b->getTurn() == 'O' && !b->isValid()){ b->displayBoard(); cout<<"\nEnter command: "; cin>>move; cout << "\n"; b->interpret(move, *b); - if(b->isValid()) { + + if(b->isValid()){ b->changeTurns(); b->setValidFalse(); } } - //if(b->isValid()) cout << b->getTurn(); - - while(b->getTurn() == 'X' ) - { + while(b->getTurn() == 'X' ){ AI(); } @@ -57,41 +53,30 @@ void Engine::startGame(){ } } -void Engine::easyAI() -{ +void Engine::easyAI(){ vector listOfMoves = b->viewPossibleMoves(); - /* - for(int x = 0; x < listOfMoves.size(); ++x) { - cout << listOfMoves[x].row << " " << listOfMoves[x].column << " " << listOfMoves[x].moveType << "\n\n"; - } - */ + srand(time(NULL)); int randomChoice = rand() % (listOfMoves.size()-1) - 0; - //int temp = randomChoice; - cout << "easy AI move: " << listOfMoves[randomChoice].row << listOfMoves[randomChoice].column << listOfMoves[randomChoice].moveType << "\n"; b->move(listOfMoves[randomChoice]); b->changeTurns(); } -void Engine::AI(){ - //cout << "----------------------BEGIN AI FUNCTION----------------------\n"; +void Engine::AI(int depth){ vector listOfMoves = b->viewPossibleMoves(); Board* temp = new Board(*b); - //probably not needed, check later - /* - if (b->getTurn() != 'X'){ - cout << "a changing of turns is needed. \n"; - b->changeTurns(); - } - */ + //create node with current board state + //only doing 1 branch right now because testing /*for (int i = 0; i < listOfMoves.size(); ++i){ minMax(b, listOfMoves[i]); }*/ + //remove this soon b->move(minMax(temp, listOfMoves[0], 0, 0)); + b->changeTurns(); //verification of correct turn @@ -100,8 +85,8 @@ void Engine::AI(){ cout << "ERROR in Engine::AI: b is on the wrong turn. \n"; } */ + b->displayBoard(); - //cout << "----------------------END AI FUNCTION----------------------\n"; } moves Engine::minMax(Board* temp, moves m, int c, int r){ @@ -109,36 +94,24 @@ moves Engine::minMax(Board* temp, moves m, int c, int r){ //cout << "c: " << c << "\n\n"; //cout << "current turn: " << temp->getTurn() << "\n"; vector listOfMoves = temp->viewPossibleMoves(); - //cout << "listOfMoves size: " << listOfMoves.size() << "\n\n"; - /* - if (c > 5){ - return m; - } - */ + if (temp->isGameOver() == true){ - //cout << "END OF PATH REACHED\n"; + cout << "END OF PATH REACHED\n\n"; return m; } else { if(temp->getPiece(8 - m.row, m.column)->getType() == temp->getTurn() && temp->isThisMovePossible(8 - m.row, m.column, m.moveType)){ - //cout << "piece has been moved in minMax\n"; temp->move(m); temp->evaluate('X', 'O'); temp->changeTurns(); - //temp->displayBoard(); } else { - //cout << m.row << " " << m.column << "\n\n"; m = minMax(temp, listOfMoves[++r], c, r); } - //temp->displayBoard(); vector listOfMoves = temp->viewPossibleMoves(); - //cout << "listOfMoves size: " << listOfMoves.size() << "\n\n"; minMax(temp, listOfMoves[0], 0, 0); - - //testing return m; } } diff --git a/Engine.h b/Engine.h index 9a4b2d7..d552741 100644 --- a/Engine.h +++ b/Engine.h @@ -9,9 +9,9 @@ class Engine { public: Engine(); + Board* getBoard() { return b; } void startGame(); void easyAI(); - void AI(); - Board* getBoard() { return b; } + void AI(int depth); moves minMax(Board* temp, moves m, int c, int r); }; diff --git a/test.cpp b/test.cpp index 9524e92..c26c406 100644 --- a/test.cpp +++ b/test.cpp @@ -6,16 +6,5 @@ int main() { //Board b; Engine e; - /* ->>>>>>> master - int pn = 0; - cout << "Welcome to Breakthrough server launcher, please enter a host port number: \n"; - cin >> pn; - cin.clear(); - cin.ignore(10000,'\n'); -<<<<<<< HEAD - e.startGame(pn); -======= - */ e.startGame(); } From b1b340e6d2fe2271c61d8adb0391185cf405e05b Mon Sep 17 00:00:00 2001 From: Rebecca Schofield Date: Thu, 29 Oct 2015 08:58:32 -0500 Subject: [PATCH 2/2] minmax structure done --- Board.cpp | 26 ++++++++++++++------------ Board.h | 11 ++++++++--- Engine.cpp | 37 ++++++++++++++----------------------- Engine.h | 5 +++-- MNode.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ MNode.h | 30 ++++++++++++++++++++++++++++++ makefile | 12 ++++++------ 7 files changed, 118 insertions(+), 46 deletions(-) create mode 100755 MNode.cpp create mode 100755 MNode.h diff --git a/Board.cpp b/Board.cpp index c3b5902..6750ab2 100644 --- a/Board.cpp +++ b/Board.cpp @@ -250,7 +250,7 @@ void Board::move(string inputMove){ move(m); } -void Board::move(moves m){ +Board Board::move(moves m){ int row = 8 - (m.row); int column = m.column; @@ -258,7 +258,7 @@ void Board::move(moves m){ if (row > 8 || row < 0 || column > 8 || column < 0) { cout<<"ERROR: index out of bound."<getX() << piece->getY() << "\n\n"; if (piece->getType() != turn) { @@ -277,9 +277,9 @@ void Board::move(moves m){ else { if(isThisMovePossible(row, column, m.moveType)) - { + { if (m.moveType == "FWD") { - piece->moveFwd(); + piece->moveFwd(); } else if (m.moveType == "LEFT") { @@ -334,6 +334,8 @@ void Board::move(moves m){ setValidFalse(); } } + + return *this; } bool Board::isThisMovePossible(int r, int c, string moveType){ @@ -355,16 +357,16 @@ bool Board::isThisMovePossible(int r, int c, string moveType){ if (piece->getType() == 'O') reflector = -1; - if (moveType == "FWD"){ + if (moveType == "FWD"){ if (!isPiece(r + reflector, c)) - return true; + return true; else return false; } else if (moveType == "RIGHT"){ temp = getPiece(r + reflector, c+1); - if(c < 7) { + if(c < 7) { if (!isPiece(r+reflector, c+1) && (r+reflector >= 0) && (r+reflector <= 7) && (c+1 <= 7)) { //cout << "What.\n\n"; return true; @@ -379,14 +381,14 @@ bool Board::isThisMovePossible(int r, int c, string moveType){ return false; } } - else { + else { return false; } } else if (moveType == "LEFT"){ temp = getPiece(r + reflector, c-1); - if(c > 0) { + if(c > 0) { if (!isPiece(r+reflector, c-1) && (r+reflector >= 0) && (r+reflector <= 7)) { //cout << "What.\n\n"; return true; @@ -401,7 +403,7 @@ bool Board::isThisMovePossible(int r, int c, string moveType){ return false; } } - else { + else { return false; } } @@ -549,4 +551,4 @@ int Board::evaluate(char max, char min){ return 0; } } - + diff --git a/Board.h b/Board.h index 21c5d4a..7af5bcf 100644 --- a/Board.h +++ b/Board.h @@ -10,6 +10,12 @@ struct moves { int row; int column; string moveType; + + moves() { + row = -1; + column = -1; + moveType = ""; + } moves(int linea, int columna, string m) { row = linea; @@ -47,8 +53,7 @@ public: int charToIntColumn(char input); char intToCharColumn(int input); void move(string inputMove); - void move(moves jugada); - void moveWOPrint(moves jugada); + Board move(moves m); bool isThisMovePossible(int r, int c, string moveType); vector viewPossibleMoves(); string myToUpper(string input); @@ -56,4 +61,4 @@ public: void interpret(string input, Board& tablero); void snapshot(vector& inputVec, Board inputBoard); int evaluate(char max, char min); -}; +}; diff --git a/Engine.cpp b/Engine.cpp index 3ba0753..17079f0 100644 --- a/Engine.cpp +++ b/Engine.cpp @@ -43,7 +43,8 @@ void Engine::startGame(){ } while(b->getTurn() == 'X' ){ - AI(); + easyAI(); + //AI(3); } gameOver = b->isGameOver(); @@ -64,10 +65,9 @@ void Engine::easyAI(){ } void Engine::AI(int depth){ - vector listOfMoves = b->viewPossibleMoves(); Board* temp = new Board(*b); - - //create node with current board state + moves empty; + MNode* root = new MNode(*temp, empty, 0); //only doing 1 branch right now because testing /*for (int i = 0; i < listOfMoves.size(); ++i){ @@ -75,33 +75,23 @@ void Engine::AI(int depth){ }*/ //remove this soon - b->move(minMax(temp, listOfMoves[0], 0, 0)); - - b->changeTurns(); - - //verification of correct turn - /* - if (b->getTurn() != 'O'){ - cout << "ERROR in Engine::AI: b is on the wrong turn. \n"; - } - */ + //b->move(minMax(temp, listOfMoves[0], 0, 0)); + b->changeTurns(); b->displayBoard(); } -moves Engine::minMax(Board* temp, moves m, int c, int r){ - //testing purposes only, c = finite depth - //cout << "c: " << c << "\n\n"; - //cout << "current turn: " << temp->getTurn() << "\n"; - vector listOfMoves = temp->viewPossibleMoves(); - - if (temp->isGameOver() == true){ +moves Engine::minMax(MNode* node, int depth){ + Board current = node->getState(); + vector listOfMoves = current.viewPossibleMoves(); + /* + if (current.isGameOver() == true){ cout << "END OF PATH REACHED\n\n"; return m; } else { - if(temp->getPiece(8 - m.row, m.column)->getType() == temp->getTurn() && temp->isThisMovePossible(8 - m.row, m.column, m.moveType)){ + if(current.getPiece(8 - m.row, m.column)->getType() == current.getTurn() && current.isThisMovePossible(8 - m.row, m.column, m.moveType)){ temp->move(m); temp->evaluate('X', 'O'); temp->changeTurns(); @@ -114,4 +104,5 @@ moves Engine::minMax(Board* temp, moves m, int c, int r){ minMax(temp, listOfMoves[0], 0, 0); return m; } -} + */ +} diff --git a/Engine.h b/Engine.h index d552741..89f3327 100644 --- a/Engine.h +++ b/Engine.h @@ -1,6 +1,7 @@ #pragma once #include "Board.h" +#include "MNode.h" using namespace std; @@ -13,5 +14,5 @@ public: void startGame(); void easyAI(); void AI(int depth); - moves minMax(Board* temp, moves m, int c, int r); -}; + moves minMax(MNode* node, int depth); +}; diff --git a/MNode.cpp b/MNode.cpp new file mode 100755 index 0000000..8f4c410 --- /dev/null +++ b/MNode.cpp @@ -0,0 +1,43 @@ +#include +#include +#include "MNode.h" + +using namespace std; + +MNode::MNode(){ + children.clear(); + minimax_val = -1; +} + +MNode::MNode(Board s, moves m, int mmval){ + state = s; + mvs = m; + minimax_val = mmval; +} + +MNode::MNode(const MNode& n){ + children = n.getChildren(); + minimax_val = n.getMMVal(); +} + +void MNode::setMMVal(int mmval) { + minimax_val = mmval; +} + +bool MNode::hasChildren(){ + if (children.size() != 0) + return true; + else + return false; +} + +void printTree(int depth, const MNode& n){ + vector children; + cout << "depth " << depth << " :" << n.getMMVal() << " "; + children = n.getChildren(); + + //print out root + for (int i = 0; i < children.size(); ++i){ + printTree(++depth, *children[i]); + } +} \ No newline at end of file diff --git a/MNode.h b/MNode.h new file mode 100755 index 0000000..1afe963 --- /dev/null +++ b/MNode.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include "Board.h" + +using namespace std; + +class MNode { + vector children; + Board state; + moves mvs; + int minimax_val; + +public: + MNode(); + MNode(Board s, moves m, int mmval); + MNode(const MNode& n); + vector getChildren() const { return children; } + void addChild(MNode* n) { children.push_back(n); } + int getMMVal() const { return minimax_val; } + void setMMVal(int mmval); + Board getState() { return state; } + void setState(Board s) { state = s; } + moves getMove() { return mvs; } + void setMove(moves m) { mvs = m; } + bool hasChildren(); +}; + +void printTree(int depth, const MNode& n); \ No newline at end of file diff --git a/makefile b/makefile index e779fde..de4028a 100755 --- a/makefile +++ b/makefile @@ -3,13 +3,13 @@ all: test server server: Server.o - g++ -std=c++11 -o server Server.o Engine.o Piece.o Board.o + g++ -std=c++11 -o server Server.o Engine.o Piece.o Board.o MNode.o -Server.o: Server.cpp Engine.cpp Board.cpp Piece.cpp - g++ -std=c++11 -c -g Server.cpp Engine.cpp Board.cpp Piece.cpp +Server.o: Server.cpp Engine.cpp Board.cpp Piece.cpp MNode.cpp + g++ -std=c++11 -c -g Server.cpp Engine.cpp Board.cpp Piece.cpp MNode.cpp test: test.o - g++ -std=c++11 -o test test.o Engine.o Piece.o Board.o + g++ -std=c++11 -o test test.o Engine.o Piece.o Board.o MNode.o -test.o: test.cpp Engine.cpp Board.cpp Piece.cpp - g++ -std=c++11 -c -g test.cpp Engine.cpp Board.cpp Piece.cpp \ No newline at end of file +test.o: test.cpp Engine.cpp Board.cpp Piece.cpp MNode.cpp + g++ -std=c++11 -c -g test.cpp Engine.cpp Board.cpp Piece.cpp MNode.cpp \ No newline at end of file