Sign in to follow this  
Username314

Templates? - Repetitious Coding for a Board Game

Recommended Posts

Hello pros of gamedev, I'm making a board game called Omok (yes, the game in MapleStory). It's like a connect 5 game played with Go pieces. What I need help on is to eliminate the repetitive coding. The game has 225 game squares. Starting with the basics, every time I click on one, I need to write a snippet of code which to checks to see if there's already a piece played in that game square. For these 3-4 lines of code, however, I would have to copy and paste them 225 times and rename the bool variable names 225 times. I bet there's another way to do the same thing but with much less coding, but I don't know what it is. My friend said I might need a template to do this, but he's not sure. So what kind of coding is necessary to omit the repetitious coding? Edit: Oops, sorry for not including more info. I am developing this game using C++ on VS 2005 with .NET on a Microsoft Forms Application.

Share this post


Link to post
Share on other sites
Oh wow... Yeah definitely don't store it as 225 different variables. I'm not sure if you've learned about arrays yet, but if I understand what you're doing right, what you want to do is create an array of bool's. Then you can loop through the check just create a function which takes the index and performs the check.

This would be the easiest way to implement it.

Share this post


Link to post
Share on other sites
One solution is an array; however, we're using C++ so we'll use std::vector. Basically this is just a container; we are going to use it to hold the 255 bool values we need to represent our board. Here is some code you can run to see how it all works - it's not 100% "pristine" C++ but you should get the idea :)



#include <iostream>
#include <vector>

// This is our class that is going to handle our game board
// We use a std::vector to hold our array and handle indexing ourselves using WhichIndexIsThis
class GameBoard
{
public:
// The constructor creates a container with 255 false entries in it
GameBoard() : theBoard_(255, false) {}

// Attempt to place a piece, returns false is the location is already filled
// True otherwise
bool PlacePiece(int x, int y)
{
if(IsSlotFilled(x, y))
return false;
theBoard_[WhichIndexIsThis(x, y)] = true;
return true;
}

private:

// Query function to check the container of locations
bool IsSlotFilled(int x, int y)
{
return theBoard_[WhichIndexIsThis(x, y)];
}

// Turns an x, y location into an index in our container
int WhichIndexIsThis(int x, int y)
{
return 15*x + y;
}

// A container for our board
// False means that square is empty, true means it has a piece played
// One thing to bear in mind is vector<bool> has some "interesting" qualities, but it serves our purpose here
std::vector<bool> theBoard_;
};


int main()
{
// Create our game board
GameBoard theGameBoard;

// An ever lasting loop we are going to use until we explicitly break out of it
for(;;)
{
// In practice you'd throw some error checking in here
int x, y;
std::cout << "Enter an x location (0-14): ";
std::cin >> x;
if(x < 0 || x > 14)
break;

// Error check here too!
std::cout << "Enter a y location (0-14): ";
std::cin >> y;
if(y < 0 || y > 14)
break;

// Check to see if we can place a piece
bool result = theGameBoard.PlacePiece(x, y);

// This resultant code you might want to have made part of GameBoard class, up to you
if(result)
std::cout << "Piece placed at " << x << ", " << y;
else
std::cout << "Location " << x << ", " << y << " already full, try again!";

// Flush for the new loop
std::cout << std::endl;
}

// All done
system("pause");
return 0;
}





Boost probably has an array alternative (probably called something imaginative like boost::array). However, the code above should give you your first steps towards using the C++ libraries container classes.

Hope this helps,

Jim.

Share this post


Link to post
Share on other sites
Be careful with vectors of bool as they are not supported by all compliers in the same way. There's more info here http://www.gotw.ca/publications/N1211.pdf, and probably if you search around a bit. If you do have problems just use a vector of chars or ints and then cast to bool.

Share this post


Link to post
Share on other sites
Quote:
Original post by Balaam
Be careful with vectors of bool as they are not supported by all compliers in the same way. There's more info here http://www.gotw.ca/publications/N1211.pdf, and probably if you search around a bit. If you do have problems just use a vector of chars or ints and then cast to bool.


A much better solution would be to use an enum:

enum BoardSquareState
{
NoPiecePlayed,
BlackPiecePlayed,
WhitePiecePlayed
};

std::vector<BoardSquareState> Board(225);

Share this post


Link to post
Share on other sites
Yup, in my defence I did put in a comment about vector<bool> having some interesting properties - but given this was a basic introduction to a container class I thought it unlikely it would be a big issue at this time - this code was purely intended as a first glance at containers (without having to worry about the pitfalls of proxy classes).

In a larger program I assumed that in fact it would be a vector<int>, or even a vector<shared_ptr<Player> > - although an enum would be good too, I just never use enums enough.

Jim.

Share this post


Link to post
Share on other sites
1) Omok is Pente in the US. I love this game. Although a pente board is normally the same size a go board (19x19) - but that doesn't matter.

2) I'm assume your 225 squares are in a grid of 9x10 or 10x9?

If so then you would want to do something like this: (I'm assuming the enum option used previously)


using std::vector;
typedef vector<vector<BoardSquareState> > OmokBoard;

void InitializeOmokBoard(OmokBoard board)
{
board.clear();
board.resize(10);
for(i=0; i<10; ++i)
{
board[i].clear();
board[i].resize(9, NoPiecePlayed);
}
}



of course, in your case that would probably be a member function instead of a function which takes an OmokBoard parameter, but you should get the idea.

Share this post


Link to post
Share on other sites
Quote:
Original post by Xai
1) Omok is Pente in the US. I love this game. Although a pente board is normally the same size a go board (19x19) - but that doesn't matter.

2) I'm assume your 225 squares are in a grid of 9x10 or 10x9?

If so then you would want to do something like this: (I'm assuming the enum option used previously)

*** Source Snippet Removed ***

of course, in your case that would probably be a member function instead of a function which takes an OmokBoard parameter, but you should get the idea.


First of all, your code doesn't work. Secondly, it's terribly inefficient.

Both of these problems have the same cause: you pass the board parameter by value. This means that the InitializeOmokBoard function will have a copy of the original board vector. In other words, every time the function is called, the memory of the original vector is copied over into a new variable, and then destroyed again as soon as the function exits. The function will accomplish no meaningful work, and wastes resources doing it.

At the very least, the board parameter should be passed by reference, i.e. OmokBoard& board. However, this is C++, so we may as well use the language properly:

enum OmokPiece
{
NoPiece,
BlackPiece,
WhitePiece
};

class OmokBoard
{
// Constructor
public:
OmokBoard() : Board(225)
{
}

// Access to the board
public:
bool IsSquareOpen(unsigned square) const
{
return (Board[square] == NoPiece);
}

void PlaySquare(unsigned square, OmokPiece piece)
{
assert(IsSquareOpen(square)); // Shouldn't play on top of a used square!

Board[square] = piece;
}

// Internal storage
protected:
std::vector<OmokPiece> Board;
};




Obviously, this can be changed to use the vector-of-vectors approach easily enough. Even better, since the concept of the game board is now encapsulated in a class, the internal representation can be changed in any way we want without breaking other code, because the interface (the IsSquareOpen and PlaySquare functions) will always stay the same.

Share this post


Link to post
Share on other sites
Quote:
Original post by Xai
2) I'm assume your 225 squares are in a grid of 9x10 or 10x9?


9x10 is 90 squares, no matter how you orient them.

The board in question is 15 x 15.

http://users.abac.com/MeriBird/Omok/rules.html

Share this post


Link to post
Share on other sites

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