Sign in to follow this  

New to game programming

This topic is 4839 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello all, I am new to game programming, although I have dabbled with C/C++ off and on for the past few years. Anyways, I wanted to share with everyone here my first game creation: TIC-TAC-TOE! It is nothing spectacular by any means. It is written in C++ and uses standard C++ streams for user input and output. It automaticly checks for win and stalemate conditions. That's about it. To any experienced game dev'ers or even experienced programmers in this forum, would you mind looking at the code and giving me feedback either negative or positive. It does'nt matter which. I would just like some feedback so that I can learn the voice of experience. Thanks all, JD GAMEBOARD.CPP:
#include ".\gameboard.h"
#include <iostream>
using namespace std;

GameBoard::GameBoard(void)
{
}

GameBoard::~GameBoard(void)
{
}

void GameBoard::DrawBoard(void)
{
	int x,y,z=0;
	
	cout << endl;

	for (x=0; x < 3; x++)
	{
		for (y=0; y < 3; y++)
		{
			cout << " ";
			switch (GameBoardData[x][y])
			{
				case 1:
					cout << "X";
					break;
				
				case 2:
					cout << "O";
					break;
				
				default:
					cout << y+1+z;
			}
			cout << " ";
			if (y != 2)
				cout << "|";
		}
		z=z+3;
		if (x !=2) 
		{
			cout << endl;		
			cout << " ---------";
			cout << endl;
		}
	}

	cout << endl << endl; 
}

bool GameBoard::SetPlayerPiece(int Position, int Player)
{
	int x, y;

	x = (Position / 3);
	y = (Position % 3) - 1;

	if (GameBoardData[x][y] == 1 || GameBoardData[x][y] == 2)
	{
		cout << "This space is already occupied" << endl;
		return false;
	}

	GameBoardData[x][y] = Player;
	return true;
}

int GameBoard::CheckWinCondition(int Player)
{
	if (GameBoardData[0][0]+GameBoardData[0][1]+GameBoardData[0][2] == Player * 3)
		return Player;
	
	if (GameBoardData[1][0]+GameBoardData[1][1]+GameBoardData[1][2] == Player * 3)
		return Player;

	if (GameBoardData[2][0]+GameBoardData[2][1]+GameBoardData[2][2] == Player * 3)
		return Player;

	if (GameBoardData[0][0]+GameBoardData[1][0]+GameBoardData[2][0] == Player * 3)
		return Player;

	if (GameBoardData[0][1]+GameBoardData[1][1]+GameBoardData[2][1] == Player * 3)
		return Player;

	if (GameBoardData[0][2]+GameBoardData[1][2]+GameBoardData[2][2] == Player * 3)
		return Player;

	if (GameBoardData[0][0]+GameBoardData[1][1]+GameBoardData[2][2] == Player * 3)
		return Player;

	if (GameBoardData[0][2]+GameBoardData[1][1]+GameBoardData[2][0] == Player * 3)
		return Player;

	return 0;
}

bool GameBoard::CheckForStalemate(void)
{
	int x, y;
	int StalemateCounter=0;

	for (x=0; x < 3; x++)
	{
		for (y=0; y < 3; y++)
		{
			if (GameBoardData[x][y] == 1 || GameBoardData[x][y] == 2)
			StalemateCounter++;			
		}
	}
	if (StalemateCounter == 9)
        return true;
	else
		return false;
}


GAMEBOARD.H:
#pragma once

class GameBoard
{
public:
	int GameBoardData[3][3];

	GameBoard(void);
	~GameBoard(void);

	bool SetPlayerPiece(int Position, int Player);
	void DrawBoard(void);
	int CheckWinCondition(int Player);
	bool CheckForStalemate(void);

};

GAMEOBJECT.CPP:
#include ".\gameobject.h"
#include <iostream>

using namespace std;

GameObject::GameObject(void)
{
	GameWon = false;
	CurrentPlayer = 1;
}

GameObject::~GameObject(void)
{
}

void GameObject::NewGame(void)
{
	cout << endl;
	cout << "Welcome to Tic-Tac-Toe!"  << endl;
    cout << endl;
}

bool GameObject::RunGame(void)
{
	char Response;

	NewGame();
	
	theBoard.DrawBoard();

	while (!GameWon)
	{
			if (PlayerTurn(CurrentPlayer)==false)
			{
				if(CurrentPlayer == 1)
					CurrentPlayer = 2;
				else CurrentPlayer = 1;
			}
			theBoard.DrawBoard();
			if (theBoard.CheckForStalemate()==true)
			{
				cout << "Stalemate!" << endl;
				GameWon=true;
			}
			if(theBoard.CheckWinCondition(CurrentPlayer)==CurrentPlayer)
			{
				cout << "Player " << CurrentPlayer << " wins!" << endl;
				GameWon = true;
			}
			if(CurrentPlayer == 1)
				CurrentPlayer = 2;
			else CurrentPlayer = 1;
	}
	cout << endl;
	cout << "Another Game? ";
	cin >> Response;
	if (Response == 'Y' || Response == 'y')
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool GameObject::PlayerTurn(int Player)
{
	int Move;

	cout << "Player "<< Player << "'s Turn: ";
	cin >> Move;
	
	if(theBoard.SetPlayerPiece(Move, Player)==false)
		return false;
	
	return true;
}


GAMEOBJECT.H:
#pragma once
#include "GameBoard.h"

class GameObject
{
private:
	bool GameWon;
	int CurrentPlayer;
	GameBoard theBoard;

public:
	
	GameObject(void);
	~GameObject(void);

	void NewGame(void);
	bool RunGame(void);
	bool PlayerTurn(int Player);
};

MAIN.CPP:
#include "GameObject.h"


int main(void)
{
	GameObject *theGame;
	bool Running = true;

	while (Running)
	{
		theGame = new GameObject;
		if(theGame->RunGame()==false)
		{
			Running = false;
		}
		delete theGame;
	}
	
}

Share this post


Link to post
Share on other sites
Hi!

My first advice is: Use comments!!! ;-)

In GameBoard::SetPlayerPiece(), you should really check for a valid Position. You're assuming that a value between 0 and 8 is specified (at least I can't see a check). But when, for example, 9 is entered, something bad happens. x will be 3, and y will be -1!! This will most likely give you an access violation when indexing GameBoardData[][].

Another thing that sticks out is, that you're not initializing the array GameBoardData[][]. This is bad, because you rely on specific values being set alot (1 and 2). And even if you wouldn't rely on specific values, you should always initialize your data! The place to do this is, of course, the constructor.

Then you use the #pragma once directive, which is fine as long as you know that your code will always be compiled with a compiler that supports it (I don't really know which ones do or don't). But I suggest you use the classical #ifdef way. And, also for the sake of platform-independence, type #include "./header.h" or simply #include "header.h".

Hope that helps!

cya,
Drag0n

Share this post


Link to post
Share on other sites
Thanks for the replies everybody. To dragon: I made changes you suggested. I can't believe I wasn't checking for bad user input in the SetPlayerPiece function. Dumb. Thanks, I appreciate the input. Unfourtantly I have no idea on how to start implementing AI for this game. I have never done anything with AI.
Again, thanks everyone for your help.

P.S. If you are interested in seeing the source code to this program, drop me an email. jjasteffen922@hotmail.com

Share this post


Link to post
Share on other sites
Quote:
Original post by Rendman
Unfourtantly I have no idea on how to start implementing AI for this game. I have never done anything with AI.


I would suggest starting with some basic decision checks.

- check for win state (if false, next)
- check open spaces and see if any will make win state true.
- if none will make win state true, see if a space will give 2 in a row.

And so on. You can get as detailed as you want. To start just use a bunch of if statements will logical operators.

Share this post


Link to post
Share on other sites
As for AI, what I did was:

1) if any position lets AI win in one move, take it
2) if any position lets the player to win, take it
3) weight each space according to strategic value (number of adjacent friendly tiles vs number of adjacent hostile tiles)
4) chose the tile with the greatest weight (if two or more have the greatest weight, select randomly)
5) clean up any situations where the AI always loses (this check goes between 2 and 3 but is the last thing you should try)

Obviously you could instead go with the old minmax routine, but this would prevent the user from ever being able to win.

Share this post


Link to post
Share on other sites
One minor note:

"if(StalemateCounter == 9)
return true;
else
return false;"

Actually, you can just write "return StalemateCounter == 9;". This is because the phrase "StalemateCounter == 9" evaluates to a zero (false) or nonzero value (true) directly, which really is what you already want.

Share this post


Link to post
Share on other sites
But that is also a lot more obscure, wise. I mean, it is an interesting note, but not something most people would think about when they first look at the code. He would spend just as much time commenting it and explaining why it works, so when others look at the code they can understand it.

Keep it clean and simple, but most of all, keep it understandable.


As for the code itself, I am very impressed. When I made my first tic-tac-toe game, I didn't even think about making the game itself an object. Did you program in Java before this? I only say that because after programming in Java, I tend to write my code a lot more like yours. Before, when I made the switch from C to C++, my code was a lot less object oriented.

Very impressed. Keep up the good work.

Share this post


Link to post
Share on other sites
visage, no I have never programmed in Java. When I first started to learn C/C++ I read ALOT. Then I experimented. Then I read some more. Then I played around with what I learned some more. In between all those steps I spent alot of time thinking too. I won't claim that this method is best by any means. It takes a long time, and I still don't understand alot. But I am learning, and I feel that game programming offers the best all around method of learning and understanding a plethora of different programming problems and solutions.

Thanks for the feed back.

JD

Share this post


Link to post
Share on other sites
Quote:
Original post by Unwise owl
Actually, you can just write "return StalemateCounter == 9;". This is because the phrase "StalemateCounter == 9" evaluates to a zero (false) or nonzero value (true) directly, which really is what you already want.


To answer the subsequent posters: This is *not* obscure, *not* difficult to understand, and *works* in C (because integers are interpreted as booleans in the necessary way), C++ (because integers are implicitly cast to booleans in the necessary way when needed) and Java/C# (because the expression already results in a boolean). And is almost certainly the preferred way of doing it. Writing the extra lines is repeating yourself.

Compare:
"If this expression is true I want to say it is true; otherwise, i.e. if it is false, I want to say it is false."

Versus:
"I want to tell you the truth value of this expression."

And because it is a way of repeating yourself, it is actually one of the *first* things I look for in code, and tell people to correct.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
...C++ (because integers are implicitly cast to booleans in the necessary way when needed)...


The ==-operator always evaluates to a bool, so nothing actually gets casted implicitely in this case. But the way you suggest is the most obvious and in my opinion easiest to understand. And it is more efficient (even though new compilers will probably optimize it anyways).

Quote:
Original post by Shard
Maybe the best way to do it is to use the ? operator.


...which is just another, less readable if-expression.

Cheers,
Drag0n

Share this post


Link to post
Share on other sites
Quote:
Original post by Drag0n
Quote:
Original post by Zahlman
...C++ (because integers are implicitly cast to booleans in the necessary way when needed)...


The ==-operator always evaluates to a bool, so nothing actually gets casted implicitely in this case. But the way you suggest is the most obvious and in my opinion easiest to understand. And it is more efficient (even though new compilers will probably optimize it anyways).


Oops, I think you're right. There would of course be implicit casting back to int if you then do arithmetic with the result :)

Quote:

Quote:
Original post by Shard
Maybe the best way to do it is to use the ? operator.


...which is just another, less readable if-expression.

Cheers,
Drag0n

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Zahlman
Oops, I think you're right. There would of course be implicit casting back to int if you then do arithmetic with the result :)


Yes, let's do some boolean arithmetic! ;)

Cheers,
Drag0n

Share this post


Link to post
Share on other sites

This topic is 4839 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this