Say, how about some planning before coding

.
My presence here is all about learning young folks how to think before coding. In fact, coding becomes super easy if one manages to analyse a bit first.
Let me tell you how I did half a tic-tac-toe (see code below) program in 15 minutes!
First I want to know about the domain problem. Or in normal words:
what the heck are we talking about?
Then I want to make sure what's going on with this application. To find out I play a few games to get the "global" idea. From there I know the main functions. Let us call this
use case analisys.
Then I'm thinking like this:
Quote:
|
Hey, the playground is basically a 3x3 matrix and the elements in that matrix can be owned by Player_1, Player_2, or it can be empty.
|
So I come up with this:
Code:
enum Owner
{
PLAYER_1,
PLAYER_2,
EMPTY
};
And now I need to make the play ground by creating that 3x3 matrix and encapsulate it with typical things that can occur on that playground. For example, creating the playground. Just look at the class, and things get obvious. This is the result of use case analisys (don't let that difficult phrase scare you!).
Code:
class Field
{
public:
Field();
Owner winner() const;
bool full() const;
void set_field(Position, Owner);
private:
static bool equal(Owner, Owner, Owner);
Owner _owner[3][3];
};
But each field in the matrix has a position (co-ordinate). I'll make a
seperate struct (or class if you will) for performance reasons. Just a demonstration of a nice technique. You could integrate it into the Field class if you will.
Code:
struct Position
{
int _x, _y;
Position(int x, int y) :
_x(x), _y(y)
{}
Position() :
_x(-1), _y(-1)
{}
};
So now I have my domain, only because I played a few games and thought for 5 minutes using nothing else but a pencil and one page! The actual implementation takes only a second. Observe the complete code below. Would you believe that I spent more time typing this on the forum then developing the core of the game?
Here we go:
Code:
struct Position
{
int _x, _y;
Position(int x, int y) :
_x(x), _y(y)
{}
Position() :
_x(-1), _y(-1)
{}
};
//--------------------------------------------------
enum Owner
{
PLAYER_1,
PLAYER_2,
EMPTY
};
//--------------------------------------------------
class Field
{
public:
Field();
Owner winner() const;
bool full() const;
void set_field(Position, Owner);
private:
static bool equal(Owner, Owner, Owner);
Owner _owner[3][3];
};
//--------------------------------------------------
Field::Field()
{
for(unsigned i=0; i<3; ++i)
{
for(unsigned j=0; j<3; ++j)
{
_owner[i][j] = EMPTY;
}
}
}
//--------------------------------------------------
void Field::set_field(Position pos, Owner owner)
{
_owner[pos._x][pos._y] = owner;
}
//--------------------------------------------------
bool Field::equal(Owner a, Owner b, Owner c)
{
if(a == b && b == c)
{
return a != EMPTY;
}
return false;
}
bool Field::full() const
{
for(unsigned i=0; i<3; ++i)
{
for(unsigned j=0; j<3; ++j)
{
if( _owner[i][j] == EMPTY)
{
return false;
}
}
}
}
//--------------------------------------------------
Owner Field::winner() const
{
for(int i=0; i<3; ++i)
{
if(equal(_owner[i][0], _owner[i][1], _owner[i][2]))
return _owner[i][0];
}
for(int j=0; j<3; ++j)
{
if(equal(_owner[0][j], _owner[1][j], _owner[2][j]))
return _owner[0][j];
}
if(equal(_owner[0][0], _owner[1][1], _owner[2][2]))
return _owner[0][0];
if(equal(_owner[2][0], _owner[1][1], _owner[0][2]))
return _owner[0][2];
return EMPTY;
}
//--------------------------------------------------
int main(int argc, char *argv[])
{
//Create the play ground.
Field theField;
//Create the players here.
//...magic code here...
while(1)
{
// 1) Determine which position player_1 or player_2 chooses.
// 2) Store it in Field::_owner.
// 3) Update the visualisation (GUI, console, bash, iMac, etc.).
// 4) Do we have a winner perhaps?
if(theField.winner() != EMPTY)
{
//We have a winner.
break;
}
// 5) Otherwise, do we hava draw (no winner, but all fields full).
if(theField.full() )
{
//All fields are used. It must be a draw if we manage to get here.
break;
}
// 6) No winner and some field(s) is/are empty.
// ...magic code to switch players turn...
}
// 7) We have a winner or it is draw.
// ...magic code to visualise and wrap things (application, cleanup) up...
return 0;
}
Yup. That's it.
See if you like it.