New to game programming

Started by
14 comments, last by GameDev.net 19 years, 7 months ago
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;
	}
	
}

Advertisement
Very nice code structure. Now it's time to tackle a simple AI.
______________________________________________________________________________________The Phoenix shall arise from the ashes... ThunderHawk -- ¦þ"So. Any n00bs need some pointers? I have a std::vector<n00b*> right here..." - ZahlmanMySite | Forum FAQ | File Formats______________________________________________________________________________________
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
-----------------------------"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to build bigger and better idiots. So far, the universe is winning..." -- Rich Cook"...nobody ever accused English pronounciation and spelling of being logical." -- Bjarne Stroustrup"...the war on terror is going badly because, if you where to compare it to WWII, it's like America being attacked by Japan, and responding by invading Brazil." -- Michalson
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
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.

Steven Bradley .:Personal Journal:. .:WEBPLATES:. .:CGP Beginners Group:. "Time is our most precious resource yet it is the resource we most often waste." ~ Dr. R.M. Powell
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.
______________________________________________________________________________________The Phoenix shall arise from the ashes... ThunderHawk -- ¦þ"So. Any n00bs need some pointers? I have a std::vector<n00b*> right here..." - ZahlmanMySite | Forum FAQ | File Formats______________________________________________________________________________________
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.
I'd say it was less easy to understand though.
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.
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

This topic is closed to new replies.

Advertisement