How can I fix my C++ Connect4 checkGameOver Function
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++
add a comment |
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++
None of the usual mistakes like callingsrandall 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
add a comment |
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++
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++
c++ g++
asked Nov 26 '18 at 23:48
jackattack825jackattack825
94
94
None of the usual mistakes like callingsrandall 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
add a comment |
None of the usual mistakes like callingsrandall 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
add a comment |
1 Answer
1
active
oldest
votes
... 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 :-)
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
... 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 :-)
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
add a comment |
... 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 :-)
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
add a comment |
... 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 :-)
... 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 :-)
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
None of the usual mistakes like calling
srandall 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