How can I fix my C++ Connect4 checkGameOver Function












0















We have to make Connect4 in C++ as our last assignment for one of my classes. As of right now I have a fairly functional version. I had a really promising idea for a recursive solution for checking if the game is over but the issue is it only checks starting from the token it is starting at. For example if the most recently placed token has 3 of the same kind in any direction that is valid it works, but if it has 2 in one direction and 1 the opposite way it doesn't work. Does anyone have any ideas for how I could edit my function to incorporate the 2nd situation or should I just scrap it and rewrite it differently. Here is my code.



//TODO implement checking spots other than start

#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

int runGame(int, int, int);
void promptUser(int**, int, int, int, int);
void genRanMove(int**, int, int, int);
bool checkGameOver(int**, int, int, int, int, int, int, int, int);
void showBoard(int**, int, int);
void playAgain();

using namespace std;

int main(int argc, char *argv) {

if (argc < 4) {
cerr << "Not enough input, syntax is 1/2 players, # columns, and # of rows" << endl;
exit(0);
}

if (argc == 4 && (argv[1][0] == '1' || argv[1][0] == '2') && (argv[2][0] >= '1' && argv[2][0] <= '9') && (argv[3][0] >= '1' && argv[3][0] <= '9')) {
cout << "nnYou have chosen to play Connect 4 in " << argv[1][0] << " player mode and with " << argv[2][0] << " columns and with " << argv[3][0] << " rows.n" << endl;
}
else {
cerr << "Improper syntax, syntax is 1/2 players, # columns, and # of rows" << endl;
exit(0);
}

cout << "Welcome to Connect 4, each player will take a turn choosing a column to select, a metaphorical coin will fall down to the highest availible row.nThe game ends when a player has gotten 4 of their coins in a row horizontally, vertically, or diagonally.nPlayer 1 will always use 1's and Player 2 will always be 2's.nThe AI will always be 3's.nEmpty slots will be shown as 0's.nn" << endl;

srand(time(NULL));
int winner = runGame(argv[1][0] - '0', argv[2][0] - '0', argv[3][0] - '0');

if (winner == 1 || winner == 2) {
cout << "Winner was player # " << winner << endl;
}
else if (winner == 3)
cout << "You let the AI win :(" << endl;
else if (winner == -1)
cout << "The game ended in a tie" << endl;

playAgain();

}

/******************************************************
** Function: runGame
** Description: runsGame
** Parameters: gameMode columns rows
** Pre-Conditions:
** Post-Conditions: returns winning player, 1 or 2 for player # and 3 for ai
******************************************************/
int runGame(int gameMode, int columns, int rows) { //returns which player won
int holdPoints[2] = { 0, 0 };
switch (gameMode) {
case 1:
cout << "You have chosen to play against an AI" << endl;
break;
case 2:
cout << "You have chosen to play with another human player" << endl;
break;
}
int** board = new int*[columns];
for (int i = 0; i< columns; i++) {
board[i] = new int[rows];
}

for (int i = 0; i< columns; i++) {
for (int j = 0; j< rows; j++) {
board[i][j] = 0;
}
}

for (int i = 0; i< rows*columns/2; i++) { //check for number of possible moves in order to have a tie
showBoard(board, rows, columns);
promptUser(board, holdPoints, rows, columns, 1);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 1, rows, columns)) {
return 1;
}
cout << "nn";
showBoard(board, rows, columns);
if (gameMode == 2) {
promptUser(board, holdPoints, rows, columns, 2);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 2, rows, columns)) {
return 2;
}
}
else if (gameMode == 1) {
genRanMove(board, holdPoints, rows, columns);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 3, rows, columns)) {
return 3;
}
}

//showBoard(board, rows, columns);

cout << "nn";
}

for (int i = 0; i < columns; i++) {
delete board[i];
}
delete board;

return -1; //signifies a tie
}


/******************************************************
** Function: promptUser
** Description: gets input from user for their turn, stores the resting place of their token in points
** Parameters: board and array to hold point,num columns
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void promptUser(int** board, int point, int numRows, int numColumns, int playerNum) {
int col, lowZero;
lowZero = -1;
cout << "What column would you like to choose" << endl;
cin >> col;
if (col<0 || col > numColumns -1) {
cout << "The # you chose must be >=0 and <= " << numColumns-1 << endl;
promptUser(board, point, numRows, numColumns, playerNum);
}
//now need to find the lowest possible row in the given column that has a 0
for (int i = 0; i < numRows; i++) {
if (board[col][i] == 0)
lowZero = i;
}

if (lowZero != -1) {
board[col][lowZero] = playerNum;
cout << "Player " << playerNum << " dropped a token in column " << col << " that rested at row " << lowZero << endl;
point[0] = col;
point[1] = lowZero;
return;
}

else {
cout << "Column " << col << " was full, please pick a new one" << endl;
promptUser(board, point, numRows, numColumns, playerNum);
}

}

/******************************************************
** Function: genRanMove
** Description: gets random column from "ai", stores the resting place of their token in points
** Parameters: board and array to hold point
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void genRanMove(int** board, int point, int numRows, int numColumns) {
cout << "AI is finding a column" << endl;
int col = rand() % numColumns;
int lowZero = -1;

for (int i = 0; i < numRows; i++) {
if (board[col][i] == 0)
lowZero = i;
}

if (lowZero != -1) {
board[col][lowZero] = 3;
cout << "AI dropped a token in column " << col << " that rested at row " << lowZero << endl;
point[0] = col;
point[1] = lowZero;
return;
}

//didnt find a row that works
genRanMove(board, point, numRows, numColumns);

}

/******************************************************
** Function: showBoard
** Description: prints he current gameboard
** Parameters: the board, numrows and numcolumns
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void showBoard(int** board, int numRows, int numColumns) {
for (int i = 0; i < numColumns; i++) {
for (int j = 0; j < numRows; j++) {
cout << board[j][i] << " ";
}
cout << endl;
}
}

/******************************************************
** Function: playAgain
** Description: gets info to play again
** Parameters: n/a
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void playAgain() {
int again;
int mode, rows, columns;
cout << "Would you like to play again? Type 1 if so." << endl;
cin >> again;
if (again) {
cout << "What mode? 1 for 1 player and 2 for 2 player" << endl;
cin >> mode;
cout << "How many rows?" << endl;
cin >> rows;
cout << "How many columns?" << endl;
cin >> columns;

if ((mode<=0 || mode >2) || rows<= 0 || columns<= 0) {
cout << "Improper inputs. Mode must be 1/2 and rows and columns must both be >0" << endl;
playAgain();
}
else {
runGame(mode, columns, rows);
}

}
}

/******************************************************
** Function: checkGameOver
** Description: checks if game is over by recursively checking spots around original
** Parameters: board, curr col, curr row, change col, change row, total found, and what number it is looking for in the board
** Pre-Conditions:
** Post-Conditions:
******************************************************/
bool checkGameOver(int** board, int currCol, int currRow, int changeCol, int changeRow, int totalFound, int numSearch, int numRows, int numColumns) {
if (totalFound == 4) //base case
return true;
if (currRow <0 || currRow >numRows - 1 || currCol<0 || currCol> numColumns - 1)
return false;

if (board[currCol][currRow] == numSearch)
totalFound++;


else
return false; // the checked index didnt contain the same # we wanted

return checkGameOver(board, currCol + changeCol, currRow + changeRow, changeCol, changeRow, totalFound, numSearch, numRows, numColumns);
}









share|improve this question























  • None of the usual mistakes like calling srand all over the place or ignoring compiler warnings. Kudos. Any way we can get you to distill this down to an Minimal, Complete, and Verifiable example though? You should be able to isolate the bug in less than 500 lines of code.

    – user4581301
    Nov 27 '18 at 0:04
















0















We have to make Connect4 in C++ as our last assignment for one of my classes. As of right now I have a fairly functional version. I had a really promising idea for a recursive solution for checking if the game is over but the issue is it only checks starting from the token it is starting at. For example if the most recently placed token has 3 of the same kind in any direction that is valid it works, but if it has 2 in one direction and 1 the opposite way it doesn't work. Does anyone have any ideas for how I could edit my function to incorporate the 2nd situation or should I just scrap it and rewrite it differently. Here is my code.



//TODO implement checking spots other than start

#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

int runGame(int, int, int);
void promptUser(int**, int, int, int, int);
void genRanMove(int**, int, int, int);
bool checkGameOver(int**, int, int, int, int, int, int, int, int);
void showBoard(int**, int, int);
void playAgain();

using namespace std;

int main(int argc, char *argv) {

if (argc < 4) {
cerr << "Not enough input, syntax is 1/2 players, # columns, and # of rows" << endl;
exit(0);
}

if (argc == 4 && (argv[1][0] == '1' || argv[1][0] == '2') && (argv[2][0] >= '1' && argv[2][0] <= '9') && (argv[3][0] >= '1' && argv[3][0] <= '9')) {
cout << "nnYou have chosen to play Connect 4 in " << argv[1][0] << " player mode and with " << argv[2][0] << " columns and with " << argv[3][0] << " rows.n" << endl;
}
else {
cerr << "Improper syntax, syntax is 1/2 players, # columns, and # of rows" << endl;
exit(0);
}

cout << "Welcome to Connect 4, each player will take a turn choosing a column to select, a metaphorical coin will fall down to the highest availible row.nThe game ends when a player has gotten 4 of their coins in a row horizontally, vertically, or diagonally.nPlayer 1 will always use 1's and Player 2 will always be 2's.nThe AI will always be 3's.nEmpty slots will be shown as 0's.nn" << endl;

srand(time(NULL));
int winner = runGame(argv[1][0] - '0', argv[2][0] - '0', argv[3][0] - '0');

if (winner == 1 || winner == 2) {
cout << "Winner was player # " << winner << endl;
}
else if (winner == 3)
cout << "You let the AI win :(" << endl;
else if (winner == -1)
cout << "The game ended in a tie" << endl;

playAgain();

}

/******************************************************
** Function: runGame
** Description: runsGame
** Parameters: gameMode columns rows
** Pre-Conditions:
** Post-Conditions: returns winning player, 1 or 2 for player # and 3 for ai
******************************************************/
int runGame(int gameMode, int columns, int rows) { //returns which player won
int holdPoints[2] = { 0, 0 };
switch (gameMode) {
case 1:
cout << "You have chosen to play against an AI" << endl;
break;
case 2:
cout << "You have chosen to play with another human player" << endl;
break;
}
int** board = new int*[columns];
for (int i = 0; i< columns; i++) {
board[i] = new int[rows];
}

for (int i = 0; i< columns; i++) {
for (int j = 0; j< rows; j++) {
board[i][j] = 0;
}
}

for (int i = 0; i< rows*columns/2; i++) { //check for number of possible moves in order to have a tie
showBoard(board, rows, columns);
promptUser(board, holdPoints, rows, columns, 1);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 1, rows, columns)) {
return 1;
}
cout << "nn";
showBoard(board, rows, columns);
if (gameMode == 2) {
promptUser(board, holdPoints, rows, columns, 2);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 2, rows, columns)) {
return 2;
}
}
else if (gameMode == 1) {
genRanMove(board, holdPoints, rows, columns);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 3, rows, columns)) {
return 3;
}
}

//showBoard(board, rows, columns);

cout << "nn";
}

for (int i = 0; i < columns; i++) {
delete board[i];
}
delete board;

return -1; //signifies a tie
}


/******************************************************
** Function: promptUser
** Description: gets input from user for their turn, stores the resting place of their token in points
** Parameters: board and array to hold point,num columns
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void promptUser(int** board, int point, int numRows, int numColumns, int playerNum) {
int col, lowZero;
lowZero = -1;
cout << "What column would you like to choose" << endl;
cin >> col;
if (col<0 || col > numColumns -1) {
cout << "The # you chose must be >=0 and <= " << numColumns-1 << endl;
promptUser(board, point, numRows, numColumns, playerNum);
}
//now need to find the lowest possible row in the given column that has a 0
for (int i = 0; i < numRows; i++) {
if (board[col][i] == 0)
lowZero = i;
}

if (lowZero != -1) {
board[col][lowZero] = playerNum;
cout << "Player " << playerNum << " dropped a token in column " << col << " that rested at row " << lowZero << endl;
point[0] = col;
point[1] = lowZero;
return;
}

else {
cout << "Column " << col << " was full, please pick a new one" << endl;
promptUser(board, point, numRows, numColumns, playerNum);
}

}

/******************************************************
** Function: genRanMove
** Description: gets random column from "ai", stores the resting place of their token in points
** Parameters: board and array to hold point
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void genRanMove(int** board, int point, int numRows, int numColumns) {
cout << "AI is finding a column" << endl;
int col = rand() % numColumns;
int lowZero = -1;

for (int i = 0; i < numRows; i++) {
if (board[col][i] == 0)
lowZero = i;
}

if (lowZero != -1) {
board[col][lowZero] = 3;
cout << "AI dropped a token in column " << col << " that rested at row " << lowZero << endl;
point[0] = col;
point[1] = lowZero;
return;
}

//didnt find a row that works
genRanMove(board, point, numRows, numColumns);

}

/******************************************************
** Function: showBoard
** Description: prints he current gameboard
** Parameters: the board, numrows and numcolumns
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void showBoard(int** board, int numRows, int numColumns) {
for (int i = 0; i < numColumns; i++) {
for (int j = 0; j < numRows; j++) {
cout << board[j][i] << " ";
}
cout << endl;
}
}

/******************************************************
** Function: playAgain
** Description: gets info to play again
** Parameters: n/a
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void playAgain() {
int again;
int mode, rows, columns;
cout << "Would you like to play again? Type 1 if so." << endl;
cin >> again;
if (again) {
cout << "What mode? 1 for 1 player and 2 for 2 player" << endl;
cin >> mode;
cout << "How many rows?" << endl;
cin >> rows;
cout << "How many columns?" << endl;
cin >> columns;

if ((mode<=0 || mode >2) || rows<= 0 || columns<= 0) {
cout << "Improper inputs. Mode must be 1/2 and rows and columns must both be >0" << endl;
playAgain();
}
else {
runGame(mode, columns, rows);
}

}
}

/******************************************************
** Function: checkGameOver
** Description: checks if game is over by recursively checking spots around original
** Parameters: board, curr col, curr row, change col, change row, total found, and what number it is looking for in the board
** Pre-Conditions:
** Post-Conditions:
******************************************************/
bool checkGameOver(int** board, int currCol, int currRow, int changeCol, int changeRow, int totalFound, int numSearch, int numRows, int numColumns) {
if (totalFound == 4) //base case
return true;
if (currRow <0 || currRow >numRows - 1 || currCol<0 || currCol> numColumns - 1)
return false;

if (board[currCol][currRow] == numSearch)
totalFound++;


else
return false; // the checked index didnt contain the same # we wanted

return checkGameOver(board, currCol + changeCol, currRow + changeRow, changeCol, changeRow, totalFound, numSearch, numRows, numColumns);
}









share|improve this question























  • None of the usual mistakes like calling srand all over the place or ignoring compiler warnings. Kudos. Any way we can get you to distill this down to an Minimal, Complete, and Verifiable example though? You should be able to isolate the bug in less than 500 lines of code.

    – user4581301
    Nov 27 '18 at 0:04














0












0








0








We have to make Connect4 in C++ as our last assignment for one of my classes. As of right now I have a fairly functional version. I had a really promising idea for a recursive solution for checking if the game is over but the issue is it only checks starting from the token it is starting at. For example if the most recently placed token has 3 of the same kind in any direction that is valid it works, but if it has 2 in one direction and 1 the opposite way it doesn't work. Does anyone have any ideas for how I could edit my function to incorporate the 2nd situation or should I just scrap it and rewrite it differently. Here is my code.



//TODO implement checking spots other than start

#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

int runGame(int, int, int);
void promptUser(int**, int, int, int, int);
void genRanMove(int**, int, int, int);
bool checkGameOver(int**, int, int, int, int, int, int, int, int);
void showBoard(int**, int, int);
void playAgain();

using namespace std;

int main(int argc, char *argv) {

if (argc < 4) {
cerr << "Not enough input, syntax is 1/2 players, # columns, and # of rows" << endl;
exit(0);
}

if (argc == 4 && (argv[1][0] == '1' || argv[1][0] == '2') && (argv[2][0] >= '1' && argv[2][0] <= '9') && (argv[3][0] >= '1' && argv[3][0] <= '9')) {
cout << "nnYou have chosen to play Connect 4 in " << argv[1][0] << " player mode and with " << argv[2][0] << " columns and with " << argv[3][0] << " rows.n" << endl;
}
else {
cerr << "Improper syntax, syntax is 1/2 players, # columns, and # of rows" << endl;
exit(0);
}

cout << "Welcome to Connect 4, each player will take a turn choosing a column to select, a metaphorical coin will fall down to the highest availible row.nThe game ends when a player has gotten 4 of their coins in a row horizontally, vertically, or diagonally.nPlayer 1 will always use 1's and Player 2 will always be 2's.nThe AI will always be 3's.nEmpty slots will be shown as 0's.nn" << endl;

srand(time(NULL));
int winner = runGame(argv[1][0] - '0', argv[2][0] - '0', argv[3][0] - '0');

if (winner == 1 || winner == 2) {
cout << "Winner was player # " << winner << endl;
}
else if (winner == 3)
cout << "You let the AI win :(" << endl;
else if (winner == -1)
cout << "The game ended in a tie" << endl;

playAgain();

}

/******************************************************
** Function: runGame
** Description: runsGame
** Parameters: gameMode columns rows
** Pre-Conditions:
** Post-Conditions: returns winning player, 1 or 2 for player # and 3 for ai
******************************************************/
int runGame(int gameMode, int columns, int rows) { //returns which player won
int holdPoints[2] = { 0, 0 };
switch (gameMode) {
case 1:
cout << "You have chosen to play against an AI" << endl;
break;
case 2:
cout << "You have chosen to play with another human player" << endl;
break;
}
int** board = new int*[columns];
for (int i = 0; i< columns; i++) {
board[i] = new int[rows];
}

for (int i = 0; i< columns; i++) {
for (int j = 0; j< rows; j++) {
board[i][j] = 0;
}
}

for (int i = 0; i< rows*columns/2; i++) { //check for number of possible moves in order to have a tie
showBoard(board, rows, columns);
promptUser(board, holdPoints, rows, columns, 1);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 1, rows, columns)) {
return 1;
}
cout << "nn";
showBoard(board, rows, columns);
if (gameMode == 2) {
promptUser(board, holdPoints, rows, columns, 2);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 2, rows, columns)) {
return 2;
}
}
else if (gameMode == 1) {
genRanMove(board, holdPoints, rows, columns);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 3, rows, columns)) {
return 3;
}
}

//showBoard(board, rows, columns);

cout << "nn";
}

for (int i = 0; i < columns; i++) {
delete board[i];
}
delete board;

return -1; //signifies a tie
}


/******************************************************
** Function: promptUser
** Description: gets input from user for their turn, stores the resting place of their token in points
** Parameters: board and array to hold point,num columns
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void promptUser(int** board, int point, int numRows, int numColumns, int playerNum) {
int col, lowZero;
lowZero = -1;
cout << "What column would you like to choose" << endl;
cin >> col;
if (col<0 || col > numColumns -1) {
cout << "The # you chose must be >=0 and <= " << numColumns-1 << endl;
promptUser(board, point, numRows, numColumns, playerNum);
}
//now need to find the lowest possible row in the given column that has a 0
for (int i = 0; i < numRows; i++) {
if (board[col][i] == 0)
lowZero = i;
}

if (lowZero != -1) {
board[col][lowZero] = playerNum;
cout << "Player " << playerNum << " dropped a token in column " << col << " that rested at row " << lowZero << endl;
point[0] = col;
point[1] = lowZero;
return;
}

else {
cout << "Column " << col << " was full, please pick a new one" << endl;
promptUser(board, point, numRows, numColumns, playerNum);
}

}

/******************************************************
** Function: genRanMove
** Description: gets random column from "ai", stores the resting place of their token in points
** Parameters: board and array to hold point
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void genRanMove(int** board, int point, int numRows, int numColumns) {
cout << "AI is finding a column" << endl;
int col = rand() % numColumns;
int lowZero = -1;

for (int i = 0; i < numRows; i++) {
if (board[col][i] == 0)
lowZero = i;
}

if (lowZero != -1) {
board[col][lowZero] = 3;
cout << "AI dropped a token in column " << col << " that rested at row " << lowZero << endl;
point[0] = col;
point[1] = lowZero;
return;
}

//didnt find a row that works
genRanMove(board, point, numRows, numColumns);

}

/******************************************************
** Function: showBoard
** Description: prints he current gameboard
** Parameters: the board, numrows and numcolumns
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void showBoard(int** board, int numRows, int numColumns) {
for (int i = 0; i < numColumns; i++) {
for (int j = 0; j < numRows; j++) {
cout << board[j][i] << " ";
}
cout << endl;
}
}

/******************************************************
** Function: playAgain
** Description: gets info to play again
** Parameters: n/a
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void playAgain() {
int again;
int mode, rows, columns;
cout << "Would you like to play again? Type 1 if so." << endl;
cin >> again;
if (again) {
cout << "What mode? 1 for 1 player and 2 for 2 player" << endl;
cin >> mode;
cout << "How many rows?" << endl;
cin >> rows;
cout << "How many columns?" << endl;
cin >> columns;

if ((mode<=0 || mode >2) || rows<= 0 || columns<= 0) {
cout << "Improper inputs. Mode must be 1/2 and rows and columns must both be >0" << endl;
playAgain();
}
else {
runGame(mode, columns, rows);
}

}
}

/******************************************************
** Function: checkGameOver
** Description: checks if game is over by recursively checking spots around original
** Parameters: board, curr col, curr row, change col, change row, total found, and what number it is looking for in the board
** Pre-Conditions:
** Post-Conditions:
******************************************************/
bool checkGameOver(int** board, int currCol, int currRow, int changeCol, int changeRow, int totalFound, int numSearch, int numRows, int numColumns) {
if (totalFound == 4) //base case
return true;
if (currRow <0 || currRow >numRows - 1 || currCol<0 || currCol> numColumns - 1)
return false;

if (board[currCol][currRow] == numSearch)
totalFound++;


else
return false; // the checked index didnt contain the same # we wanted

return checkGameOver(board, currCol + changeCol, currRow + changeRow, changeCol, changeRow, totalFound, numSearch, numRows, numColumns);
}









share|improve this question














We have to make Connect4 in C++ as our last assignment for one of my classes. As of right now I have a fairly functional version. I had a really promising idea for a recursive solution for checking if the game is over but the issue is it only checks starting from the token it is starting at. For example if the most recently placed token has 3 of the same kind in any direction that is valid it works, but if it has 2 in one direction and 1 the opposite way it doesn't work. Does anyone have any ideas for how I could edit my function to incorporate the 2nd situation or should I just scrap it and rewrite it differently. Here is my code.



//TODO implement checking spots other than start

#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

int runGame(int, int, int);
void promptUser(int**, int, int, int, int);
void genRanMove(int**, int, int, int);
bool checkGameOver(int**, int, int, int, int, int, int, int, int);
void showBoard(int**, int, int);
void playAgain();

using namespace std;

int main(int argc, char *argv) {

if (argc < 4) {
cerr << "Not enough input, syntax is 1/2 players, # columns, and # of rows" << endl;
exit(0);
}

if (argc == 4 && (argv[1][0] == '1' || argv[1][0] == '2') && (argv[2][0] >= '1' && argv[2][0] <= '9') && (argv[3][0] >= '1' && argv[3][0] <= '9')) {
cout << "nnYou have chosen to play Connect 4 in " << argv[1][0] << " player mode and with " << argv[2][0] << " columns and with " << argv[3][0] << " rows.n" << endl;
}
else {
cerr << "Improper syntax, syntax is 1/2 players, # columns, and # of rows" << endl;
exit(0);
}

cout << "Welcome to Connect 4, each player will take a turn choosing a column to select, a metaphorical coin will fall down to the highest availible row.nThe game ends when a player has gotten 4 of their coins in a row horizontally, vertically, or diagonally.nPlayer 1 will always use 1's and Player 2 will always be 2's.nThe AI will always be 3's.nEmpty slots will be shown as 0's.nn" << endl;

srand(time(NULL));
int winner = runGame(argv[1][0] - '0', argv[2][0] - '0', argv[3][0] - '0');

if (winner == 1 || winner == 2) {
cout << "Winner was player # " << winner << endl;
}
else if (winner == 3)
cout << "You let the AI win :(" << endl;
else if (winner == -1)
cout << "The game ended in a tie" << endl;

playAgain();

}

/******************************************************
** Function: runGame
** Description: runsGame
** Parameters: gameMode columns rows
** Pre-Conditions:
** Post-Conditions: returns winning player, 1 or 2 for player # and 3 for ai
******************************************************/
int runGame(int gameMode, int columns, int rows) { //returns which player won
int holdPoints[2] = { 0, 0 };
switch (gameMode) {
case 1:
cout << "You have chosen to play against an AI" << endl;
break;
case 2:
cout << "You have chosen to play with another human player" << endl;
break;
}
int** board = new int*[columns];
for (int i = 0; i< columns; i++) {
board[i] = new int[rows];
}

for (int i = 0; i< columns; i++) {
for (int j = 0; j< rows; j++) {
board[i][j] = 0;
}
}

for (int i = 0; i< rows*columns/2; i++) { //check for number of possible moves in order to have a tie
showBoard(board, rows, columns);
promptUser(board, holdPoints, rows, columns, 1);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 1, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 1, rows, columns)) {
return 1;
}
cout << "nn";
showBoard(board, rows, columns);
if (gameMode == 2) {
promptUser(board, holdPoints, rows, columns, 2);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 2, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 2, rows, columns)) {
return 2;
}
}
else if (gameMode == 1) {
genRanMove(board, holdPoints, rows, columns);
if (checkGameOver(board, holdPoints[0], holdPoints[1], 0, 1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, 0, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 0, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 0, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], 1, -1, 0, 3, rows, columns) || checkGameOver(board, holdPoints[0], holdPoints[1], -1, 1, 0, 3, rows, columns)) {
return 3;
}
}

//showBoard(board, rows, columns);

cout << "nn";
}

for (int i = 0; i < columns; i++) {
delete board[i];
}
delete board;

return -1; //signifies a tie
}


/******************************************************
** Function: promptUser
** Description: gets input from user for their turn, stores the resting place of their token in points
** Parameters: board and array to hold point,num columns
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void promptUser(int** board, int point, int numRows, int numColumns, int playerNum) {
int col, lowZero;
lowZero = -1;
cout << "What column would you like to choose" << endl;
cin >> col;
if (col<0 || col > numColumns -1) {
cout << "The # you chose must be >=0 and <= " << numColumns-1 << endl;
promptUser(board, point, numRows, numColumns, playerNum);
}
//now need to find the lowest possible row in the given column that has a 0
for (int i = 0; i < numRows; i++) {
if (board[col][i] == 0)
lowZero = i;
}

if (lowZero != -1) {
board[col][lowZero] = playerNum;
cout << "Player " << playerNum << " dropped a token in column " << col << " that rested at row " << lowZero << endl;
point[0] = col;
point[1] = lowZero;
return;
}

else {
cout << "Column " << col << " was full, please pick a new one" << endl;
promptUser(board, point, numRows, numColumns, playerNum);
}

}

/******************************************************
** Function: genRanMove
** Description: gets random column from "ai", stores the resting place of their token in points
** Parameters: board and array to hold point
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void genRanMove(int** board, int point, int numRows, int numColumns) {
cout << "AI is finding a column" << endl;
int col = rand() % numColumns;
int lowZero = -1;

for (int i = 0; i < numRows; i++) {
if (board[col][i] == 0)
lowZero = i;
}

if (lowZero != -1) {
board[col][lowZero] = 3;
cout << "AI dropped a token in column " << col << " that rested at row " << lowZero << endl;
point[0] = col;
point[1] = lowZero;
return;
}

//didnt find a row that works
genRanMove(board, point, numRows, numColumns);

}

/******************************************************
** Function: showBoard
** Description: prints he current gameboard
** Parameters: the board, numrows and numcolumns
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void showBoard(int** board, int numRows, int numColumns) {
for (int i = 0; i < numColumns; i++) {
for (int j = 0; j < numRows; j++) {
cout << board[j][i] << " ";
}
cout << endl;
}
}

/******************************************************
** Function: playAgain
** Description: gets info to play again
** Parameters: n/a
** Pre-Conditions:
** Post-Conditions:
******************************************************/
void playAgain() {
int again;
int mode, rows, columns;
cout << "Would you like to play again? Type 1 if so." << endl;
cin >> again;
if (again) {
cout << "What mode? 1 for 1 player and 2 for 2 player" << endl;
cin >> mode;
cout << "How many rows?" << endl;
cin >> rows;
cout << "How many columns?" << endl;
cin >> columns;

if ((mode<=0 || mode >2) || rows<= 0 || columns<= 0) {
cout << "Improper inputs. Mode must be 1/2 and rows and columns must both be >0" << endl;
playAgain();
}
else {
runGame(mode, columns, rows);
}

}
}

/******************************************************
** Function: checkGameOver
** Description: checks if game is over by recursively checking spots around original
** Parameters: board, curr col, curr row, change col, change row, total found, and what number it is looking for in the board
** Pre-Conditions:
** Post-Conditions:
******************************************************/
bool checkGameOver(int** board, int currCol, int currRow, int changeCol, int changeRow, int totalFound, int numSearch, int numRows, int numColumns) {
if (totalFound == 4) //base case
return true;
if (currRow <0 || currRow >numRows - 1 || currCol<0 || currCol> numColumns - 1)
return false;

if (board[currCol][currRow] == numSearch)
totalFound++;


else
return false; // the checked index didnt contain the same # we wanted

return checkGameOver(board, currCol + changeCol, currRow + changeRow, changeCol, changeRow, totalFound, numSearch, numRows, numColumns);
}






c++ g++






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 26 '18 at 23:48









jackattack825jackattack825

94




94













  • None of the usual mistakes like calling srand all over the place or ignoring compiler warnings. Kudos. Any way we can get you to distill this down to an Minimal, Complete, and Verifiable example though? You should be able to isolate the bug in less than 500 lines of code.

    – user4581301
    Nov 27 '18 at 0:04



















  • None of the usual mistakes like calling srand all over the place or ignoring compiler warnings. Kudos. Any way we can get you to distill this down to an Minimal, Complete, and Verifiable example though? You should be able to isolate the bug in less than 500 lines of code.

    – user4581301
    Nov 27 '18 at 0:04

















None of the usual mistakes like calling srand all over the place or ignoring compiler warnings. Kudos. Any way we can get you to distill this down to an Minimal, Complete, and Verifiable example though? You should be able to isolate the bug in less than 500 lines of code.

– user4581301
Nov 27 '18 at 0:04





None of the usual mistakes like calling srand all over the place or ignoring compiler warnings. Kudos. Any way we can get you to distill this down to an Minimal, Complete, and Verifiable example though? You should be able to isolate the bug in less than 500 lines of code.

– user4581301
Nov 27 '18 at 0:04












1 Answer
1






active

oldest

votes


















0















... or should I just scrap it and rewrite it differently?




That's the option I'd be going for :-)



While a recursive solution may be clever, you're probably better off, for a game-space of this size, keeping the code simple and just checking every single possibility rather than trying to recurse out from the newly-populated cell(a).



You can do this in "specialist" chunks so you don't have to worry about going off the edge of the board at any point. To do this, you limit the starting cell for each type so that it ends on an edge cell of the board, something like (pseudo-code):



# Check four cells given start and direction.

def didWin(row, col, rdelta, cdelta):
# Check if start cell not populated.

if cell[row][col] == empty:
return false

# Check if any cell in sequence doesn't match.

for i = 1 to 3 inclusive:
if cell[row][col] != cell[row+rdelta*i][col+cdelta*i]:
return false

# Otherwise, it's a win

return true

def getWinner():
# Check all possible horizontals.

for row = 0 to 5 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 0, 1): # cdelta=1, right.
return cell[row][col]

# Check all possible verticals.

for col = 0 to 6 inclusive:
for row = 0 to 2 inclusive:
if didWin(row, col, 1, 0): # rdelta=1, down.
return cell[row][col]

# Check all right-downs.

for row = 0 to 2 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 1, 1): # r/cdelta=1, right-down.
return cell[row][col]

# Check all right-ups.

for row = 3 to 5 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 1, -1): # rdelta=1, cdelta=-1, right-up.
return cell[row][col]

# No winner.

return empty




(a)Another good reason for doing this is that, in an educational institution, they almost always value clarity of thought over cleverness. That clarity of thought will serve you well in the start of your career and, indeed, forty years into your career, such as where I am :-)






share|improve this answer


























  • thanks for your response, I edited my code and implemented your solution and am getting segfaults, im wondering if its because the numbers u chose for the for loops in getWinner() need to loop thru for the amount of rows and columns rather than the constant numbers you put in the pseudo code

    – jackattack825
    Nov 27 '18 at 2:11













  • EDIT: your solution worked tysm, the segmentation fault only seems to occur when I or the AI chooses the last column in the board, hopefully i can figure it out on my own

    – jackattack825
    Nov 27 '18 at 2:25











  • @jackattack825, you may be right, I've just noticed your code allows for a variable number of rows and columns whereas mine was tailored for the specific 7column-by-6row Connect-4 game.

    – paxdiablo
    Nov 27 '18 at 3:08











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53490778%2fhow-can-i-fix-my-c-connect4-checkgameover-function%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









0















... or should I just scrap it and rewrite it differently?




That's the option I'd be going for :-)



While a recursive solution may be clever, you're probably better off, for a game-space of this size, keeping the code simple and just checking every single possibility rather than trying to recurse out from the newly-populated cell(a).



You can do this in "specialist" chunks so you don't have to worry about going off the edge of the board at any point. To do this, you limit the starting cell for each type so that it ends on an edge cell of the board, something like (pseudo-code):



# Check four cells given start and direction.

def didWin(row, col, rdelta, cdelta):
# Check if start cell not populated.

if cell[row][col] == empty:
return false

# Check if any cell in sequence doesn't match.

for i = 1 to 3 inclusive:
if cell[row][col] != cell[row+rdelta*i][col+cdelta*i]:
return false

# Otherwise, it's a win

return true

def getWinner():
# Check all possible horizontals.

for row = 0 to 5 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 0, 1): # cdelta=1, right.
return cell[row][col]

# Check all possible verticals.

for col = 0 to 6 inclusive:
for row = 0 to 2 inclusive:
if didWin(row, col, 1, 0): # rdelta=1, down.
return cell[row][col]

# Check all right-downs.

for row = 0 to 2 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 1, 1): # r/cdelta=1, right-down.
return cell[row][col]

# Check all right-ups.

for row = 3 to 5 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 1, -1): # rdelta=1, cdelta=-1, right-up.
return cell[row][col]

# No winner.

return empty




(a)Another good reason for doing this is that, in an educational institution, they almost always value clarity of thought over cleverness. That clarity of thought will serve you well in the start of your career and, indeed, forty years into your career, such as where I am :-)






share|improve this answer


























  • thanks for your response, I edited my code and implemented your solution and am getting segfaults, im wondering if its because the numbers u chose for the for loops in getWinner() need to loop thru for the amount of rows and columns rather than the constant numbers you put in the pseudo code

    – jackattack825
    Nov 27 '18 at 2:11













  • EDIT: your solution worked tysm, the segmentation fault only seems to occur when I or the AI chooses the last column in the board, hopefully i can figure it out on my own

    – jackattack825
    Nov 27 '18 at 2:25











  • @jackattack825, you may be right, I've just noticed your code allows for a variable number of rows and columns whereas mine was tailored for the specific 7column-by-6row Connect-4 game.

    – paxdiablo
    Nov 27 '18 at 3:08
















0















... or should I just scrap it and rewrite it differently?




That's the option I'd be going for :-)



While a recursive solution may be clever, you're probably better off, for a game-space of this size, keeping the code simple and just checking every single possibility rather than trying to recurse out from the newly-populated cell(a).



You can do this in "specialist" chunks so you don't have to worry about going off the edge of the board at any point. To do this, you limit the starting cell for each type so that it ends on an edge cell of the board, something like (pseudo-code):



# Check four cells given start and direction.

def didWin(row, col, rdelta, cdelta):
# Check if start cell not populated.

if cell[row][col] == empty:
return false

# Check if any cell in sequence doesn't match.

for i = 1 to 3 inclusive:
if cell[row][col] != cell[row+rdelta*i][col+cdelta*i]:
return false

# Otherwise, it's a win

return true

def getWinner():
# Check all possible horizontals.

for row = 0 to 5 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 0, 1): # cdelta=1, right.
return cell[row][col]

# Check all possible verticals.

for col = 0 to 6 inclusive:
for row = 0 to 2 inclusive:
if didWin(row, col, 1, 0): # rdelta=1, down.
return cell[row][col]

# Check all right-downs.

for row = 0 to 2 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 1, 1): # r/cdelta=1, right-down.
return cell[row][col]

# Check all right-ups.

for row = 3 to 5 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 1, -1): # rdelta=1, cdelta=-1, right-up.
return cell[row][col]

# No winner.

return empty




(a)Another good reason for doing this is that, in an educational institution, they almost always value clarity of thought over cleverness. That clarity of thought will serve you well in the start of your career and, indeed, forty years into your career, such as where I am :-)






share|improve this answer


























  • thanks for your response, I edited my code and implemented your solution and am getting segfaults, im wondering if its because the numbers u chose for the for loops in getWinner() need to loop thru for the amount of rows and columns rather than the constant numbers you put in the pseudo code

    – jackattack825
    Nov 27 '18 at 2:11













  • EDIT: your solution worked tysm, the segmentation fault only seems to occur when I or the AI chooses the last column in the board, hopefully i can figure it out on my own

    – jackattack825
    Nov 27 '18 at 2:25











  • @jackattack825, you may be right, I've just noticed your code allows for a variable number of rows and columns whereas mine was tailored for the specific 7column-by-6row Connect-4 game.

    – paxdiablo
    Nov 27 '18 at 3:08














0












0








0








... or should I just scrap it and rewrite it differently?




That's the option I'd be going for :-)



While a recursive solution may be clever, you're probably better off, for a game-space of this size, keeping the code simple and just checking every single possibility rather than trying to recurse out from the newly-populated cell(a).



You can do this in "specialist" chunks so you don't have to worry about going off the edge of the board at any point. To do this, you limit the starting cell for each type so that it ends on an edge cell of the board, something like (pseudo-code):



# Check four cells given start and direction.

def didWin(row, col, rdelta, cdelta):
# Check if start cell not populated.

if cell[row][col] == empty:
return false

# Check if any cell in sequence doesn't match.

for i = 1 to 3 inclusive:
if cell[row][col] != cell[row+rdelta*i][col+cdelta*i]:
return false

# Otherwise, it's a win

return true

def getWinner():
# Check all possible horizontals.

for row = 0 to 5 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 0, 1): # cdelta=1, right.
return cell[row][col]

# Check all possible verticals.

for col = 0 to 6 inclusive:
for row = 0 to 2 inclusive:
if didWin(row, col, 1, 0): # rdelta=1, down.
return cell[row][col]

# Check all right-downs.

for row = 0 to 2 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 1, 1): # r/cdelta=1, right-down.
return cell[row][col]

# Check all right-ups.

for row = 3 to 5 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 1, -1): # rdelta=1, cdelta=-1, right-up.
return cell[row][col]

# No winner.

return empty




(a)Another good reason for doing this is that, in an educational institution, they almost always value clarity of thought over cleverness. That clarity of thought will serve you well in the start of your career and, indeed, forty years into your career, such as where I am :-)






share|improve this answer
















... or should I just scrap it and rewrite it differently?




That's the option I'd be going for :-)



While a recursive solution may be clever, you're probably better off, for a game-space of this size, keeping the code simple and just checking every single possibility rather than trying to recurse out from the newly-populated cell(a).



You can do this in "specialist" chunks so you don't have to worry about going off the edge of the board at any point. To do this, you limit the starting cell for each type so that it ends on an edge cell of the board, something like (pseudo-code):



# Check four cells given start and direction.

def didWin(row, col, rdelta, cdelta):
# Check if start cell not populated.

if cell[row][col] == empty:
return false

# Check if any cell in sequence doesn't match.

for i = 1 to 3 inclusive:
if cell[row][col] != cell[row+rdelta*i][col+cdelta*i]:
return false

# Otherwise, it's a win

return true

def getWinner():
# Check all possible horizontals.

for row = 0 to 5 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 0, 1): # cdelta=1, right.
return cell[row][col]

# Check all possible verticals.

for col = 0 to 6 inclusive:
for row = 0 to 2 inclusive:
if didWin(row, col, 1, 0): # rdelta=1, down.
return cell[row][col]

# Check all right-downs.

for row = 0 to 2 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 1, 1): # r/cdelta=1, right-down.
return cell[row][col]

# Check all right-ups.

for row = 3 to 5 inclusive:
for col = 0 to 3 inclusive:
if didWin(row, col, 1, -1): # rdelta=1, cdelta=-1, right-up.
return cell[row][col]

# No winner.

return empty




(a)Another good reason for doing this is that, in an educational institution, they almost always value clarity of thought over cleverness. That clarity of thought will serve you well in the start of your career and, indeed, forty years into your career, such as where I am :-)







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 27 '18 at 0:33

























answered Nov 27 '18 at 0:07









paxdiablopaxdiablo

636k17212531675




636k17212531675













  • thanks for your response, I edited my code and implemented your solution and am getting segfaults, im wondering if its because the numbers u chose for the for loops in getWinner() need to loop thru for the amount of rows and columns rather than the constant numbers you put in the pseudo code

    – jackattack825
    Nov 27 '18 at 2:11













  • EDIT: your solution worked tysm, the segmentation fault only seems to occur when I or the AI chooses the last column in the board, hopefully i can figure it out on my own

    – jackattack825
    Nov 27 '18 at 2:25











  • @jackattack825, you may be right, I've just noticed your code allows for a variable number of rows and columns whereas mine was tailored for the specific 7column-by-6row Connect-4 game.

    – paxdiablo
    Nov 27 '18 at 3:08



















  • thanks for your response, I edited my code and implemented your solution and am getting segfaults, im wondering if its because the numbers u chose for the for loops in getWinner() need to loop thru for the amount of rows and columns rather than the constant numbers you put in the pseudo code

    – jackattack825
    Nov 27 '18 at 2:11













  • EDIT: your solution worked tysm, the segmentation fault only seems to occur when I or the AI chooses the last column in the board, hopefully i can figure it out on my own

    – jackattack825
    Nov 27 '18 at 2:25











  • @jackattack825, you may be right, I've just noticed your code allows for a variable number of rows and columns whereas mine was tailored for the specific 7column-by-6row Connect-4 game.

    – paxdiablo
    Nov 27 '18 at 3:08

















thanks for your response, I edited my code and implemented your solution and am getting segfaults, im wondering if its because the numbers u chose for the for loops in getWinner() need to loop thru for the amount of rows and columns rather than the constant numbers you put in the pseudo code

– jackattack825
Nov 27 '18 at 2:11







thanks for your response, I edited my code and implemented your solution and am getting segfaults, im wondering if its because the numbers u chose for the for loops in getWinner() need to loop thru for the amount of rows and columns rather than the constant numbers you put in the pseudo code

– jackattack825
Nov 27 '18 at 2:11















EDIT: your solution worked tysm, the segmentation fault only seems to occur when I or the AI chooses the last column in the board, hopefully i can figure it out on my own

– jackattack825
Nov 27 '18 at 2:25





EDIT: your solution worked tysm, the segmentation fault only seems to occur when I or the AI chooses the last column in the board, hopefully i can figure it out on my own

– jackattack825
Nov 27 '18 at 2:25













@jackattack825, you may be right, I've just noticed your code allows for a variable number of rows and columns whereas mine was tailored for the specific 7column-by-6row Connect-4 game.

– paxdiablo
Nov 27 '18 at 3:08





@jackattack825, you may be right, I've just noticed your code allows for a variable number of rows and columns whereas mine was tailored for the specific 7column-by-6row Connect-4 game.

– paxdiablo
Nov 27 '18 at 3:08




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53490778%2fhow-can-i-fix-my-c-connect4-checkgameover-function%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Lallio

Futebolista

Jornalista