I just started a CS degree and I'm brand new to actual programming and hence the implementation is proving difficult. I recently had an assignment that left me stumped. I was stumped because I was unable to link all the files together (2 header files .hpp and 2 implementation files .cpp). The assignment has come and gone I'm just curious as to how I would link all the files together since I know that when it comes to compile time the Board.hpp and Board.cpp files will compile into one file and the TicTacToe.hpp and TicTacToe.cpp files will compile into one file AND then all of the two compiled files will be linked to each other to produce the executable file.
Here is the error I get when I try to compile in g++:
TicTacToe.hpp:1:9: warning: #pragma once in main file
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status
I have no idea what any of that means.
I'll post the files below for your reviewing. I appreciate any help you can give. Again, I'm brand new at this so if you could explain things simply I would really appreciate it.
Board.hpp
#ifndef BOARD_HPP
#define BOARD_HPP
#include <iostream>
#include <string>
class TTTBoard
{
private:
char Board[3][3]; //creates array
int play(); // prototype for play function
void makeMove(); //prototype for makeMove function
int turn(int); //prototype for turn function
int check(int, int); //prototypr for check function
void print(char x[][3]); //prototype for print function
int gameState(char x[][3]); //prototype for gameState fuction
int player1, player2, draw, player, winner, done; //creates variables to be used.
int row, col; //creates variables to be used in gamestate function
public:
int TtlGames, TtlP1, TtlP2, TtlDraws; //creates variables that will define gamestate
void intBoard(); //prototype for intboard
};
#endif
The next one is kind of long.
Board.cpp
#include "Board.hpp"
#include <iostream>
#include <iomanip>
void TTTBoard::intBoard() //function to initialize the board
{ //initialzes the variables in order
done = false; // to be used for later functions
winner = 0;
player = 2;
player1 = 1;
player2 = 2;
draw = 3;
int i, k;
for (k = 0; k<3; k++) //initializes array to 0
{
for (i = 0; i<3; i++)
{
Board[k][i] = 0;
}
}
play(); //begins the game
}
int TTTBoard::check(int row, int col) //checks if spot if occupied
{
if (Board[row][col] == 0)
{
return true;
}
else if (Board[row][col] != 0)
{
std::cout << "That square is already taken.";
return false;
}
else
{
std::cout << "Checking for win.";
gameState(Board);
}
return false;
}
void TTTBoard::makeMove() //records players move
{
player = turn(player);
int answer = false;
while (answer == false)
{
std::cout << "Player" << turn(player) << ": please enter your move\n";
std::cin >> row, col;
answer = check(row, col);
}
if (player == 1)
Board[row][col] = 'X';
else if (player == 2)
Board[row][col] = 'O';
else
std::cout << "Failed.";
}
int TTTBoard::gameState(char x[][3]) //checks for a win or a draw
{
winner = 0;
int count = 0;
int a = row;
int b = col;
for (a = 0; a<3; a++)
{
for (b = 0; b<3; b++)
{
if (Board[a][b] == 0)
{
count++;
}
}
}
if (count > 0)
{
int row, col, xCheck, oCheck;
for (row = 0; row<3; row++)
{
xCheck = 0;
oCheck = 0;
for (col = 0; col<3; col++)
{
if (x[row][col] == 'X')
xCheck++;
if (x[row][col] == 'O')
oCheck++;
if (oCheck == 3)
{
winner = 2;
}
if (xCheck == 3)
{
winner = 1;
}
}
}
for (col = 0; col<3; col++)
{
xCheck = 0;
oCheck = 0;
for (row = 0; row<3; row++)
{
if (x[row][col] == 'X')
xCheck++;
if (x[row][col] == 'O')
oCheck++;
if (oCheck == 3)
{
winner = 2;
}
if (xCheck == 3)
{
winner = 1;
}
}
}
if (x[0][0] == 'X' && x[1][1] == 'X' && x[2][2] == 'X')
{
winner = 1;
}
else if (x[0][0] == 'O' && x[1][1] == 'O' && x[2][2] == 'O')
{
winner = 2;
}
else if (x[2][0] == 'X' && x[1][1] == 'X' && x[0][2] == 'X')
{
winner = 1;
}
else if (x[2][0] == 'O' && x[1][1] == 'O' && x[0][2] == 'O')
{
winner = 2;
}
}
else if (count == 9)
{
std::cout << "Its a draw.";
winner = 3;
}
else
{
std::cout << "It is the next players turn\n\n";
}
if (winner > 0)
{
done = true;
}
return done;
}
void TTTBoard::print(char Board[][3]) //prints current board state
{
std::cout << "\n";
std::cout << " 0 1 2\n";
std::cout << "0 " << Board[0][0] << " " << Board[0][1] << " " << Board[0][2] << " \n";
std::cout << "1 " << Board[1][0] << " " << Board[1][1] << " " << Board[1][2] << " \n";
std::cout << "2 " << Board[2][0] << " " << Board[2][1] << " " << Board[2][2] << " \n";
}
This one is also long.
TicTacToe.hpp
#ifndef TICTACTOE_HPP
#define TICTACTOE_HPP
#include "Board.hpp"
#include <iostream>
#include <string>
#include <iomanip>
class Board; //creates a board to be forward declared
class TicTacToe //creates tictactoe class
{
private:
int check(int, int);
int turn(int player);
int play(); //prototype for play method
int gameState(char x[][3]);
public:
int TtlGames, TtlP1, TtlP2, TtlDraws;
void intBoard();
Board* playBoard; //forward declarations for use in functions
Board* print;
Board* makeMove;
Board* BoardT;
};
#endif
TicTacToe.cpp
#include "Board.hpp"
#include "TicTacToe.hpp"
#include <iostream>
#include <string>
void TTTBoard::intBoard() //initializes board
{
done = false;
winner = 0;
player = 2;
player1 = 1;
player2 = 2;
draw = 3;
int i, k;
for (k = 0; k<3; k++)
{
for (i = 0; i<3; i++)
{
Board[k][i] = 0;
}
}
play();
}
int TicTacToe::turn(int player) //informs players of whose turn it is.
{
switch (player)
{
case 1: player = 2;
{
std::cout << "\nPlayers 1 turn.\n\n";
break;
}
case 2: player = 1;
{
std::cout << "\nPlayers 2 turn.\n\n";
break;
}
}
return player;
}
int TTTBoard::gameState(char x[][3]) //checks for win or draw
{
winner = 0;
int count = 0;
int a = row;
int b = col;
for (a = 0; a<3; a++)
{
for (b = 0; b<3; b++)
{
if (Board[a][b] == 0)
{
count++;
}
}
}
if (count > 0)
{
int row, col, xCheck, oCheck;
for (row = 0; row<3; row++)
{
xCheck = 0;
oCheck = 0;
for (col = 0; col<3; col++)
{
if (x[row][col] == 'X')
xCheck++;
if (x[row][col] == 'O')
oCheck++;
if (oCheck == 3)
{
winner = 2;
}
if (xCheck == 3)
{
winner = 1;
}
}
}
for (col = 0; col<3; col++)
{
xCheck = 0;
oCheck = 0;
for (row = 0; row<3; row++)
{
if (x[row][col] == 'X')
xCheck++;
if (x[row][col] == 'O')
oCheck++;
if (oCheck == 3)
{
winner = 2;
}
if (xCheck == 3)
{
winner = 1;
}
}
}
if (x[0][0] == 'X' && x[1][1] == 'X' && x[2][2] == 'X')
{
winner = 1;
}
else if (x[0][0] == 'O' && x[1][1] == 'O' && x[2][2] == 'O')
{
winner = 2;
}
else if (x[2][0] == 'X' && x[1][1] == 'X' && x[0][2] == 'X')
{
winner = 1;
}
else if (x[2][0] == 'O' && x[1][1] == 'O' && x[0][2] == 'O')
{
winner = 2;
}
}
else if (count == 9)
{
std::cout << "Its a draw.";
winner = 3;
}
else
{
std::cout << "It is the next players turn\n\n";
}
if (winner > 0)
{
done = true;
}
return done;
}
int TicTacToe::play() //initializes the game
{
int done = false;
Board* print(Board);
while (!done)
{
int count = 0;
Board* makeMove();
Board* (Board);
count++;
if (count != 9)
{
return !done;
}
else
{
done = true;
}
}
return 0;
}
int main() //main method
{
TicTacToe playGame;
playGame.TtlGames = 0, playGame.TtlP1 = 0,
playGame.TtlP2 = 0, playGame.TtlDraws = 0; //counters for total games, Player 1 Total,
int Winner = 0; //Player 2 Total , and Total draws.
char done = false;
while (!done)
{
// This will display before each game
std::cout << "Let's play a game of TicTacToe\n\n";
// Play a game and remember who won (if anyone)
playGame.intBoard();
}
// Finish
std::cout << "\n\nThank you for playing!\n";
std::cin.get();
std::cin.get();
return 0;
}
I attempted the suggestion by Code Fuller but it gave me this error.
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status
So I thought maybe if I put the Main method in a separate file and link them all it might work. I got this:
/tmp/ccmSwwUz.o: In function `TTTBoard::intBoard()':
TicTacToe.cpp:(.text+0x0): multiple definition of `TTTBoard::intBoard()'
/tmp/ccSwOY9D.o:Board.cpp:(.text+0x0): first defined here
/tmp/ccmSwwUz.o: In function `TTTBoard::gameState(char (*) [3])':
TicTacToe.cpp:(.text+0x104): multiple definition of `TTTBoard::gameState(char (* ) [3])'
/tmp/ccSwOY9D.o:Board.cpp:(.text+0x288): first defined here
/tmp/ccSwOY9D.o: In function `TTTBoard::intBoard()':
Board.cpp:(.text+0xa7): undefined reference to `TTTBoard::play()'
/tmp/ccSwOY9D.o: In function `TTTBoard::makeMove()':
Board.cpp:(.text+0x176): undefined reference to `TTTBoard::turn(int)'
Board.cpp:(.text+0x19b): undefined reference to `TTTBoard::turn(int)'
/tmp/ccmSwwUz.o: In function `TTTBoard::intBoard()':
TicTacToe.cpp:(.text+0xa7): undefined reference to `TTTBoard::play()'
/tmp/ccz4019v.o: In function `main':
Main.cpp:(.text+0x48): undefined reference to `TicTacToe::intBoard()'
collect2: ld returned 1 exit status
So then I tried compiling the Board into an object first then linking TicTacToe and Main:
g++ Board.o TicTacToe.cpp Main.cpp -o TTT
and got the following errors:
/tmp/cc9h5kAs.o: In function `TTTBoard::intBoard()':
TicTacToe.cpp:(.text+0x0): multiple definition of `TTTBoard::intBoard()'
Board.o:Board.cpp:(.text+0x0): first defined here
/tmp/cc9h5kAs.o: In function `TTTBoard::gameState(char (*) [3])':
TicTacToe.cpp:(.text+0x104): multiple definition of `TTTBoard::gameState(char (*) [3])'
Board.o:Board.cpp:(.text+0x288): first defined here
Board.o: In function `TTTBoard::intBoard()':
Board.cpp:(.text+0xa7): undefined reference to `TTTBoard::play()'
Board.o: In function `TTTBoard::makeMove()':
Board.cpp:(.text+0x176): undefined reference to `TTTBoard::turn(int)'
Board.cpp:(.text+0x19b): undefined reference to `TTTBoard::turn(int)'
/tmp/cc9h5kAs.o: In function `TTTBoard::intBoard()':
TicTacToe.cpp:(.text+0xa7): undefined reference to `TTTBoard::play()'
/tmp/ccZlZ4Dn.o: In function `main':
Main.cpp:(.text+0x48): undefined reference to `TicTacToe::intBoard()'
collect2: ld returned 1 exit status
You trying to compile Board.cpp to executable file while it doesn't contain 'main' entrypoint. You have to compile Board.cpp to object file first:
gcc Board.cpp -c
Then you can compile TicTacToe.cpp and link it with Board.o:
gcc Board.o TicTacToe.cpp -o TicTacToe
Related
I am trying to create a c++ unbeatable tic tac toe AI. after watching several videos on the topic i thought I had it all figured out. An error pops up on the screen saying "Expression: vector subscript out of range". I believe the error is coming from the availableMoves() function. however I do not know why.
The game itself works fine. any help would be appreciated.
#include <iostream>
#include <vector>
#include <ctime>
bool in(std::vector<int> v, int element)
{
for (int i = 0; i < v.size(); i++)
{
if (element == v[i])
{
return true;
}
}
return false;
}
class Board
{
private:
char board[3][3] = { {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'} };
public:
void displayBoard()
{
std::cout << "___________________" << std::endl;
for (int i = 0; i < 3; i++)
{
std::cout << "| ";
for (int j = 0; j < 3; j++)
{
std::cout << board[i][j] << " | ";
}
std::cout << std::endl;
}
std::cout << "___________________" << std::endl;
}
std::vector<int> availableMoves()
{
std::vector<int> moves;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (board[i][j] != 'X' && board[i][j] != 'O')
{
moves.push_back(i * 3 + j);
}
}
}
return moves;
}
void move(int choice, char mark)
{
int y = choice / 3;
int x = choice - y * 3;
board[y][x] = mark;
}
void revert(int choice)
{
int y = choice / 3;
int x = choice - y * 3;
board[y][x] = (char)choice + 48;
}
int checkWin()
{
for (int i = 0; i < 3; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2])
{
if (board[i][0] == 'X')
{
return 1;
}
else if (board[i][0] == 'O')
{
return -1;
}
}
}
for (int i = 0; i < 3; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i])
{
if (board[0][i] == 'X')
{
return 1;
}
else if (board[0][i] == 'O')
{
return -1;
}
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2])
{
if (board[0][0] == 'X')
{
return 1;
}
else if (board[0][0] == 'O')
{
return -1;
}
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0])
{
if (board[0][2] == 'X')
{
return 1;
}
else if (board[0][2] == 'O')
{
return -1;
}
}
return 0;
}
int evaluate()
{
return (checkWin() * -1) * (availableMoves().size() + 1);
}
Board& operator=(Board& b)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
board[i][j] = b.board[i][j];
}
}
return (*this);
}
};
class TicTacToe
{
private:
Board board;
int turn;
int searches = 0;
public:
TicTacToe()
{
std::srand(time(0));
turn = std::rand() % 2;
}
int minimax(int depth, Board curBoard, bool is_max)
{
searches++;
if (depth == 0 || curBoard.checkWin() != 0)
{
return board.evaluate();
}
if (is_max)
{
int max_eval = -2147483647;
for (int i = 0; i < curBoard.availableMoves().size(); i++)
{
curBoard.move(curBoard.availableMoves()[i], 'O');
depth -= 1;
int eval = minimax(depth, curBoard, false);
curBoard.revert(curBoard.availableMoves()[i]);
if (eval > max_eval)
{
max_eval = eval;
}
}
return max_eval;
}
if (!is_max)
{
int min_eval = 2147483647;
for (int i = 0; i < curBoard.availableMoves().size(); i++)
{
curBoard.move(curBoard.availableMoves()[i], 'X');
depth -= 1;
int eval = minimax(depth, curBoard, true);
curBoard.revert(curBoard.availableMoves()[i]);
if (eval < min_eval)
{
min_eval = eval;
}
}
return min_eval;
}
}
void game()
{
while (board.checkWin() == 0 && board.availableMoves().size() != 0)
{
board.displayBoard();
if (turn % 2 == 0)
{
std::cout << std::endl;
int choice;
std::cout << "Enter Your Move: ";
std::cin >> choice;
choice -= 1;
while (!in(board.availableMoves(), choice))
{
std::cout << "Enter A Valid Move: ";
std::cin >> choice;
}
board.move(choice, 'X');
std::cout << std::endl;
turn++;
}
board.displayBoard();
if (board.checkWin() != 0)
{
break;
}
if (turn % 2 == 1)
{
int ai = minimax(9 - (turn % 2), board, true);
std::cout << searches;
std::cin.get();
turn++;
}
}
if (board.checkWin() == 1)
{
std::cout << "You Won" << std::endl;
}
else if (board.checkWin() == -1)
{
std::cout << "You Lost" << std::endl;
}
else
{
std::cout << "Tie" << std::endl;
}
std::cout << "Would You Like To Play Again Y/N: ";
char playAgain;
std::cin >> playAgain;
if (playAgain == 'Y')
{
Board newBoard;
board = newBoard;
game();
}
}
};
int main()
{
TicTacToe ticTacToe;
ticTacToe.game();
}
Do you know how to debug? If not, you should definitely learn this, it's pretty helpful. But here's some things I found out.
The problem is not in availableMoves(), but in minimax(), more precisely in line 215, where the program calls curBoard. revert(curBoard. availableMoves()[i]).
void revert(int choice)
{
int y = choice / 3;
int x = choice - y * 3;
board[y][x] = (char)choice + 48;
}
for (int i = 0; i < curBoard.availableMoves().size(); i++)
{
curBoard.move(curBoard.availableMoves()[i], 'X');
depth -= 1;
int eval = minimax(depth, curBoard, true);
curBoard.revert(curBoard.availableMoves()[i]);
if (eval < min_eval)
{
min_eval = eval;
}
}
The error happens in the function revert, but I am not sure why. Maybe availableMoves also returns something wrong. Variable i is permanently 0 in the for-loop. So it is possible that there is something wrong at position 0 of the vector moves, which revert cannot handle. Try debugging yourself, maybe you'll find the problem.
How to use local variable treasureX in another function win? In the win function, the program works using board[6][t] but not treasureX. The treasureX variable is global but code is not working as intended.
#include <iostream>
#include <random>
#include <ctime>
char board[8][8];
char treasureX;
int t;
void Board() {
for (int x = 1; x < 7; x++) {
for (int y = 1; y < 7; y++) {
board[x][y] = '.';
}
}
}
void treasureSpawn() {
t = rand() % 6 + 1;
board[6][t] = 'X';
treasureX = board[6][t];
}
int displayBoard() {
for (int x = 0; x<8; x++) {
for (int y = 0; y<8; y++) {
std::cout << board[x][y];
if (y == 7) {
std::cout << std::endl;
}
}
}
return 0;
}
char playerPosition;
char playerSpawn() {
int randomY;
randomY = rand() % 6 + 1;
board[1][randomY] = 'G';
playerPosition = board[1][randomY];
return playerPosition;
}
int movement() {
char move;
std::cout << "Use WASD keys to move." << std::endl;
std::cin >> move;
for (int x = 1; x<7; x++) {
for (int y = 0; y<8; y++) {
if (board[x][y] == 'G') {
board[x][y] = '.';
if (move == 'W' || move == 'w') {
return board[x - 1][y] = 'G';
}
else if (move == 'A' || move == 'a') {
return board[x][y - 1] = 'G';
}
else if (move == 'D' || move == 'd') {
return board[x][y + 1] = 'G';
}
else if (move == 'S' || move == 's') {
return board[x + 1][y] = 'G';
}
else {
std::cout << "Wrong key!" << std::endl;
movement();
}
}
}
}
return 0;
}
int win() {
if (treasureX == 'G') { // when player arrives at 'X' this function does not execute. Works if I put 'board[6][t]' instead of 'treasureX'.
std::cout << "You win" << std::endl;
return 0;
}
}
int main() {
srand(time(0));
Board();
playerSpawn();
outOfBounds();
treasureSpawn();
displayBoard();
do {
movement();
checkIf();
displayBoard();
} while (win() != 0);
}
Change the definition of treasureX to be const char & treasureX = treasureSpawn(); and treasureSpawn to be
const char & treasureSpawn() {
t = rand() % 6 + 1;
board[6][t] = 'X';
return board[6][t];
}
then the value of treasureX will change when the player moves over it
Here, TreasureX is a variable inintialized in function void treasureSpawn(), and its value is not changed throughout the program (And always be 'X').
However, board[6][t] is changed while the program is executing, more precisely in the int movement() function, hence their values are different when the program executed the function win()
I am trying to learn C++ and I have made litte tictactoe game but somethings wrong. I've tried to make the winner class both a void and a bool. But when I type in one coordinate it preforms the class. For making it simple you can only win if the 3 on top is O. Whats wrong?
SO if I input: 0 0 it says winner
Here's the code:
#include <iostream>
const int rows = 3;
const int elements = 3;
const char Ochar = 'O';
char board[rows][elements];
void Clear()
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < elements; j++)
{
board[i][j] = 0;
}
}
}
void Show()
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < elements; j++)
{
std::cout << " " << board[i][j] << " |";
}
std::cout << std::endl;
std::cout << "------------" << std::endl;
}
}
bool PlayerAttack(int x, int y)
{
if (board[x][y] == 0)
{
board[x][y] = Ochar;
return true;
}
return false;
}
void Winner()
{
if (board[0][0], board[0][1], board[0][2] = 'O')
{
std::cout << "Winner";
}
}
int main()
{
Clear();
Show();
int pos1 = 0;
int pos2 = 0;
while (1)
{
std::cout << "Please input a coordinate: "; std::cin >> pos1 >> pos2; std::cout << std::endl;
PlayerAttack(pos1, pos2);
Show();
Winner();
}
}
This line does not do what you think it does
if (board[0][0], board[0][1], board[0][2] = 'O')
You'd have to do
if (board[0][0] == 'O' && board[0][1] == 'O' && board[0][2] == 'O')
To use your Winner function to break your loop
bool Winner()
{
// You'll obviously have to check more than just this row
if (board[0][0] == 'O' && board[0][1] == 'O' && board[0][2] == 'O')
{
std::cout << "Winner";
return true;
}
return false;
}
Then in main
int main()
{
Clear();
Show();
int pos1 = 0;
int pos2 = 0;
bool winner = false;
while (!winner)
{
std::cout << "Please input a coordinate: "; std::cin >> pos1 >> pos2; std::cout << std::endl;
PlayerAttack(pos1, pos2);
Show();
winner = Winner(); // Use the returned bool
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I am pretty new in C++ programming. I am coding for Tic Tac Toe game to understand how its algorithm works. My question is about I have two functions. One of them is clearBoard function and the other one is drawBoard function. I got little help about them but I couldnt figure it out the way those functions works. Can anyone simply explain me what is exactly what? I have been trying to solve it and understand it but I think I got more confused. It might be a piece of cake but I really want to understand what's exactly going on. Thanks for your time and attention...
Here clearBoard function:
void clearBoard(int board[])
{
int i;
for(i = 0; i < board_size; i++) {
board[i] = -i - 1;
}
}
And here is my drawBoard function.
void drawBoard(int board[])
{
int i, j;
int n = 0;
for(i = 0; i <= 6; i = i+3) {
for(j = 0; j < 3; ++j) {
if(board[i + j] == 2)
cout << "|X|";
else if(board[i + j] == 1)
cout << "|O|";
else
cout << "|" << n << "|";
n = n+1;
}
cout << endl;
}
}
This is my main.cpp file. I just wanted to post my entire work at least it will be easier to see complete picture.
#include <iostream>
#include <ctime>
#include<cstdlib>
#include "Define.h"
using namespace std;
int main()
{
int board[board_size];
int turn = 0;
int p = 0;
int move = 10;
srand(time(NULL));
clearBoard(board);
cout << "This turn is randomly chosen!" << endl;
p = random(2) + 1;
cout << "The first move goes to Player: " << p << endl;
turn = p;
do {
if(p== 2 && 2 == turn)
{
drawBoard(board);
move = getPlayerMove(turn);
}
else
move = makeRandMove(turn);
} while(!isMoveValid(board, move));
board[move] = turn;
while(!isWin(board, move)){
drawBoard(board);
if(2 == turn)
turn = 1;
else
turn = 2;
do {
if(2 == turn)
move = getPlayerMove(turn);
else
move = makeRandMove(turn);
} while(!isMoveValid(board, move));
board[move] = turn;
}
drawBoard(board);
cout << "Player " << turn << " wins." << endl;
return 0;
}
And this is the functions.cpp file that has the functions that I was talking about above.
#include <iostream>
#include<cstdlib>
using namespace std;
const int board_size = 9;
void clearBoard(int board[])
{
int i;
for(i = 0; i < board_size; i++) {
board[i] = -i - 1;
}
}
int random(int x)
{
return rand() % x;
}
void drawBoard(int board[])
{
int i, j;
int n = 0;
for(i = 0; i <= 6; i = i+3) {
for(j = 0; j < 3; ++j) {
if(board[i + j] == 2)
cout << "|X|";
else if(board[i + j] == 1)
cout << "|O|";
else
cout << "|" << n << "|";
n = n+1;
}
cout << endl;
}
}
int getPlayerMove(int player)
{
int move;
cout << "Player " << player << " enter move: ";
cin >> move;
return move;
}
int makeRandMove(int player)
{
cout << "Computer (player " << player << ") moving." << endl;
return rand() % board_size;
}
bool isMoveValid(int board[], int move)
{
if(board[move] < 0)
return true;
return false;
}
bool isWin(int board[], int move)
{
if((board[0] == board[1] && board[0] == board[2]) ||
(board[3] == board[4] && board[3] == board[5]) ||
(board[6] == board[7] && board[6] == board[8]) ||
(board[0] == board[3] && board[0] == board[6]) ||
(board[1] == board[4] && board[1] == board[7]) ||
(board[2] == board[5] && board[2] == board[8]) ||
(board[0] == board[4] && board[0] == board[8]) ||
(board[2] == board[4] && board[2] == board[6]))
return true;
return false;
}
And here is my define.h header file has all the protypes...
#ifndef formula
#define formula
const int board_size = 9;
int random(int x);
void clearBoard(int board[]);
void drawBoard(int board[]);
int getPlayerMove(int player);
int makeRandMove(int player);
bool isMoveValid(int boardp[], int move);
bool isWin(int board[], int move);
#endif
The key to understanding the two board functions you are having difficulty with, clearBoard and drawBoard, you need to understand the data structure that you're storing your game board in. This is, in fact, a pretty simple example. Your board is defined as an array of 9 items:
int board[board_size];
...
const int board_size = 9;
The best way to think about this is if you take your 3 x 3 tic-tac-toe game board, and lay each row side by side. So the first three elements are the first row, the next three are the second row, and the last three are the final row.
The drawBoard function is the more complex of the two functions, but if you understand what the array is and what it represents, it makes this function much more understandable. The outer for loop is looping through each "row" of the gameboard, while the inner for loop loops through each element in that row.
I've implemented Negamax as it can be found on wikipedia, which includes alpha/beta pruning.
However, it seems to favor a losing move, which is an invalid result to my knowledge.
The game is Tic-Tac-Toe, I've abstracted most of the game play so it should be rather easy to spot an error within the algorithm.
#include <list>
#include <climits>
#include <iostream>
//#define DEBUG 1
using namespace std;
struct Move {
int row, col;
Move(int row, int col) : row(row), col(col) { }
Move(const Move& m) { row = m.row; col = m.col; }
};
struct Board {
char player;
char opponent;
char board[3][3];
Board() { }
void read(istream& stream) {
stream >> player;
opponent = player == 'X' ? 'O' : 'X';
for(int row = 0; row < 3; row++) {
for(int col = 0; col < 3; col++) {
char playa;
stream >> playa;
board[row][col] = playa == '_' ? 0 : playa == player ? 1 : -1;
}
}
}
void print(ostream& stream) {
for(int row = 0; row < 3; row++) {
for(int col = 0; col < 3; col++) {
switch(board[row][col]) {
case -1:
stream << opponent;
break;
case 0:
stream << '_';
break;
case 1:
stream << player;
break;
}
}
stream << endl;
}
}
void do_move(const Move& move, int player) {
board[move.row][move.col] = player;
}
void undo_move(const Move& move) {
board[move.row][move.col] = 0;
}
bool isWon() {
if (board[0][0] != 0) {
if (board[0][0] == board[0][1] &&
board[0][1] == board[0][2])
return true;
if (board[0][0] == board[1][0] &&
board[1][0] == board[2][0])
return true;
}
if (board[2][2] != 0) {
if (board[2][0] == board[2][1] &&
board[2][1] == board[2][2])
return true;
if (board[0][2] == board[1][2] &&
board[1][2] == board[2][2])
return true;
}
if (board[1][1] != 0) {
if (board[0][1] == board[1][1] &&
board[1][1] == board[2][1])
return true;
if (board[1][0] == board[1][1] &&
board[1][1] == board[1][2])
return true;
if (board[0][0] == board[1][1] &&
board[1][1] == board[2][2])
return true;
if (board[0][2] == board [1][1] &&
board[1][1] == board[2][0])
return true;
}
return false;
}
list<Move> getMoves() {
list<Move> moveList;
for(int row = 0; row < 3; row++)
for(int col = 0; col < 3; col++)
if (board[row][col] == 0)
moveList.push_back(Move(row, col));
return moveList;
}
};
ostream& operator<< (ostream& stream, Board& board) {
board.print(stream);
return stream;
}
istream& operator>> (istream& stream, Board& board) {
board.read(stream);
return stream;
}
int evaluate(Board& board) {
int score = board.isWon() ? 100 : 0;
for(int row = 0; row < 3; row++)
for(int col = 0; col < 3; col++)
if (board.board[row][col] == 0)
score += 1;
return score;
}
int negamax(Board& board, int depth, int player, int alpha, int beta) {
if (board.isWon() || depth <= 0) {
#if DEBUG > 1
cout << "Found winner board at depth " << depth << endl;
cout << board << endl;
#endif
return player * evaluate(board);
}
list<Move> allMoves = board.getMoves();
if (allMoves.size() == 0)
return player * evaluate(board);
for(list<Move>::iterator it = allMoves.begin(); it != allMoves.end(); it++) {
board.do_move(*it, -player);
int val = -negamax(board, depth - 1, -player, -beta, -alpha);
board.undo_move(*it);
if (val >= beta)
return val;
if (val > alpha)
alpha = val;
}
return alpha;
}
void nextMove(Board& board) {
list<Move> allMoves = board.getMoves();
Move* bestMove = NULL;
int bestScore = INT_MIN;
for(list<Move>::iterator it = allMoves.begin(); it != allMoves.end(); it++) {
board.do_move(*it, 1);
int score = -negamax(board, 100, 1, INT_MIN + 1, INT_MAX);
board.undo_move(*it);
#if DEBUG
cout << it->row << ' ' << it->col << " = " << score << endl;
#endif
if (score > bestScore) {
bestMove = &*it;
bestScore = score;
}
}
if (!bestMove)
return;
cout << bestMove->row << ' ' << bestMove->col << endl;
#if DEBUG
board.do_move(*bestMove, 1);
cout << board;
#endif
}
int main() {
Board board;
cin >> board;
#if DEBUG
cout << "Starting board:" << endl;
cout << board;
#endif
nextMove(board);
return 0;
}
Giving this input:
O
X__
___
___
The algorithm chooses to place a piece at 0, 1, causing a guaranteed loss, do to this trap(nothing can be done to win or end in a draw):
XO_
X__
___
I'm pretty sure the game implementation is correct, but the algorithm should be aswell.
EDIT: Updated evaluate and nextMove.
EDIT2: Fixed first problem, there still seem to be bugs though
Your evaluate function counts the empty spaces, and does not recognize a winning board.
EDIT:
There's also a relatively minor problem in nextMove. The line should be
int score = -negamax(board, 0, -1, INT_MIN + 1, INT_MAX);
Fix that (and evaluate), and the code chooses the right move.
EDIT:
This fixes it:
if (board.isWon() || depth <= 0) {
#if DEBUG > 1
cout << "Found winner board at depth " << depth << endl;
cout << board << endl;
#endif
return -100;
}
Almost all of these problems stem from not being clear about the meaning of score. It is from the point of view of player. If negamax is evaluating the position of player 1, and player 1 cannot win, the score should be low (e.g. -100); if negamax is evaluating the position of player -1, and player -1 cannot win, the score should be low (e.g. -100). If evaluate() can't distinguish the players, then returning a score of player * evaluate(board) is just wrong.
isWon returns true for both a win or a loss of the player. That can't be helping.
There seems to be something funny with the use of player.
Your toplevel loop calls "board.do_move(*it, 1);" then calls negamax with player=1.
Then negamax will call "board.do_move(*it, player);", so it looks like the first player is effectively getting 2 moves.