Pong AI, and some advice on the code I've managed to cobble together

Started by
2 comments, last by skulldrudgery 18 years, 11 months ago
I started working on this thing a couple of days ago. Not much planning on my part has led to a bunch of code that feels "improvised." Ugliness and redundancy are my biggest worries. I could use some advice on cleaning up the code. Plus, I need to add some AI. Right now I just got a "dumb" paddle going up and down randomly (at least 5 lines in a row). I'm almost afraid to post the code. But here it is:
#include <iostream>

using std::cout;
using std::cin;
using std::endl;

#include <iomanip>

using std::setw;

#include <ctime>
#include <cmath>
#include <conio.h>
#include <windows.h>

const int SCREEN_HEIGHT = 25;
const int SCREEN_WIDTH  = 80;
const int GAME_OBJECT_STR_LENGTH = 4;
enum { pLEFT = 10, pRIGHT = 70, pMIDDLE = 39 };
enum { pTOP = 3, pBOTTOM = 22, pCENTER = 12 };
enum DIRECTION { d_LEFT = -1, d_NONE = 0, d_RIGHT = 1, d_UP = -1, d_DOWN = 1 };
enum { LOSE_LINE_LEFT = 8, LOSE_LINE_RIGHT = 72 };

// forward declarations/prototypes
void gotoxy( int, int );
void delay( int );
void print_interface();
void ai_move( int & );

int player1score = 0;
int player2score = 0;
int speedfactor = 100;
bool flag1 = false; // a flag because I'm lazy

// game object struct
struct game_object {
    char str_top[4];     // all game objects will consist of three (or less) char
    char str_middle[4];  // arrays of length 3 or less
    char str_bottom[4];
    int oldx, oldy;
    int tempx, tempy;
    int x, y;
};

// engine class
class pong {
    
    public:
        void draw_object( game_object & );
        void get_input( int & );
        void ball_move( game_object &, game_object &, game_object & );
        bool check_ball( game_object & );
        
} engine;

void pong::draw_object( game_object &object )
{
    // delete object at old location
    for ( int i = 0; i < GAME_OBJECT_STR_LENGTH - 1; i++ ) {
        if ( object.str_top )
            gotoxy( object.oldx + i, object.oldy ), cout &lt;&lt; <span class="cpp-literal">" "</span>;
    
        <span class="cpp-keyword">if</span> ( object.str_middle )
            gotoxy( object.oldx + i, object.oldy + <span class="cpp-number">1</span> ), cout &lt;&lt; <span class="cpp-literal">" "</span>;
        
        <span class="cpp-keyword">if</span> ( object.str_bottom )
            gotoxy( object.oldx + i, object.oldy + <span class="cpp-number">2</span>), cout &lt;&lt; <span class="cpp-literal">" "</span>;
    }
    
    <span class="cpp-comment">// draw object at new location</span>
    <span class="cpp-keyword">if</span> ( object.str_top )
        gotoxy( object.x, object.y ), cout &lt;&lt; object.str_top;
    
    <span class="cpp-keyword">if</span> ( object.str_middle )
        gotoxy( object.x, object.y + <span class="cpp-number">1</span> ), cout &lt;&lt; object.str_middle;
        
    <span class="cpp-keyword">if</span> ( object.str_bottom[ <span class="cpp-number">0</span> ] )
        gotoxy( object.x, object.y + <span class="cpp-number">2</span>), cout &lt;&lt; object.str_bottom;
}

<span class="cpp-keyword">void</span> pong::get_input( <span class="cpp-keyword">int</span> &amp;y )
{       
    <span class="cpp-keyword">if</span> ( GetAsyncKeyState( <span class="cpp-number">38</span> ) &amp;&amp; y != pTOP ) <span class="cpp-comment">// if the "up" key is pressed…</span>
        y–;
    
    <span class="cpp-keyword">if</span> ( GetAsyncKeyState( <span class="cpp-number">40</span> ) &amp;&amp; y != pBOTTOM - <span class="cpp-number">2</span> ) <span class="cpp-comment">// if the "down" key is pressed…</span>
        y++;
}

<span class="cpp-keyword">void</span> pong::ball_move( game_object &amp;ball, game_object &amp;p1, game_object &amp;p2 )
{
    <span class="cpp-keyword">static</span> DIRECTION Y_DIR = d_NONE;
    <span class="cpp-keyword">static</span> DIRECTION X_DIR = d_LEFT;
    
    <span class="cpp-keyword">if</span> ( flag1 == <span class="cpp-keyword">true</span> ) {
        Y_DIR = d_NONE;
        X_DIR = rand() % <span class="cpp-number">2</span> == <span class="cpp-number">0</span> ? d_LEFT : d_RIGHT;
        flag1 = <span class="cpp-keyword">false</span>;
    }
    
    <span class="cpp-keyword">if</span> ( ball.x == pLEFT + <span class="cpp-number">1</span> ) { <span class="cpp-comment">// if the ball hits the line…</span>
       
        <span class="cpp-keyword">if</span> ( ball.y == p1.y - <span class="cpp-number">1</span> ) { <span class="cpp-comment">// if it hits the top of the paddle, reflect</span>
            Y_DIR = d_UP;           <span class="cpp-comment">// along x+ and y+</span>
            X_DIR = d_RIGHT;
            <span class="cpp-keyword">if</span> ( speedfactor &gt;= <span class="cpp-number">25</span> )
                speedfactor -= <span class="cpp-number">5</span>;
        }
        
        <span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span> ( ball.y == p1.y ) { <span class="cpp-comment">// if it hits the middle, reflect along</span>
            Y_DIR = d_NONE;          <span class="cpp-comment">// x+ only</span>
            X_DIR = d_RIGHT;
            <span class="cpp-keyword">if</span> ( speedfactor &gt;= <span class="cpp-number">25</span> )
                speedfactor -= <span class="cpp-number">5</span>;
        }
        
        <span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span> ( ball.y == p1.y + <span class="cpp-number">1</span> ) {
            Y_DIR = d_DOWN;
            X_DIR = d_RIGHT;
            <span class="cpp-keyword">if</span> ( speedfactor &gt;= <span class="cpp-number">25</span> )
                speedfactor -= <span class="cpp-number">5</span>;
        }
    } <span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span> ( ball.x == pRIGHT - <span class="cpp-number">1</span> ) { <span class="cpp-comment">// if the ball hits the line…</span>
       
        <span class="cpp-keyword">if</span> ( ball.y == p2.y - <span class="cpp-number">1</span>  ) { <span class="cpp-comment">// if it hits the top of the paddle, reflect</span>
            Y_DIR = d_UP;            <span class="cpp-comment">// along x+ and y+</span>
            X_DIR = d_LEFT;
            <span class="cpp-keyword">if</span> ( speedfactor &gt;= <span class="cpp-number">25</span> )
                speedfactor -= <span class="cpp-number">5</span>;
        }
        
        <span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span> ( ball.y == p2.y ) { <span class="cpp-comment">// if it hits the middle, reflect along</span>
            Y_DIR = d_NONE;          <span class="cpp-comment">// x+ only</span>
            X_DIR = d_LEFT;
            <span class="cpp-keyword">if</span> ( speedfactor &gt;= <span class="cpp-number">25</span> )
                speedfactor -= <span class="cpp-number">5</span>;
        }
        
        <span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span> ( ball.y == p2.y + <span class="cpp-number">1</span> ) {
            Y_DIR = d_DOWN;
            X_DIR = d_LEFT;
            <span class="cpp-keyword">if</span> ( speedfactor &gt;= <span class="cpp-number">25</span> )
                speedfactor -= <span class="cpp-number">5</span>;
        }
    }
    
    <span class="cpp-keyword">if</span> ( ball.y == pTOP )
        Y_DIR = d_DOWN;
    <span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span> ( ball.y == pBOTTOM - <span class="cpp-number">2</span> )
        Y_DIR = d_UP;
    
    ball.oldx = ball.x;
    ball.oldy = ball.y;
    
    ball.x += X_DIR;
    ball.y += Y_DIR;
}

<span class="cpp-keyword">bool</span> pong::check_ball( game_object &amp;ball )
{
    <span class="cpp-keyword">if</span> ( ball.x == LOSE_LINE_RIGHT ) {
        player1score++;
        <span class="cpp-keyword">if</span> ( speedfactor - <span class="cpp-number">1</span> &lt; <span class="cpp-number">100</span> )
            speedfactor += <span class="cpp-number">2</span>;
        flag1 = <span class="cpp-keyword">true</span>;
        <span class="cpp-keyword">return</span> <span class="cpp-keyword">true</span>;
    }
    
    <span class="cpp-keyword">if</span> ( ball.x == LOSE_LINE_LEFT ) {
        player2score++;
        <span class="cpp-keyword">if</span> ( speedfactor - <span class="cpp-number">1</span> &lt; <span class="cpp-number">100</span> )
            speedfactor += <span class="cpp-number">2</span>;
        flag1 = <span class="cpp-keyword">true</span>;
        <span class="cpp-keyword">return</span> <span class="cpp-keyword">true</span>;
    }
    
    <span class="cpp-keyword">return</span> <span class="cpp-keyword">false</span>;
}

<span class="cpp-keyword">int</span> main()
{
    game_object paddle1, paddle2, ball;
    
    <span class="cpp-comment">// paddle 1 initialization</span>
    paddle1.x = pLEFT, paddle1.y = pCENTER;
    paddle1.oldx = paddle1.x, paddle1.oldy = paddle1.y;
    
    paddle1.str_top[ <span class="cpp-number">0</span> ] = '|', paddle1.str_top[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>',
        paddle1.str_top[ <span class="cpp-number">2</span> ] = '\<span class="cpp-number">0</span>';
    
    paddle1.str_middle[ <span class="cpp-number">0</span> ] = '|', paddle1.str_middle[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>',
        paddle1.str_middle[ <span class="cpp-number">2</span> ] = '\<span class="cpp-number">0</span>';
    
    paddle1.str_bottom[ <span class="cpp-number">0</span> ] = '|', paddle1.str_bottom[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>',
        paddle1.str_bottom[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>';

    <span class="cpp-comment">// paddle 2 initialization</span>
    paddle2.x = pRIGHT, paddle2.y = pCENTER;
    paddle2.oldx = paddle2.x, paddle2.oldy = paddle2.y;
    
    paddle2.str_top[ <span class="cpp-number">0</span> ] = '|', paddle2.str_top[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>',
        paddle2.str_top[ <span class="cpp-number">2</span> ] = '\<span class="cpp-number">0</span>';
    
    paddle2.str_middle[ <span class="cpp-number">0</span> ] = '|', paddle2.str_middle[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>',
        paddle2.str_middle[ <span class="cpp-number">2</span> ] = '\<span class="cpp-number">0</span>';
    
    paddle2.str_bottom[ <span class="cpp-number">0</span> ] = '|', paddle2.str_bottom[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>',
        paddle2.str_bottom[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>';
    
    <span class="cpp-comment">// ball initialization</span>
    ball.x = pMIDDLE, ball.y = pCENTER;
    ball.oldx = ball.x, ball.oldy = ball.y;
    
    ball.str_top[ <span class="cpp-number">0</span> ] = '\<span class="cpp-number">0</span>', ball.str_top[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>',
        ball.str_top[ <span class="cpp-number">2</span> ] = '\<span class="cpp-number">0</span>';
    
    ball.str_middle[ <span class="cpp-number">0</span> ] = <span class="cpp-number">219</span>, ball.str_middle[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>',
        ball.str_middle[ <span class="cpp-number">2</span> ] = '\<span class="cpp-number">0</span>';
    
    ball.str_bottom[ <span class="cpp-number">0</span> ] = '\<span class="cpp-number">0</span>', ball.str_bottom[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>',
        ball.str_bottom[ <span class="cpp-number">1</span> ] = '\<span class="cpp-number">0</span>';
        
    <span class="cpp-keyword">while</span>( <span class="cpp-number">1</span> ) {
        delay( speedfactor );
        print_interface();
        engine.draw_object( paddle1 );
        engine.draw_object( paddle2 );
        engine.draw_object( ball );
        
        <span class="cpp-keyword">if</span> ( kbhit() ) {
            paddle1.oldy = paddle1.y;
            paddle2.oldy = paddle2.y;
            engine.get_input( paddle1.y );
        }
        
        ai_move( paddle2.y );
        
        engine.ball_move( ball, paddle1, paddle2 );
        
        <span class="cpp-keyword">if</span> ( engine.check_ball( ball ) ) {
            paddle1.x = pLEFT, paddle1.y = pCENTER;
            paddle1.oldx = paddle1.x, paddle1.oldy = paddle1.y;
            
            paddle2.x = pRIGHT, paddle2.y = pCENTER;
            paddle2.oldx = paddle2.x, paddle2.oldy = paddle2.y;
            
            ball.x = pMIDDLE, ball.y = pCENTER;
            ball.oldx = ball.x, ball.oldy = ball.y;
            
            gotoxy( pMIDDLE - <span class="cpp-number">10</span>, pCENTER - <span class="cpp-number">1</span> );
            cout &lt;&lt; <span class="cpp-literal">"                                     "</span>;
            
            gotoxy( pMIDDLE - <span class="cpp-number">10</span>, pCENTER );
            cout &lt;&lt; <span class="cpp-literal">"Oops! Score is "</span> &lt;&lt; player1score &lt;&lt; <span class="cpp-literal">" - "</span> &lt;&lt; player2score &lt;&lt; endl;
            
            gotoxy( pMIDDLE - <span class="cpp-number">10</span>, pCENTER + <span class="cpp-number">1</span> );
            cout &lt;&lt; <span class="cpp-literal">"                                     "</span>;
            
            delay( <span class="cpp-number">3000</span> );
            system( <span class="cpp-literal">"cls"</span> );
        } 
    }
}

<span class="cpp-comment">// a couple of functions for utility purposes</span>
<span class="cpp-keyword">void</span> gotoxy( <span class="cpp-keyword">int</span> x, <span class="cpp-keyword">int</span> y )
{
    COORD pos;
    HANDLE screen = GetStdHandle( STD_OUTPUT_HANDLE );

    pos.X = x;
    pos.Y = y;

    SetConsoleCursorPosition( screen, pos );
}

<span class="cpp-keyword">void</span> delay( <span class="cpp-keyword">int</span> milliseconds )
{
    time_t now = clock();
    time_t end = now + milliseconds;
    
    <span class="cpp-keyword">while</span>( now = clock() &lt; end );
}

<span class="cpp-keyword">void</span> print_interface()
{
    gotoxy( <span class="cpp-number">0</span>, <span class="cpp-number">0</span> );
    cout &lt;&lt; <span class="cpp-literal">"Player 1: "</span> &lt;&lt; player1score &lt;&lt; <span class="cpp-literal">"\tPlayer 2: "</span> &lt;&lt; player2score
            &lt;&lt; <span class="cpp-literal">"\t\tGamespeed is currently: "</span>
               &lt;&lt; setw( <span class="cpp-number">2</span> ) &lt;&lt; abs( speedfactor - <span class="cpp-number">100</span> ) &lt;&lt; <span class="cpp-literal">"/80\n\n"</span>
         &lt;&lt; <span class="cpp-literal">"        _________________________________________________________________\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span>
         &lt;&lt; <span class="cpp-literal">"       |________________________________|________________________________|\n"</span>;
}

<span class="cpp-keyword">void</span> ai_move( <span class="cpp-keyword">int</span> &amp;y )
{   
    <span class="cpp-keyword">static</span> DIRECTION dir = d_UP;
    <span class="cpp-keyword">static</span> <span class="cpp-keyword">int</span> dcounter = <span class="cpp-number">0</span>;
    
    <span class="cpp-keyword">if</span> ( y == pTOP )
        dir = d_DOWN;
    <span class="cpp-keyword">else</span>
        <span class="cpp-keyword">if</span> ( y == pBOTTOM - <span class="cpp-number">2</span> )
            dir = d_UP;
        <span class="cpp-keyword">else</span>
            <span class="cpp-keyword">if</span> ( dcounter &gt; <span class="cpp-number">5</span> )
                dir = rand() % <span class="cpp-number">2</span> == <span class="cpp-number">0</span> ? d_UP : d_DOWN;
    y += dir;
    dcounter++;
    <span class="cpp-keyword">if</span> ( dcounter &gt; <span class="cpp-number">6</span> )
        dcounter = <span class="cpp-number">0</span>;
}




</pre></div><!–ENDSCRIPT–>
Please excuse any n00bish-ness. I started off ok. I had an engine class, but after some time it just devolved into a collection of public functions, pointless to have as a class. I can make this hideous beast work, but I want to make it work right. Hints, tips, AI ideas, anything will be appreciated. Thanks in advance. The main thing is AI, though.

Edit: Oh yeah, and it's an ASCII pong, but you already knew that [looksaround]
skulldrudgery--A tricky bit of toil
Advertisement
Putting everything into a class is not necessarily a good thing - it doesn't make your code more 'object oriented.' Some functions are naturally suited to being public globals. So don't worry about that.

My issues with your code would be:

  1. Personally, I tend to group all my includes together and put them in alphabetical order (when dependencies are not a problem).
  2. Those enums need commenting.
  3. 'flag1' is a terrible variable name. You could change it, or you could fix up the comment to tell us something useful.
  4. You say that game objects will require arrays of length 3 or less, yet your arrays are of length 4. I think you want to change the comment to say 'strings of three characters or less, not including the null terminator.'
  5. What's 'tempx' and 'tempy'?
  6. Using commas like that is a fairly nasty idea, because you're doing two things with one statement. It looks like an attempt to avoid using curly braces after the if - that's a really bad habit to get into, because at first glance there is only one thing being done by that line of code, a misleading way to leave things. Add curly braces and split the gotoxy/cout into seperate statements.
  7. It's often a good idea to bracket out seperate clauses in an if statement to avoid any potential problems with operator precedence (the get_input function's ifs are what I'm looking at).
  8. Don't you want to be copying paddle2.y to paddle2.oldy regardless of whether the user has hit a key, because your AI is going to be moving the paddle?
  9. gotoxy, delay, and ai_move need commenting.


Other than that, it's a fairly nice system you've got there.

Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse

I agree with superpig's comments. I also wrote a pong clone as my first game, if you want the source code it's here:

http://www.freewebs.com/crazyballsgame/

It uses directdraw, but the AI could be used in a text-game. Basically, check whether the ball is higher or lower than the AI paddle, and move the paddle a set number of spaces up or down accordingly.

If you scroll down the page ^ there's english underneath.
Thanks for the tips, superpig. Using your suggestions, and some from PMs and other forums (and of course, looking at other people's code), I think I have managed to clean it up and make it much prettier and easier to understand. As far as the AI, I can't believe how simple it was. I should have been able to figure it out on my own. To the AP, I took a look at your game. It was nice. I like the AI, even if it was a bit easy. Thanks for the good example.

Without further ado:
// ASCII Pong// Programmed by Muhammad al-Haider// pong.cpp#include <conio.h>#include <cmath>#include <ctime>#include <iomanip>#include <iostream>#include <windows.h>using namespace std;/*** global variables ***/const int str_length = 4; // length for game object stringsint p1score = 0;int p2score = 0;int speed = 100; // gamespeed (length of delay for the main game loop)bool randomize = true; // flag to randomize the direction the ball is moving/*** enumerations ***/enum { pLEFT = 10, pRIGHT = 70, pMIDDLE = 39 };    // horizontal(x) positions enum  { pTOP = 3, pBOTTOM = 22, pCENTER = 12 };    // vertical(y) positions   enum { LOSE_LINE_LEFT = 8, LOSE_LINE_RIGHT = 72 }; // the ball is out if it crosses                                                   // one of these lines enum DIRECTION { d_LEFT = -1, d_FLAT = 0, d_RIGHT = 1, // Direction an object is                 d_UP = -1, d_DOWN = 1 };              // travelling/*** structs ***/struct game_object {    char    szTop[ str_length ];  // all game objects will consist of three (or less)    char szMiddle[ str_length ];  // char strings of length 3 or less    char szBottom[ str_length ];    COORD old;    COORD current; };/*** prototypes/forward declarations ***/void print_title();void draw_object( game_object & );void draw_interface();void print_point_message();void ball_move( game_object &, COORD, COORD );void get_input( short & );void ai_move( short &, game_object &, short );bool check_ball( game_object & );void gotoxy( int, int );void delay( int );/******************************************************************************** Main                                                                         ********************************************************************************/int main(){    srand( time( NULL ) ); // seed random number generator        /*** initialize game_objects ***/        game_object paddle1, paddle2, ball;    short dir; // direction the ball is traveling    /**********    | paddle1 |    **********/    paddle1.old.X = paddle1.current.X = pLEFT;    paddle1.old.Y = paddle1.current.Y = pCENTER;        // top string    paddle1.szTop[ 0 ] = '|';    paddle1.szTop[ 1 ] = 0;    paddle1.szTop[ 2 ] = 0;        // middle string    paddle1.szMiddle[ 0 ] = '|';    paddle1.szMiddle[ 1 ] = 0;    paddle1.szMiddle[ 2 ] = 0;        // bottom string    paddle1.szBottom[ 0 ] = '|';    paddle1.szBottom[ 1 ] = 0;    paddle1.szBottom[ 2 ] = 0;        /**********    | paddle2 |    **********/    paddle2.old.X = paddle2.current.X = pRIGHT;    paddle2.old.Y = paddle2.current.Y = pCENTER;        // top string    paddle2.szTop[ 0 ] = '|';    paddle2.szTop[ 1 ] = 0;    paddle2.szTop[ 2 ] = 0;        // middle string    paddle2.szMiddle[ 0 ] = '|';    paddle2.szMiddle[ 1 ] = 0;    paddle2.szMiddle[ 2 ] = 0;        // bottom string    paddle2.szBottom[ 0 ] = '|';    paddle2.szBottom[ 1 ] = 0;    paddle2.szBottom[ 2 ] = 0;        /*******    | ball |    *******/    ball.old.X = ball.current.X = pMIDDLE;    ball.old.Y = ball.current.Y = pCENTER;        // top string    ball.szTop[ 0 ] = 0;    ball.szTop[ 1 ] = 0;    ball.szTop[ 2 ] = 0;        // middle string    ball.szMiddle[ 0 ] = 219;    ball.szMiddle[ 1 ] = 0;    ball.szMiddle[ 2 ] = 0;        // bottom string    ball.szBottom[ 0 ] = 0;    ball.szBottom[ 1 ] = 0;    ball.szBottom[ 2 ] = 0;        print_title();    while( 1 ) {        delay( speed );        draw_interface();        draw_object( paddle1 );        draw_object( paddle2 );        draw_object( ball );                paddle1.old.Y = paddle1.current.Y;        paddle2.old.Y = paddle2.current.Y;                // determine whether ball is moving left or right        if ( ball.old.X < ball.current.X )            dir = d_RIGHT;        if ( ball.old.X > ball.current.X )            dir = d_LEFT;                // move the game objects        if ( kbhit() ) get_input( paddle1.current.Y );        ai_move( paddle2.current.Y, ball, dir );        ball_move( ball, paddle1.current, paddle2.current );                if ( check_ball( ball ) ) { // if one of the players misses the ball                        // reset the game objects            paddle1.old.X = paddle1.current.X = pLEFT;            paddle1.old.Y = paddle1.current.Y = pCENTER;            paddle2.old.X = paddle2.current.X = pRIGHT;            paddle2.old.Y = paddle2.current.Y = pCENTER;            ball.old.X = ball.current.X = pMIDDLE;            ball.old.Y = ball.current.Y = pCENTER;            randomize = true; // randomize horizontal direction of the ball                        print_point_message(); // print a message that the score has changed            delay( 3000 ); // wait three seconds            system( "cls" ); // clear the board and continue        }    }}/******************************************************************************** "Drawing" Functions                                                          ********************************************************************************//*** prints the title and some short information ***/void print_title(){    cout << "\n\n\n\n\n\n\n\n\n\t\t\tASCII Pong version 1.0\n\t\t\tby Muhammad al-Haider"         << "\n\t\t\tskulldrudgery@hotmail.com";    delay( 4000 );    system( "cls" );}/*** prints an object to the screen and clears the object's former position ***/void draw_object( game_object &object ){    // delete object at old location    for ( int i = 0; i < str_length - 1; i++ ) {        if ( object.szTop )<br>            gotoxy( object.old.X + i, object.old.Y ), cout &lt;&lt; <span class="cpp-literal">" "</span>;<br>    <br>        <span class="cpp-keyword">if</span> ( object.szMiddle )<br>            gotoxy( object.old.X + i, object.old.Y + <span class="cpp-number">1</span> ), cout &lt;&lt; <span class="cpp-literal">" "</span>;<br>        <br>        <span class="cpp-keyword">if</span> ( object.szBottom )<br>            gotoxy( object.old.X + i, object.old.Y + <span class="cpp-number">2</span>), cout &lt;&lt; <span class="cpp-literal">" "</span>;<br>    }<br>    <br>    <span class="cpp-comment">// draw object at new location</span><br>    <span class="cpp-keyword">if</span> ( object.szTop[ <span class="cpp-number">0</span> ] )<br>        gotoxy( object.current.X, object.current.Y ), cout &lt;&lt; object.szTop;<br>    <br>    <span class="cpp-keyword">if</span> ( object.szMiddle[ <span class="cpp-number">0</span> ] )<br>        gotoxy( object.current.X, object.current.Y + <span class="cpp-number">1</span> ), cout &lt;&lt; object.szMiddle;<br>        <br>    <span class="cpp-keyword">if</span> ( object.szBottom[ <span class="cpp-number">0</span> ] )<br>        gotoxy( object.current.X, object.current.Y + <span class="cpp-number">2</span>), cout &lt;&lt; object.szBottom;<br>}<br><br><span class="cpp-comment">/*** prints the "interface" of the game: the board, score and gamespeed ***/</span><br><span class="cpp-keyword">void</span> draw_interface()<br>{<br>    gotoxy( <span class="cpp-number">0</span>, <span class="cpp-number">0</span> ); <span class="cpp-comment">// reset the cursor, to begin printing from upper-left corner</span><br>    <br>    cout &lt;&lt; <span class="cpp-literal">"        Player 1: "</span> &lt;&lt; setw( <span class="cpp-number">2</span> ) &lt;&lt; p1score &lt;&lt; <span class="cpp-literal">"  Player 2: "</span> &lt;&lt; setw( <span class="cpp-number">2</span> )<br>         &lt;&lt; p2score &lt;&lt; <span class="cpp-literal">"\t    Gamespeed is currently: "</span> &lt;&lt; setw( <span class="cpp-number">2</span> ) &lt;&lt; abs( speed - <span class="cpp-number">100</span> )<br>         &lt;&lt; <span class="cpp-literal">"/80\n\n"</span>;<br>         <br>    cout &lt;&lt; <span class="cpp-literal">"        _________________________________________________________________\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"   A   |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"   S   |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"   C   |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"   I   |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"   I   |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"   P   |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"   O   |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"   N   |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"   G   |                                |                                |\n"</span><br>         &lt;&lt; <span class="cpp-literal">"       |________________________________|________________________________|\n"</span>;<br>}<br><br><span class="cpp-comment">/*** prints a message that the score has changed ***/</span><br><span class="cpp-keyword">void</span> print_point_message()<br>{<br>    gotoxy( pMIDDLE - <span class="cpp-number">10</span>, pCENTER - <span class="cpp-number">1</span> );<br>    cout &lt;&lt; <span class="cpp-literal">"                         "</span>;<br>    <br>    gotoxy( pMIDDLE - <span class="cpp-number">10</span>, pCENTER + <span class="cpp-number">1</span> );<br>    cout &lt;&lt; <span class="cpp-literal">"                         "</span>;<br>    <br>    gotoxy( pMIDDLE - <span class="cpp-number">10</span>, pCENTER );<br>    cout &lt;&lt; <span class="cpp-literal">"Oops! Score is "</span> &lt;&lt; p1score &lt;&lt; <span class="cpp-literal">" - "</span> &lt;&lt; p2score;<br>}<br>    <br><br><span class="cpp-comment">/*******************************************************************************<br>* "Moving" Functions                                                           *<br>*******************************************************************************/</span><br><br><span class="cpp-comment">/*** moves the ball and reflects it off the surfaces (paddles and borders) ***/</span><br><span class="cpp-keyword">void</span> ball_move( game_object &amp;ball, COORD p1, COORD p2 )<br>{<br>    <span class="cpp-keyword">static</span> DIRECTION Y_DIR = d_FLAT; <span class="cpp-comment">// y direction of the ball</span><br>    <span class="cpp-keyword">static</span> DIRECTION X_DIR = d_LEFT; <span class="cpp-comment">// x direction of the ball</span><br>    <br>    <span class="cpp-comment">// if the randomize flag is set, randomly choose directions and reset flag</span><br>    <span class="cpp-keyword">if</span> ( randomize ) {<br>        X_DIR = rand() % <span class="cpp-number">100</span> &lt; <span class="cpp-number">50</span> ? d_LEFT : d_RIGHT;<br>        Y_DIR = rand() % <span class="cpp-number">100</span> &lt; <span class="cpp-number">50</span> ? d_UP : d_DOWN;<br>        randomize = <span class="cpp-keyword">false</span>;<br>    }<br>    <br>    <span class="cpp-comment">// if the ball reaches the x coordinates (+1) of the left paddle…</span><br>    <span class="cpp-keyword">if</span> ( ball.current.X == pLEFT + <span class="cpp-number">1</span> ) {<br><br>        <span class="cpp-comment">// …check if any part of the paddle would "hit" it, if it hits the…</span><br>        <span class="cpp-keyword">if</span> ( ball.current.Y == p1.Y - <span class="cpp-number">1</span> ) { <span class="cpp-comment">// …top, reflect along y+ and x+</span><br>            Y_DIR = d_UP;<br>            X_DIR = d_RIGHT;<br>            <span class="cpp-keyword">if</span> ( speed &gt;= <span class="cpp-number">25</span> ) speed -= <span class="cpp-number">3</span>;<br>        } <span class="cpp-keyword">else</span><br>            <span class="cpp-keyword">if</span> ( ball.current.Y == p1.Y ) { <span class="cpp-comment">// …middle, reflect along x+ only</span><br>                Y_DIR = d_FLAT;<br>                X_DIR = d_RIGHT;<br>                <span class="cpp-keyword">if</span> ( speed &gt;= <span class="cpp-number">25</span> ) speed -= <span class="cpp-number">3</span>;<br>            } <span class="cpp-keyword">else</span><br>                <span class="cpp-keyword">if</span> ( ball.current.Y == p1.Y + <span class="cpp-number">1</span> ) { <span class="cpp-comment">// …bottom, reflect along y- and x+</span><br>                    Y_DIR = d_DOWN;<br>                    X_DIR = d_RIGHT;<br>                    <span class="cpp-keyword">if</span> ( speed &gt;= <span class="cpp-number">25</span> ) speed -= <span class="cpp-number">3</span>; <span class="cpp-comment">// speed increases each time the ball is hit</span><br>                }<br>    } <span class="cpp-comment">// end if ( ball.current.X == pLEFT + 1 )</span><br>    <br>    <span class="cpp-comment">// if the ball reaches the x coordinates (-1) of the right paddle…</span><br>    <span class="cpp-keyword">if</span> ( ball.current.X == pRIGHT - <span class="cpp-number">1</span> ) {<br>        <br>        <span class="cpp-comment">// …check if any part of the paddle would "hit" it, if it hits the…</span><br>        <span class="cpp-keyword">if</span> ( ball.current.Y == p2.Y - <span class="cpp-number">1</span> ) { <span class="cpp-comment">// …top, reflect along y+ and x-</span><br>            Y_DIR = d_UP;<br>            X_DIR = d_LEFT;<br>            <span class="cpp-keyword">if</span> ( speed &gt;= <span class="cpp-number">25</span> ) speed -= <span class="cpp-number">3</span>;<br>        } <span class="cpp-keyword">else</span><br>            <span class="cpp-keyword">if</span> ( ball.current.Y == p2.Y ) { <span class="cpp-comment">// …middle, reflect along x- only</span><br>                Y_DIR = d_FLAT;<br>                X_DIR = d_LEFT;<br>                <span class="cpp-keyword">if</span> ( speed &gt;= <span class="cpp-number">25</span> ) speed -= <span class="cpp-number">3</span>;<br>            } <span class="cpp-keyword">else</span><br>                <span class="cpp-keyword">if</span> ( ball.current.Y == p2.Y + <span class="cpp-number">1</span> ) { <span class="cpp-comment">// …bottom, reflect along y- and x-</span><br>                    Y_DIR = d_DOWN;<br>                    X_DIR = d_LEFT;<br>                    <span class="cpp-keyword">if</span> ( speed &gt;= <span class="cpp-number">25</span> ) speed -= <span class="cpp-number">3</span>;<br>                }<br>    } <span class="cpp-comment">// end if ( ball.current.Y == p2.current.Y - 1 )</span><br>    <br>    <span class="cpp-comment">// if the ball hits the top border…</span><br>    <span class="cpp-keyword">if</span> ( ball.current.Y == pTOP ) Y_DIR = d_DOWN; <span class="cpp-comment">// reflect along y-</span><br>    <br>    <span class="cpp-comment">// if the ball hits the bottom border…</span><br>    <span class="cpp-keyword">if</span> ( ball.current.Y == pBOTTOM - <span class="cpp-number">2</span> ) Y_DIR = d_UP; <span class="cpp-comment">// reflect along y+</span><br>    <br>    <span class="cpp-comment">// update the old coordinates to the current ones</span><br>    ball.old.X = ball.current.X;<br>    ball.old.Y = ball.current.Y;<br>    <br>    <span class="cpp-comment">// update the coordinates of the ball according to the directions the it's moving</span><br>    ball.current.X += X_DIR;<br>    ball.current.Y += Y_DIR;<br>}<br><br><span class="cpp-comment">/*** moves the computer paddle according to the ai routine ***/</span><br><span class="cpp-keyword">void</span> ai_move( <span class="cpp-keyword">short</span> &amp;y, game_object &amp;ball, <span class="cpp-keyword">short</span> h_direction )<br>{   <br>    <span class="cpp-keyword">static</span> DIRECTION dir = d_UP; <span class="cpp-comment">// vertical direction</span><br>    <span class="cpp-keyword">static</span> <span class="cpp-keyword">int</span> dcounter = <span class="cpp-number">0</span>; <span class="cpp-comment">// number of lines moved in one direction</span><br>    <br>    <span class="cpp-comment">// if the ball is close to the right paddle and is traveling that way…</span><br>    <span class="cpp-keyword">if</span> ( ball.current.X &gt; <span class="cpp-number">60</span> &amp;&amp; h_direction == d_RIGHT ) {<br>        dcounter = <span class="cpp-number">0</span>; <span class="cpp-comment">// reset counter</span><br>        <br>        <span class="cpp-keyword">if</span> ( y &gt; ball.current.Y ) <span class="cpp-comment">// if the paddle is lower than the ball, move up</span><br>            y–;<br>        <br>        <span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span> ( y &lt; ball.current.Y ) <span class="cpp-comment">// if higher, move down</span><br>            y++;<br>    } <span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span> ( h_direction == d_RIGHT ) {<br>        <span class="cpp-comment">// if the ball is not close, the paddle moves randomly</span><br><br>    <br>        <span class="cpp-keyword">if</span> ( y == pTOP ) dir = d_DOWN;<br>        <span class="cpp-keyword">else</span><br>            <span class="cpp-keyword">if</span> ( y == pBOTTOM - <span class="cpp-number">2</span> ) dir = d_UP;<br>            <span class="cpp-keyword">else</span> <span class="cpp-comment">// if the dcounter is more than five, change to a random direction </span><br>                <span class="cpp-keyword">if</span> ( dcounter == <span class="cpp-number">8</span> ) dir = rand() % <span class="cpp-number">2</span> == <span class="cpp-number">0</span> ? d_UP : d_DOWN;<br>    <br>        dcounter++;<br>        y += dir;<br>    <br>        <span class="cpp-comment">// reset the counter for the number of lines moved</span><br>        <span class="cpp-keyword">if</span> ( dcounter &gt; <span class="cpp-number">8</span> ) dcounter = <span class="cpp-number">0</span>;<br>    }<br>}<br><br><span class="cpp-comment">/*******************************************************************************<br>* Input Functions                                                              *<br>*******************************************************************************/</span><br><br><span class="cpp-comment">/*** get direction input from player, and change y coordinate appropriately ***/</span><br><span class="cpp-keyword">void</span> get_input( <span class="cpp-keyword">short</span> &amp;y )<br>{       <br>    <span class="cpp-keyword">if</span> ( GetAsyncKeyState( <span class="cpp-number">38</span> ) &amp;&amp; y != pTOP ) y–; <span class="cpp-comment">// "up" key, ignore if paddle is at top</span><br>    <span class="cpp-keyword">if</span> ( GetAsyncKeyState( <span class="cpp-number">40</span> ) &amp;&amp; y != pBOTTOM - <span class="cpp-number">2</span> ) y++; <span class="cpp-comment">// "down" key, ignore if paddle is</span><br>                                                           <span class="cpp-comment">// at bottom (- 2 to account for</span><br>                                                           <span class="cpp-comment">// paddle length)</span><br>}<br><br><span class="cpp-comment">/*******************************************************************************<br>* Winning Condition Functions                                                  *<br>*******************************************************************************/</span><br><br><span class="cpp-comment">/*** check if the ball has gone "out" ***/</span><br><span class="cpp-keyword">bool</span> check_ball( game_object &amp;ball )<br>{<br>    <span class="cpp-keyword">if</span> ( ball.current.X == LOSE_LINE_RIGHT ) { <span class="cpp-comment">// if player 2 misses the ball…</span><br>        p1score++; <span class="cpp-comment">// …player one scores</span><br>        <span class="cpp-keyword">if</span> ( speed - <span class="cpp-number">1</span> &lt; <span class="cpp-number">100</span> ) speed += <span class="cpp-number">2</span>; <span class="cpp-comment">// if the game speed is over 0, decrease by 2</span><br>        randomize = <span class="cpp-keyword">true</span>; <span class="cpp-comment">// choose a random direction for the ball ( left or right)</span><br>        <span class="cpp-keyword">return</span> <span class="cpp-keyword">true</span>; <span class="cpp-comment">// the ball was missed</span><br>    }<br>    <br>    <span class="cpp-keyword">if</span> ( ball.current.X == LOSE_LINE_LEFT ) { <span class="cpp-comment">// if player 1 misses the ball…</span><br>        p2score++; <span class="cpp-comment">// …player two scores</span><br>        <span class="cpp-keyword">if</span> ( speed - <span class="cpp-number">1</span> &lt; <span class="cpp-number">100</span> ) speed += <span class="cpp-number">2</span>; <span class="cpp-comment">// if the game speed is over 0, decrease by 2</span><br>        randomize = <span class="cpp-keyword">true</span>; <span class="cpp-comment">// choose a random direction for the ball ( left or right)</span><br>        <span class="cpp-keyword">return</span> <span class="cpp-keyword">true</span>; <span class="cpp-comment">// the ball was missed</span><br>    }<br>    <br>    <span class="cpp-keyword">return</span> <span class="cpp-keyword">false</span>; <span class="cpp-comment">// the ball was not missed</span><br>}<br><br><span class="cpp-comment">/*******************************************************************************<br>* Utility Functions                                                            *<br>*******************************************************************************/</span><br><br><span class="cpp-comment">// move the cursor to the given coordinates</span><br><span class="cpp-keyword">void</span> gotoxy( <span class="cpp-keyword">int</span> x, <span class="cpp-keyword">int</span> y )<br>{<br>    COORD pos;<br>    HANDLE screen = GetStdHandle( STD_OUTPUT_HANDLE );<br><br>    pos.X = x;<br>    pos.Y = y;<br><br>    SetConsoleCursorPosition( screen, pos );<br>}<br><br><span class="cpp-comment">// delay for a given number of milliseconds - busy waiting</span><br><span class="cpp-keyword">inline</span> <span class="cpp-keyword">void</span> delay( <span class="cpp-keyword">int</span> m )<br>{<br>    <span class="cpp-keyword">for</span> ( time_t end = clock() + m; clock() &lt; end; );<br>}<br><br><br><br></pre></div><!–ENDSCRIPT–><br><br>@ superpig feel the impotent force of my ratings++ &#111;n you
skulldrudgery--A tricky bit of toil

This topic is closed to new replies.

Advertisement