Speed up development with full-stack environments for every branch.

Learn More

Connect 4 program negamax search [C++]

Forked from Hello World C++ Example.

10 Runs 76 Views 2 Copies

Connect 4 game with negamax search for computer moves

Saved

Saved

Aberration 1

Aberration
published 24 days ago

// ConsoleApplication14.cpp : Defines the entry point for the console application.
//


#include <iostream>
#include <iomanip>
//#include <windows.h>

using namespace std;
//HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);

char board[6][7];
char p1 = 'G';
char p2 = 'R';
int d1 = 1;
int d2 = 1;

void initboard(char(&board)[6][7]);
void dispboard(char(&board)[6][7]);
char checkwin(char(&board)[6][7]);
void gametype();
void pvp(char(&board)[6][7]);
void pve(char(&board)[6][7]);
void eve(char(&board)[6][7]);
void compchoice(char(&board)[6][7], char player1,char player2, int &depth);
void playerchoice(char(&board)[6][7], char player);
void place_piece(char(&board)[6][7], char player, int move);
void remove_piece(char(&board)[6][7], int move);
int negamax(char(&board)[6][7], char player1, char player2, int &depth);
int pick_best_move(char(&board)[6][7], char player1, char player2, int &depth);



int main()
{
	gametype();


	//system("pause");
	return 0;
}




/*
------------------------------------------------------------
------------------------------------------------------------
Initialize the board as empty (empty spaces signified by '.'
------------------------------------------------------------
------------------------------------------------------------
*/
void initboard(char(&board)[6][7])
{
	for (int i = 0; i < 6; i++)
	{
		for (int j = 0; j < 7; j++)
		{
			board[i][j] = '.';
		}
		cout << endl;
	}
}
/*
-----------------------------------------
-----------------------------------------
Display's the board in it's current state
-----------------------------------------
-----------------------------------------
*/

void dispboard(char(&board)[6][7])
{
	cout << "   1   2   3   4   5   6   7";
	for (int i = 0; i < 6; i++)
	{
		cout << "\n -----------------------------\n |";

		for (int j = 0; j < 7; j++)
		{
			if (board[i][j] == '.')
			{
				cout << "   " << "|";
			}
			else if (board[i][j] == p1)
			{

				//SetConsoleTextAttribute(console, 170);
				cout << " G ";
				//SetConsoleTextAttribute(console, 15);
				cout << "|";

			}
			else if (board[i][j] == p2)
			{
				//SetConsoleTextAttribute(console, 205);
				cout << " R ";
				//SetConsoleTextAttribute(console, 15);
				cout << "|";

			}

		}
	}
	cout << "\n -----------------------------\n\n\n";

}
/*
--------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------
Allows the player to choose where to move, checks to make sure the move is valid, and calls place_piece() to place the piece if it is.
--------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------
*/
void playerchoice(char(&board)[6][7], char player)
{
	int move, check = 1;
	while (check)
	{
		cout << "Which columb?(1-7): ";
		cin >> move;
		cout << endl;
		if ((move != 1 && move != 2 && move != 3 && move != 4 && move != 5 && move != 6 && move != 7) || cin.fail() || (board[0][move - 1] != '.'))
		{
			dispboard(board);
			cout << "\n That is an invalid move. Please try again.\n";
			cin.clear();
			cin.ignore(256, '\n');
			check = 1;
		}
		else
		{
			place_piece(board, player, move);
			check = 0;

		}
	}

}
/*
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
Check if the someone won the game and returns the character of the winner, If there is no winner yet then it returns '.'
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
*/
char checkwin(char(&board)[6][7])
{
	char win = '.';
	for (int i = 0; i < 6; i++) //Check horizontal win conditions
	{
		for (int j = 0; j < 4; j++)
		{
			if (((board[i][j] == board[i][j + 1]) && (board[i][j] == board[i][j + 2]) && (board[i][j] == board[i][j + 3])) && (board[i][j] != '.'))
			{
				win = board[i][j];
				i = 6;
				j = 4;
			}
		}
	}
	for (int i = 0; i < 3; i++) //check vertical win conditions
	{
		for (int j = 0; j < 7; j++)
		{
			if (((board[i][j] == board[i + 1][j]) && (board[i][j] == board[i + 2][j]) && (board[i][j] == board[i + 3][j])) && (board[i][j] != '.'))
			{
				win = board[i][j];
				i = 3;
				j = 7;
			}
		}
	}
	for (int i = 0; i < 3; i++) //check diagonal down win conditions
	{
		for (int j = 0; j < 4; j++)
		{
			if (((board[i][j] == board[i + 1][j + 1]) && (board[i][j] == board[i + 2][j + 2]) && (board[i][j] == board[i + 3][j + 3])) && (board[i][j] != '.'))
			{
				win = board[i][j];
				i = 3;
				j = 4;
			}
		}
	}
	for (int i = 3; i < 6; i++) //check diagonal up win conditions
	{
		for (int j = 0; j < 4; j++)
		{
			if (((board[i][j] == board[i - 1][j + 1]) && (board[i][j] == board[i - 2][j + 2]) && (board[i][j] == board[i - 3][j + 3])) && (board[i][j] != '.'))
			{
				win = board[i][j];
				i = 6;
				j = 4;
			}
		}
	}
	return win;
}
/*
-------------------------------------------------
-------------------------------------------------
Plays a game of player versus player connect four
-------------------------------------------------
-------------------------------------------------
*/
void pvp(char(&board)[6][7])
{
	int i = 0;
	initboard(board);
	dispboard(board);
	for (int i = 0; i<42; i++)
	{
		if (i % 2 == 0)
		{
			cout << "Player #1's Turn!\n";
			playerchoice(board, p1);
			dispboard(board);
		}
		if (i % 2 == 1)
		{
			cout << "Player #2's Turn!\n";
			playerchoice(board, p2);
			dispboard(board);
		}
		if (checkwin(board) == p1)
		{
			cout << "Player #1 Wins!\n\n\n\n\n";
			i = 42;
		}
		if (checkwin(board) == p2)
		{
			cout << "Player #2 Wins!\n\n\n\n\n";
			i = 42;
		}
	}

}
/*
------------------------------------------------------------
------------------------------------------------------------
Allows the player to choose whether to play pvp, pve, or eve
------------------------------------------------------------
------------------------------------------------------------
*/
void gametype()
{
	int a;
	cout << "What type of game do you wish to  play?\n(Enter the number of the menu option for)\n(1):Player V Player\n(2):Player vComp\n(3):Comp V Comp\n";
	cin >> a;
	while (a != 1 && a != 2 && a != 3 || cin.fail())
	{
		cout << "That is not a valid gametype. Pick from the following menu:\n(1):Player V Player\n(2):Player vComp\n(3):Comp V Comp\n";
		cin.clear();
		cin.ignore(256, '\n');
		cin >> a;
	}
	switch (a)
	{
	case 1:
		pvp(board);
		break;
	case 2:
		pve(board);
		break;
	case 3:
		eve(board);
		break;
	}
}
/*
---------------------------------------------------------------------------
---------------------------------------------------------------------------
Places a piece of designated character on the board in a designated column.
---------------------------------------------------------------------------
---------------------------------------------------------------------------
*/
void place_piece(char(&board)[6][7], char player, int move)
{
	for (int i = 6; i > -1; i--)
	{
		if (board[i][move - 1] == '.')
		{
			board[i][move - 1] = player;
			i=-1;
		}
	}
}
/*
----------------------------------
----------------------------------
Removes the top piece in a column.
----------------------------------
----------------------------------
*/
void remove_piece(char(&board)[6][7], int move)
{
	for (int i = 0; i < 6; i++)
	{
		if (board[i][move] != '.')
		{
			board[i][move] = '.';
			i = 6;
		}
	}
}

/*
--------------------------------------------------
----------------------------------------------------------------
Scores a move by calling itself recursively and 
--------------------------------------------------
-----------------------------------------------------
*/
int negamax(char(&board)[6][7], char player1, char player2, int &depth)
{
	int best_move_score = -9999;
	int score_for_this_move = 0;

	//If player 1 wins, then the score is high (good for player1)
	if (checkwin(board) == player1)
		return 1000;

	//If player 2 loses, then the score is low (bad for player1)
	else if (checkwin(board) == player2)
		return -1000;

	for (int c = 0; c < 7; c++)
	{
		if (board[0][c] == '.')
		{
			if (depth > 0)
			{
				depth--;
				place_piece(board, player1, c + 1); //Try test move.
				score_for_this_move = -(negamax(board, player2, player1, depth));
				remove_piece(board, c); //Put back test move.
				depth++;
				if (score_for_this_move >= best_move_score)
				{
					best_move_score = score_for_this_move;
				}
			}
			else 
			{
				score_for_this_move = 0;
				if (score_for_this_move >= best_move_score)
				{
					best_move_score = score_for_this_move;
				}
			}
		}
	}


	if (best_move_score == -9999 || best_move_score == 0)
		return 0;

	else if (best_move_score < 0)
		return best_move_score + 1;

	else if (best_move_score > 0)
		return best_move_score - 1; //As the game goes longer, and the recursion goes deeper, the moves near the end are less favorable than in the beginning.

}

/*
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Allows the computer to find which of the 7 columns is the best move to make. Calls negamax() to score each move and updates the best move if another column returns a higher score.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/

int pick_best_move(char (&board)[6][7], char player1, char player2, int &depth) 
{
	int best_move_score = -9999;
	int best_move_col = 0;
	int score_for_this_move = 0;

	for (int c = 0; c < 7; c++)
	{
		if (board[0][c] == '.')
		{
			place_piece(board, player1, c + 1); //Try test move.
			score_for_this_move = -(negamax(board, player2, player1, depth));
			remove_piece(board, c); //Put back test move.

			if (score_for_this_move >= best_move_score)
			{
				best_move_score = score_for_this_move;
				best_move_col = c;
			}
		}
	}
	return (best_move_col);
}
/*
-------------------------------------------------
-------------------------------------------------
Plays a game of Enemy versus Enemy connect four
-------------------------------------------------
-------------------------------------------------
*/
void eve(char(&board)[6][7])
{
	int i = 0;
	cout << "What difficulty do you want for cpu1?\n(1) Effortless\n(2) Minimal\n(3) Easy\n(4) Average\n(5) Descent\n(6) Hard\n(7) Feindish\n";
	cin >> d1;
	if ((d1 != 1 && d1 != 2 && d1 != 3 && d1 != 4 && d1 != 5 && d1 != 6 && d1 != 7) || cin.fail())
	{
		dispboard(board);
		cout << "\n That is an invalid difficulty. Please choose a real difficulty level.\n(1) Effortless\n(2) Minimal\n(3) Easy\n(4) Average\n(5) Descent\n(6) Hard\n(7) Feindish\n";
		cin.clear();
		cin.ignore(256, '\n');
		cin >> d1;
	}
	cout << "What difficulty do you want for cpu2?\n(1) Effortless\n(2) Minimal\n(3) Easy\n(4) Average\n(5) Descent\n(6) Hard\n(7) Feindish\n";
	cin >> d2;
	if ((d2 != 1 && d2 != 2 && d2 != 3 && d2 != 4 && d2 != 5 && d2 != 6 && d2 != 7) || cin.fail())
	{
		dispboard(board);
		cout << "\n That is an invalid difficulty. Please choose a real difficulty level.\n(1) Effortless\n(2) Minimal\n(3) Easy\n(4) Average\n(5) Descent\n(6) Hard\n(7) Feindish\n";
		cin.clear();
		cin.ignore(256, '\n');
		cin >> d2;
	}

	initboard(board);
	dispboard(board);
	for (int i = 0; i<42; i++)
	{
		if (i % 2 == 0)
		{
			cout << "Player #1's Turn!\n";
			compchoice(board, p1, p2, d1);
			dispboard(board);
		}
		if (i % 2 == 1)
		{
			cout << "Player #2's Turn!\n";
			compchoice(board, p2, p1, d2);
			dispboard(board);
		}
		if (checkwin(board) == p1)
		{
			cout << "Player #1 Wins!\n\n\n\n\n";
			i = 42;
		}
		if (checkwin(board) == p2)
		{
			cout << "Player #2 Wins!\n\n\n\n\n";
			i = 42;
		}
	}
	d1 = 0;
	d2 = 0;
}
/*
--------------------------------------------
--------------------------------------------
Lets the computer take its turn when called.
--------------------------------------------
--------------------------------------------
*/
void compchoice(char(&board)[6][7], char player1,  char player2, int &depth)
{
	int move;
	move = pick_best_move(board, player1, player2, depth);
	place_piece(board, player1, move+1);

}


void pve(char(&board)[6][7])
{
	int i = 0;
	cout << "What difficulty do you want for cpu1?\n(1) Effortless\n(2) Minimal\n(3) Easy\n(4) Average\n(5) Descent\n(6) Hard\n(7) Feindish\n";
	cin >> d1;
	if ((d1 != 1 && d1 != 2 && d1 != 3 && d1 != 4 && d1 != 5 && d1 != 6 && d1 != 7) || cin.fail())
	{
		dispboard(board);
		cout << "\n That is an invalid difficulty. Please choose a real difficulty level.\n(1) Effortless\n(2) Minimal\n(3) Easy\n(4) Average\n(5) Descent\n(6) Hard\n(7) Feindish\n";
		cin.clear();
		cin.ignore(256, '\n');
		cin >> d1;
	}
	initboard(board);
	dispboard(board);
	for (int i = 0; i<42; i++)
	{
		if (i % 2 == 0)
		{
			cout << "Player #1's Turn!\n";
			playerchoice(board, p1);
			dispboard(board);
		}
		if (i % 2 == 1)
		{
			cout << "Player #2's Turn!\n";
			compchoice(board, p2, p1, d1);
			dispboard(board);
		}
		if (checkwin(board) == p1)
		{
			cout << "Player #1 Wins!\n\n\n\n\n";
			i = 42;
		}
		if (checkwin(board) == p2)
		{
			cout << "Player #2 Wins!\n\n\n\n\n";
			i = 42;
		}
	}
	d1 = 0;
}
Please login/signup to get access to the terminal.

Your session has timed out.

Dismiss (the page may not function properly).