# Need help w/2d array game function

• 11-10-2001
cpp4ever
Need help w/2d array game function
Hello,

I am writing a Connect-4 computer game based on the classic "board game." It is written in C++ as a Console Mode program. For those that don't know, you have a 7x6 "board" filled with empty slots.

000000
000000
000000
000000
000000
000000
000000

It is a 2 player game where each player (let's use symbols 1 and 2 respectively) tries to connect 4 of their markers in a variety of ways. For example:

EXAMPLE 1 EXAMPLE 2 EXAMPLE 3
000000 000000 000000
000000 020000 010020
111100 002000 020020
000000 000200 000020
000000 000020 000020
000000 000000 000000
000000 000000 000000

Get the picture? Pretty simple? :) My question is: what routine would I write to check if player 1 or 2 is the winner and how would I implement it? I used a "brute force" routine for Tic-Tac-Toe (only 3x3; just took awhile to code), but I don't want this to take quite so much work. ;) Any suggestions?

Thx for your help!,

cpp4ever
• 11-10-2001
Leeman_s
Yes
I did the same thing for my tic tac toe game, and now i'm going to do connect 4 and battleship. you can make the win checking a lot easier with loops. Here is how I did it in tic tac toe:

{
int w;
char d;
for(int p=1;p<=2;p++)
{
if(p==2)
{
d='O';
w=2;
}
for(int g=1;g<4;g++)
{
if(board[1][g]==d && board[2][g]==d && board[3][g]==d)
{
win=w;
}
}
for(int t=1;t<4;t++)
{
if(board[t][1]==d && board[t][2]==d && board[t][3]==d)
{
win=w;
}
}
if(board[1][1]==d && board[2][2]==d && board[3][3]==d)
{
win=w;
}
if(board[3][1]==d && board[2][2]==d && board[1][3]==d)
{
win=w;
}
}
}

Thats all i have to say.
• 11-10-2001
Leeman_s
ok
ok I thought of a way. Do this:

for(int g=1;g<=7;g++)
if(board[g][z]=='X' && board[g][(z-1)]=='X' &&
board[g][(z-2)]=='X' && board[g][(z-3)]=='X'){
win=1;
}

ok that would check for all horizontal wins. Do you get what im saying? Then you do the similar for vertical and... diagonal would be harder. This is assuming your array for the board is board. And you use g and z for the row and column. And um if you use it, say "and a special thanks to leeman_s". Hehe. I'm serious.
• 11-10-2001
ender
ok, excuse me for being blunt...I will use the excuse that I am a bit intoxicated (which makes it hard to type) but what I see is crap...... so, the right answer, well no right answers, but a good solution: recursion

Use a recursive fuction that checks up, down, diagonol (wow, I don't know how to spell), left, right... remind me in the morning and I'll write the code for you if you don't know how to. Good night ....yawn :o
• 11-10-2001
The V.
Why not just check to see if the last piece played won the game? You need to check much fewer cases then -- and the game can only be won after any turn if that piece won the game.
• 11-10-2001
cpp4ever
Yes, if you have time post code
Ender,

I trust you are feeling well this morning? >:) Anyways, if you have time to write the code it would be much appreciated. I am compiling the responses right now to test all answers, so yours would be appreciated if/when you have the time. ;)

Thanks
• 11-10-2001
ender
after a few glasses of water my head has cleared up a bit.... ok 2 things

yes, checking the last pieced played would be a given, BUT, and that was a big but, do you want ai? If you do, this is where I would have the ai "strategize"...look for block, look for an opening that gave them, etc

now, the checking part...

Not sure how you have your board set up...you say an array, but I would probably make it atleast a struct, class would be better.
I think I'm going to write a separate slot class that has a tree style to it where each slot has pointers to its adjacent slots, then you can recursively check each one of those, passing a count each time...when you get a count of 4, return true, otherwise return false, something like that.....like this

class Slot {
public:

Slot();
bool getState() {return state;}

private:

bool state;
Slot *left, *right, *up, *down, *duleft, *duright, *ddleft, *ddright;
// dd = diagonally down, du = diagonally up
}

Slot::Slot() {

state = false;
left = right = up = down = duleft = duright = ddleft = ddright = NULL;
}

bool Slot::checkAdjacent(int dir) {

switch( dir ) {
case LEFT: if(left = NULL) return false;
return left->getState();
case RIGHT: if(right = NULL) return false;
return right->getState();

... it just occured to me, that since I defind the directions below, I could just have an array of slot pointers for the adjacent slots, but I'm not rewriting all this, you can do that.

ie. class Slot {
...
...
private:

I'm going to assume a board class with atleast the following:
(Oh yeah, defining the 8 possible directions, you'll need those...but I'm sure you have those already)
const int UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3, DULEFT = 4, DURIGHT = 5,
DDLEFT = 6, DDRIGHT = 7,

ROWS = 7, COLUMNS = 6;

class Board {
public:

Board();
bool checkDir(slot *s,int x,int y)
bool checkWin(int x, int y);

private:

slot *board[COLUMNS][ROWS]; // This makes checking evaulation of an
// (x,y) coord. instead of (y,x)...although
// I don't think this is "standard order
// when dealing with such 2 dimensional
// arrays, but eh...
bool checkWin(slot *s, int cout, int direction);
}

Board::Board() {
int row, col;

for(col=1; col<COLUMNS; col++)
for(row=1; row<ROWS; row++) {
board[col][row]->left = board[col-1][row];
board[col][row]->right = board[col+1][row];
board[col][row]->down = board[col][row-1];
board[col][row]->up = board[col][row+1];
board[col][row]->duleft = board[col-1][row+1];
board[col][row]->duright = board[col+1][row+1];
... // Yeah, I got tired of copy, paste, edit
}

// The 2 border rows and 2 border columns must have their outside
// slot pointers set to null, I'll let you deal with that, just 4 more for loops,
// acutally only 2
}

bool Board::checkWin(int x, int y) {
if(checkDir(LEFT, x, y) // I guess instead of x, y, you could pass board[x][y]
// actually that would be better....did I mention I'm
// writing this as I go?
if(checkWin(board[x-1][y], 2, LEFT)
return true;

if(checkDir(RIGHT, x, y)
if(checkWin(board[x+1][y], 2, RIGHT)

.... I think you can figure out where this is going

else return false;
}
bool Board::checkDir(int dir, int x, int y) {
// If I had slots with adjacent slot pointers in an array I could get rid of this
// switch statement as well as the one above...
switch( dir ) {
case LEFT: return board[x][y]->checkAdjacent(LEFT);

...
}

// See, you replace the 8 slot pointers, for adjacent slots, with an array and
// replace the passing of x, y, with board[x][y] (we'll call it's replacement s)
// and this would be simplified to: return s->checkAdjacent(adj_slot[dir]);
}

So that gives you pretty much everything you need....I began to confuse myself, constantly revising as I went. There is much optimization that can be done with this probably. There is also excessive wrapping going on...no, not the music style. I'm a wrap fiend...there I'm referring to the music style, but only in jest. Anyways, I'm gonna go drink some more water, take some pills and pray this headache goes away.
• 11-10-2001
ender
Screwed up here

>bool checkDir(slot *s,int x,int y)
Meant to write either checkDir(int dir, slot *s) or checkDir(int dir, int x, int y), *s and x,y would be redundant. Actually it has to be slot *s now that I look at it. so nearly everwhere where I put int x, y and then use board[x][y] has to be a slot pointer since I later use the below function with a slot pointer...the x, y would be lost on the first pass

>bool checkWin(slot *s, int cout, int direction);

Sorry, forgot to write the helper function for the overloaded checkWin()
This is kind of important...here goes

bool checkWin(slot *s, int count, int direction) {

if(count == 4) return true;

if checkDir(direction, s)
return checkWin(slot s->adjacent_slots[direction], count++, direction);

return false;
}

there, that's the recursion that I was talking about. Now this will only run twice at max...maybe you could just put that in a for loop. Wow, I feel bad for insulting that guy last night. I'm producing crap too...I'd feel bad anyways, but ....oh right, back to the programming....I have no more to say about it. Hope this helps.