Stuck at 4 in a row game, checking who is the winner

(First of all I am sorry for any miss spelled in my writting)
Hello, I have been programming the little mini game 4 in a row, where i have 6 colums and 7 Row Tabel(variable Tabel[6][7]) . There are only two players with their game "Stones" one being 'X' and the other being 'O'. The game stars with player one and then goes on to player two. The console gives out a small recreation of the 4 in a row table, and the player has to decide in which Row from 0-6 he wants to "throw" his Stone. The programm also check that if one Array space has already an 'X' or a 'O' it moves the stone to one higher. But my problems begins here, I am stuck at how to check who is the winner of the game. I don't know how to make the programm check if there are 4 'X' or 'O' in a Row (void CheckWinner(void) ). I have only tried with 'X' but i can't see to get the winner.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//4 in a row
using namespace std; 
#include <iostream>
#include <string.h>


class FourWins
{
public:
struct Player
{
	string name;
	char Stone[2]={'X','0'};
}Player[2];
public:
int K=1; 
public:
int L; 
public:
char Tabel[6][7]={};

public:
void PlayerNameInput(void)
{
	for(int x=0; x<2; x++)
	{
		cout<<"Please Player"<<x+1<<" write your name"<<endl;
		cin>>Player[x].name;
	}
}

public:
void TableOutput(void) 
{	
	for (int i=5; i>=0; i--)
	{
	for(int x=0; x<7; x++)
	{
		cout<<"|"<<Tabel[i][x]<<"|";
	}
	cout<<endl;
	}
	cout<<endl<<"Row: "<<endl; 
	cout<<" 0  1  2  3  4  5  6 "<<endl;
}

public:
void TableRowInput(void) 
{
	int a, b=0, c=1;
	cout<<Player[L].name<<" Turn"<<endl;
	cout<<"choose your row"<<endl;
	cin>>a;
	while(c<=1)
	{
		if(Tabel[b][a]==0)
		{
			Tabel[b][a]=Player[L].Stone[L];
			c=c+1;
			cout<<c<<endl;
		}
		else
		{
		b=b+1;	
		}
	}
	system("cls");
}

public:
void CheckWinner(void)
{
	int CW=0; 
	for(int g=0; g<6; g++)
	{
		for(int h=0; h<7; h++)
		{
			if(Tabel[g][h]=='X')
			{
			CW=CW+1;
			}
			else
			{
			CW=0;	
			}
		}
		if(CW==4)
		{
		cout<<Player[0].name<<" has won"<<endl;	
		break;
		K=K+5;	
		}
	}
}

public:
void Mainn(void)
{
	PlayerNameInput();
	
	while(K<=1)
	{
	L=0;	//player 1
 	TabelOutput();
 	TabelRowInput();
 	CheckWinner();
 	L=1; //player 2
 	TabelOutput();
 	TabelRowInput();
 	CheckWinner();
 	
	}	
}
};
     				
int main()//main programm
{	
	FourWins game;
	game.Mainn();
}
Last edited on
Hello Nickoblack.

I can't currently help you as i don't understand your question:
- What is the game your trying to make ?
- What are the rules ?

A few tips when asking this website:
1) Write a more descriptive title because
Stuck at 4 in a row game
doesn't describe the problem you have.
2) Describe the problem in details.
3) Paste only the code that is relevant - all commented code should be discarded if it doesn't have anything to do with your question.

A few tips for structuring a program:
1) Each variable, function, class or struct should have a meaningful name (And in English).
2) Code should be separated into .h and .cpp files.
3) Don't use comments to describe what your code does unless it's and algorithm and even that you will need to explain fully what the algorithm does.
Last edited on
Hello globaltourist,

I have edit the post, hopefully it is more clear that it used to be.
I appreciate your advices that i will keep in mind for future post.
I think i understand what your trying to achieve.
I will recreate it and post my version here, also I'l comment why I did it the way I do.
NOTE: I will give you a few tips when writing games so you wont run into this problem in the future.
checkwinner should only check the most recent move to see if it created a winning move. Computers are fast enough that it does not matter if you check the whole board every time, but this sort of thing is critical for more complex games.
@jonnin Im rewriting it with the MVC pattern and i comment it heavily so he can easily understand it for when he wants to move on to larger projects, I also add tips and resources for him to visit and learn from because most of his practices currently are plain wrong.
@Nickoblack im about to finish my rework for your program i just wanted to point out that you confused rows and cols, your program checks for 4 stones in a col and you called it a row
Firstly I would recommend you the following resources for getting more knowledge of the language:
http://www.cplusplus.com/forum/articles/10627/
https://www.tutorialspoint.com/cplusplus/cpp_multi_dimensional_arrays.htm
http://www.learncpp.com/

Secondly I will recommend you to use https://www.hackerrank.com/domains/algorithms/warmup
for exercise.

Now for the code i wrote for you.
Iv'e used the MVC (model-view-controll) pattern to decouple the code as much as possible and I recommend you google it and learn more.
Also visit https://sourcemaking.com/, it is a great resource to learn code architecture from and it has plenty of examples and explanations.

game_view.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef GAME_VIEW_H
#define GAME_VIEW_H

#include <array>  //prefer std::array to raw arrays
#include <string>

#define ROWS 7
#define COLS 6

//using namespace std; <-- *DONT EVER USE THIS*
using std::string; //<--explicitly state what your using instead
using std::array;  //<--explicitly state what your using instead

class GameView final
{
public:
	//allways pass std:: objects by const& if you don't intend on changing their content,
	//standard types such as: int, short, char, long etc.. should be passed by value unless you want to change their values
	//in which case you can by by & (without const)
	//go to: http://www.learncpp.com/ and read chapters 7.1 to 7.4a (ideally read all of the guide).
	//I wont do it here because it might be a bit more advanced but you should mark all functions that dont
	//modify member variables as const.
	void printStones(array<array<char, COLS>, ROWS> const& table);   
	void printPlayerTurn(string const& player_name);                 
	void printWinner(string const& name);			
	void askPlayerName(int player_num);
	void printEndMessage();
	void printGameBoard();
	void printTie();
};

#endif 


game_view.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "game_view.h"

#include <Windows.h> //for gotoxy function (although you should avoid this library if you want portable code)
#include <iostream>  //for std::cout

//using namespace std; <-- *DONT EVER USE THIS*
using std::cout;         //<--explicitly state what your using instead

#define TABLE_VIEW_WIDTH  35
#define TABLE_VIEW_HEIGHT 23
#define FIRST_CELL_X      12
#define FIRST_CELL_Y       6
#define WIDTH_PAD          4  
#define HEIGHT_PAD         2

#define END_GAME_Y 24
#define END_GAME_X  0

#define STATEBOX_Y 21
#define STATEBOX_X  1

#define TURN_Y 1
#define TURN_X 1

#define BOARD_Y 0
#define BOARD_X 0

namespace details {
	struct Position
	{
		int x;
		int y;
	};

	struct Dimentions
	{
		int height;
		int width;
	};

	void gotoxy(Position pos) {
		COORD coord{ static_cast<short>(pos.x), static_cast<short>(pos.y) };
		SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
	}

	void loadString(string const& str, Dimentions size, Position pos)
	{
		for (int y{}; y < size.height; ++y) {
			for (int x{}; x < size.width; ++x) {
				gotoxy({ pos.x + x, pos.y + y });
				cout << str[y * size.width + x];
			}
		}
	}

	const string game_board
	{
		"+---------------------------------+"
		"|                                 |"
		"+---------------------------------+"
		"+---------+---+---+---+---+---+---+"
		"|ROWS/COLS| 0 | 1 | 2 | 3 | 4 | 5 |"
		"+---------+---+---+---+---+---+---+"
		"|    0    |   |   |   |   |   |   |"
		"+---------+---+---+---+---+---+---+"
		"|    1    |   |   |   |   |   |   |"
		"+---------+---+---+---+---+---+---+"
		"|    2    |   |   |   |   |   |   |"
		"+---------+---+---+---+---+---+---+"
		"|    3    |   |   |   |   |   |   |"
		"+---------+---+---+---+---+---+---+"
		"|    4    |   |   |   |   |   |   |"
		"+---------+---+---+---+---+---+---+"
		"|    5    |   |   |   |   |   |   |"
		"+---------+---+---+---+---+---+---+"
		"|    6    |   |   |   |   |   |   |"
		"+---------+---+---+---+---+---+---+"
		"+---------------------------------+"
		"|                                 |"
		"+---------------------------------+"
	};
}

void GameView::printStones(array<array<char, COLS>, ROWS> const& table)
{
	for (int y{}; y < ROWS; ++y) {
		for (int x{}; x < COLS; ++x) {
			details::gotoxy({ x * WIDTH_PAD + FIRST_CELL_X, y * HEIGHT_PAD + FIRST_CELL_Y });
			cout << table[y][x];
		}
	}
}

void GameView::printPlayerTurn(string const& player_name)
{
	details::gotoxy({ TURN_X, TURN_Y });
	cout << "                                 ";  
	details::gotoxy({ TURN_X, TURN_Y });
	cout << " Player " << player_name << "\'s turn"; 
}

void GameView::printWinner(string const& name)
{
	details::gotoxy({ STATEBOX_X, STATEBOX_Y });
	cout << " Player " << name << " won!"; 
}

void GameView::askPlayerName(int player_num)
{
	cout << "Player " << player_num << " please enter your name (18 symbols max): ";
}

void GameView::printEndMessage()
{
	details::gotoxy({ END_GAME_X, END_GAME_Y });
	//use at the end of the game
	//console will print : "Press any button to continue" by default
}

void GameView::printGameBoard()
{
	details::loadString(details::game_board, { TABLE_VIEW_HEIGHT, TABLE_VIEW_WIDTH }, {BOARD_X, BOARD_Y});
}

void GameView::printTie()
{
	details::gotoxy({ STATEBOX_X, STATEBOX_Y });
	cout << " game ended with a tie";
}
game_model.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#ifndef GAME_MODEL_H
#define GAME_MODEL_H

#include <array>  //prefer std::array to raw arrays
#include <string>

#define ROWS 7
#define COLS 6

#define PLAYERS 2

//using namespace std; <-- *DONT EVER USE THIS*
using std::string; //<--explicitly state what your using instead
using std::array;  //<--explicitly state what your using instead

class GameModel final
{
public:
	GameModel();

	array<array<char, COLS>, ROWS> const& getStoneTable();
	std::string const& getCurrentPlayerName();
	int  addStone(int col, char stone);
	bool setPlayerName(int player_num);
	bool hasWon(int row, char stone);
	bool getCurrentPlayerTurn();
	void nextPlayerTurn();
	bool checkForTie();

private:
	bool                           player_turn_{ false };
	array<std::string, PLAYERS>    player_;
	array<array<char, COLS>, ROWS> table_;
};

#endif  


game_model.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include "game_model.h"

#include <iostream>

#define MAX_NAME_LENGTH 18
#define FOUR_IN_A_ROW    4

using std::getline;
using std::cin;

GameModel::GameModel()
	: table_
	{ {{ ' ', ' ', ' ', ' ', ' ', ' ' },
	   { ' ', ' ', ' ', ' ', ' ', ' ' },
	   { ' ', ' ', ' ', ' ', ' ', ' ' },
	   { ' ', ' ', ' ', ' ', ' ', ' ' },
	   { ' ', ' ', ' ', ' ', ' ', ' ' },
  	 { ' ', ' ', ' ', ' ', ' ', ' ' },
	   { ' ', ' ', ' ', ' ', ' ', ' ' }} }
{
}

array<array<char, COLS>, ROWS> const & GameModel::getStoneTable()
{
	return table_;
}

std::string const & GameModel::getCurrentPlayerName()
{
	return player_[player_turn_];
}

int GameModel::addStone(int col, char stone)
{
	for (int row{ ROWS - 1 }; row >= 0; --row) 
		if (table_[row][col] == ' ') {
			table_[row][col] = stone;
			return row;
		}
	return -1;
}

bool GameModel::setPlayerName(int player_num)
{
	std::string name;
	getline(cin, name);
	if (name.size() > MAX_NAME_LENGTH || name == "")
		return false;
	else if (player_[0] == name)
		return false;
	player_[player_num] = name;
	return true;
}

bool GameModel::hasWon(int row, char stone)
{
	int same_stones{};
	for (int col{}; col < COLS; ++col) {
		if (table_[row][col] == stone) {
			if (++same_stones == FOUR_IN_A_ROW)
				return true;
		}
		else
			same_stones = 0;
	}
	return false;
}

bool GameModel::getCurrentPlayerTurn()
{
	return player_turn_;
}

void GameModel::nextPlayerTurn()
{
	player_turn_ ? player_turn_ = false : player_turn_ = true;
}

bool GameModel::checkForTie()
{
	for (int row{}; row < ROWS; ++row)
		for (int col{}; col < COLS; ++col)
			if (table_[row][col] == ' ')
				return false;
	return true;
}


game_controller.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef GAME_CONTROLLER_H
#define GAME_CONTROLLER_H

#include "game_model.h"
#include "game_view.h"

class GameController final
{
public:
	GameController(GameModel& model, GameView&  view);

	void execute();
	void onLoad();

private:
	GameModel& model_;
	GameView&  view_;

	void readPlayerName(int player_num);
	int getColFromPlayer();
};

#endif  


game_controller.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "game_controller.h"

#include <array>
#include <conio.h>
#include <Windows.h>

GameController::GameController(GameModel & model, GameView & view)
	:model_{ model }, view_{ view }
{
}

void GameController::execute()
{
	std::array<char, 2> stones{ 'X', 'O' };
	bool gameInProgress{ true };
	while (gameInProgress) {
		view_.printPlayerTurn(model_.getCurrentPlayerName());
		int row;
		do {
			int col = getColFromPlayer();
			row = model_.addStone(col, stones[model_.getCurrentPlayerTurn()]);
		} while (row == -1);
		view_.printStones(model_.getStoneTable());
		if (model_.hasWon(row, stones[model_.getCurrentPlayerTurn()])) {
			view_.printWinner(model_.getCurrentPlayerName());
			view_.printEndMessage();
			gameInProgress = false;
		}
		else if (model_.checkForTie()) {
			view_.printTie();
			view_.printEndMessage();
			gameInProgress = false;
		}
		else 
			model_.nextPlayerTurn();
	}
}

void GameController::onLoad()
{
	int player_num{ 0 };
	readPlayerName(player_num++);
	readPlayerName(player_num);
	system("cls");
	view_.printGameBoard();
}

void GameController::readPlayerName(int player_num)
{
	do {
		view_.askPlayerName(player_num);
	} while (!model_.setPlayerName(player_num));
}

int GameController::getColFromPlayer()
{
	int input;
	do {
		 input = _getch();
	} while (input < '0' || input > '5');
	return input - '0'; 
}


source.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "game_controller.h"
#include "game_model.h"
#include "game_view.h"

//anyway i wouldn't recomment you to use the native windows.h as a beginner, i will recomment you
//ncurses if you use linux and pdcurses if you use windows, and that is only if you want to make 
//console stuff otherwise learn something like openCV for graphics

int main()
{
	GameModel model; //game data
	GameView  view;  //the way the data is displayed

	GameController controller{ model, view }; //acts like an adaptor/glue between view and model
	controller.onLoad(); //called once 
	controller.execute();//contains game loop
	return 0;
}
Topic archived. No new replies allowed.