Server Help Forum Index Server Help
Community forums for Subgame, ASSS, and bots
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   StatisticsStatistics   RegisterRegister 
 ProfileProfile   Login to check your private messagesLogin to check your private messages   LoginLogin (SSL) 

Server Help | ASSS Wiki (0) | Shanky.com
I got bored and made a Tic-Tac-Toe game in SDL.

 
Post new topic   Reply to topic Printable version
 View previous topic  sizeof(unions + struct + bitfield) Post :: Post Know of any quality material on ANNs?  View next topic  
Author Message
Animate Dreams
Gotta buy them all!
(Consumer whore)


Age:36
Gender:Gender:Male
Joined: May 01 2004
Posts: 821
Location: Middle Tennessee
Offline

PostPosted: Mon Jan 25, 2010 11:15 pm    Post subject: I got bored and made a Tic-Tac-Toe game in SDL. Reply to topic Reply with quote

I wanted to learn SDL, and this is the first actual application I've made. I could use some advice on better ways to do things, if you guys have the time.

Code: Show/Hide
/* Tic-Tac-Toe
** By Kevin J. Russell
** 2010.01.19 January 19th, 2010
**
** This is my first game.
** It's Tic-Tac-Toe in C++/SDL.
*/


/* Includes */
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"


/* Screen Attributes */
const int SCREEN_WIDTH = 600;
const int SCREEN_HEIGHT = 600;
const int SCREEN_BPP = 32;

enum Mark
{ markOpen, markX, markO };


/* Function Prototypes */
void ApplySurface(int x, int y, SDL_Surface *source, SDL_Surface *destination);
void MarkSquare(int square, Mark mark);
void Logic();

/* Surfaces */
SDL_Surface *screen = NULL;
SDL_Surface *background = NULL;
SDL_Surface *x = NULL;
SDL_Surface *o = NULL;
SDL_Surface *win = NULL;


SDL_Event event;

Mark board[10];
Mark mark = markO;
bool quit = false;


int main(int argc, char *args[])
{
    for (int i = 0; i < 10; i++)
        board[i] = markOpen;
   
    SDL_Init(SDL_INIT_EVERYTHING);
    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT,
        SCREEN_BPP, SDL_SWSURFACE);
    SDL_WM_SetCaption("Tic-Tac-Toe", NULL);
   
    background = SDL_DisplayFormat(IMG_Load("background.png"));
    x = SDL_DisplayFormat(IMG_Load("x.png"));
    o = SDL_DisplayFormat(IMG_Load("o.png"));
   
    ApplySurface(0, 0, background, screen);
    SDL_Flip(screen);
   
    while (quit == false)
    {
        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_MOUSEBUTTONDOWN)
            {
                // Sneaky algorithm to convert mouse pos to square number
                MarkSquare((event.button.x/200)
                    + (event.button.y/200)*3 +1, mark);
               
                Logic();
            }
            if (event.type == SDL_QUIT)
                quit = true;
        }
    }
    SDL_FreeSurface(win);
    SDL_FreeSurface(background);
    SDL_FreeSurface(x);
    SDL_FreeSurface(o);
    SDL_Quit();
   
    return 0;
}


void ApplySurface(int x, int y, SDL_Surface *source, SDL_Surface *destination)
{
    SDL_Rect offset;

    offset.x = x;
    offset.y = y;

    SDL_BlitSurface(source, NULL, destination, &offset);
}


void MarkSquare(int square, Mark mark)
{
    board[square] = mark;

    // Get placement co-ords based on square number.
    int xpos = (((square-1)%3) *200) +10;
    int ypos = (((square-1)/3) *200) +10;
   
    if (mark == markX)
        ApplySurface(xpos, ypos, x, screen);
    else if (mark == markO)
        ApplySurface(xpos, ypos, o, screen);
}


void Logic()
{
    if (mark == markX)
        mark = markO;
    else if (mark == markO)
        mark = markX;
   
    // Victory Check
    if (board[1] == board[2] && board[1] == board[3] && board[1] != markOpen)
    {
        if (board[1] == markX)
            win = SDL_DisplayFormat(IMG_Load("xwin.png"));
        else
            win = SDL_DisplayFormat(IMG_Load("owin.png"));
        ApplySurface(0, 201, win, screen);
    }
    else if (board[4] == board[5] && board[4] == board[6] && board[4] != markOpen)
    {
        if (board[4] == markX)
            win = SDL_DisplayFormat(IMG_Load("xwin.png"));
        else
            win = SDL_DisplayFormat(IMG_Load("owin.png"));
        ApplySurface(0, 201, win, screen);
    }
    else if (board[7] == board[8] && board[7] == board[9] && board[7] != markOpen)
    {
        if (board[7] == markX)
            win = SDL_DisplayFormat(IMG_Load("xwin.png"));
        else
            win = SDL_DisplayFormat(IMG_Load("owin.png"));
        ApplySurface(0, 201, win, screen);
    }
    else if (board[1] == board[4] && board[1] == board[7] && board[1] != markOpen)
    {
        if (board[1] == markX)
            win = SDL_DisplayFormat(IMG_Load("xwin.png"));
        else
            win = SDL_DisplayFormat(IMG_Load("owin.png"));
        ApplySurface(0, 201, win, screen);
    }
    else if (board[2] == board[5] && board[2] == board[8] && board[2] != markOpen)
    {
        if (board[2] == markX)
            win = SDL_DisplayFormat(IMG_Load("xwin.png"));
        else
            win = SDL_DisplayFormat(IMG_Load("owin.png"));
        ApplySurface(0, 201, win, screen);
    }
    else if (board[3] == board[6] && board[3] == board[9] && board[3] != markOpen)
    {
        if (board[3] == markX)
            win = SDL_DisplayFormat(IMG_Load("xwin.png"));
        else
            win = SDL_DisplayFormat(IMG_Load("owin.png"));
        ApplySurface(0, 201, win, screen);
    }
    else if (board[1] == board[5] && board[1] == board[9] && board[1] != markOpen)
    {
        if (board[1] == markX)
            win = SDL_DisplayFormat(IMG_Load("xwin.png"));
        else
            win = SDL_DisplayFormat(IMG_Load("owin.png"));
        ApplySurface(0, 201, win, screen);
    }
    else if (board[3] == board[5] && board[3] == board[7] && board[3] != markOpen)
    {
        if (board[3] == markX)
            win = SDL_DisplayFormat(IMG_Load("xwin.png"));
        else
            win = SDL_DisplayFormat(IMG_Load("owin.png"));
        ApplySurface(0, 201, win, screen);
    }
    SDL_Flip(screen);
}


You should have seen what I had before. I had programmed in the co-ordinates for each square manually, so my game loop looked like this:
Code: Show/Hide
if (event.type == SDL_MOUSEBUTTONDOWN)
            {
                if (event.button.x <= 200 && event.button.y <= 200)
                    MarkSquare(1, mark);
                if (event.button.x > 200 && event.button.x <= 400 && event.button.y <= 200)
                    MarkSquare(2, mark);
                if (event.button.x > 400 && event.button.y <= 200)
                    MarkSquare(3, mark);
                if (event.button.x <= 200 && event.button.y > 200 && event.button.y <= 400)
                    MarkSquare(4, mark);
                if (event.button.x > 200 && event.button.x <= 400 && event.button.y > 200 && event.button.y <= 400)
                    MarkSquare(5, mark);
                if (event.button.x > 400 && event.button.y > 200 && event.button.y <= 400)
                    MarkSquare(6, mark);
                if (event.button.x <= 200 && event.button.y > 400)
                    MarkSquare(7, mark);
                if (event.button.x > 200 && event.button.x <= 400 && event.button.y > 400)
                    MarkSquare(8, mark);
                if (event.button.x > 400 && event.button.y > 400)
                    MarkSquare(9, mark);
               
                Logic();
            }


I still have something very similar for the win condition. I check each possible win state. I realize I should probably just check the column and the row of the square just posted, but I'm not sure how to do that. Should I use a multi-dimensional array instead? Then, I think I could just take the square that was just played, board[x][y], and I could check in a loop like board[x][i], and board[i][y]. Something like that.

Source and executable attached. You'll need SDL installed to compile, though.




TicTacToe.7z - 284.35 KB
File downloaded or viewed 101 time(s)
Back to top
View users profile Send private message Add User to Ignore List Send email Visit posters website AIM Address MSN Messenger
Samapico
No, these DO NOT look like penises, ok?


Joined: May 08 2003
Posts: 1252
Offline

PostPosted: Mon Jan 25, 2010 11:27 pm    Post subject: Reply to topic Reply with quote

A loop in a 2D array would definitely save you some work.
You're also wasting board[0] tongue.gif

A loop to scroll through a 2D array, without needing too many weird control structures, could look like this:

Code: Show/Hide

//check rows
for (int j = 0; j < 3; j++) //for each row
if (board[0][j] != markOpen && board[0][j] == board[1][j] && board[0][j] == board[2][j])
  win(board[0][j]);

//where win is a function that takes a Mark argument
//do the same for columns

You could have another for in there, but you'd have to make tricky stuff to compare each cell. Like store the first value, compare each one, and break out the for loop at some point... If you could have a 4x4 or larger board, it would be worth it, but not here, imo.
_________________
(Insert a bunch of dead links here)
Back to top
View users profile Send private message Add User to Ignore List
Animate Dreams
Gotta buy them all!
(Consumer whore)


Age:36
Gender:Gender:Male
Joined: May 01 2004
Posts: 821
Location: Middle Tennessee
Offline

PostPosted: Fri Jan 29, 2010 5:21 pm    Post subject: Reply to topic Reply with quote

Code: Show/Hide
/* Tic-Tac-Toe
** By Kevin J. Russell
** 2010.01.19 January 19th, 2010
**
** This is my first game.
** It's Tic-Tac-Toe in C++/SDL.
*/


/* Includes */
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"


/* Screen Attributes */
const int SCREEN_WIDTH = 600;
const int SCREEN_HEIGHT = 600;
const int SCREEN_BPP = 32;

enum Mark
{ markOpen, markX, markO };


/* Function Prototypes */
void ApplySurface(int x, int y, SDL_Surface *source, SDL_Surface *destination);
void MarkSquare(int squarex, int squarey, Mark mark);
void Logic();

/* Surfaces */
SDL_Surface *screen = NULL;
SDL_Surface *background = NULL;
SDL_Surface *x = NULL;
SDL_Surface *o = NULL;
SDL_Surface *win = NULL;


SDL_Event event;

//Mark board[10];
Mark board[3][3];
Mark mark = markO;
bool quit = false;


int main(int argc, char *args[])
{
    /*for (int i = 0; i < 10; i++)
        board[i] = markOpen;*/
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            board[i][j] = markOpen;
   
    SDL_Init(SDL_INIT_EVERYTHING);
    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT,
        SCREEN_BPP, SDL_SWSURFACE);
    SDL_WM_SetCaption("Tic-Tac-Toe", NULL);
   
    background = SDL_DisplayFormat(IMG_Load("background.png"));
    x = SDL_DisplayFormat(IMG_Load("x.png"));
    o = SDL_DisplayFormat(IMG_Load("o.png"));
   
    ApplySurface(0, 0, background, screen);
    SDL_Flip(screen);
   
    while (quit == false)
    {
        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_MOUSEBUTTONDOWN)
            {
                // Sneaky algorithm to convert mouse pos to square co-ord
                MarkSquare(event.button.x/200, event.button.y/200, mark);
               
                Logic();
            }
            if (event.type == SDL_QUIT)
                quit = true;
        }
    }
    SDL_FreeSurface(win);
    SDL_FreeSurface(background);
    SDL_FreeSurface(x);
    SDL_FreeSurface(o);
    SDL_Quit();
   
    return 0;
}


void ApplySurface(int x, int y, SDL_Surface *source, SDL_Surface *destination)
{
    SDL_Rect offset;

    offset.x = x;
    offset.y = y;

    SDL_BlitSurface(source, NULL, destination, &offset);
}


void MarkSquare(int squarex, int squarey, Mark mark)
{
    board[squarex][squarey] = mark;

    // Get placement co-ords based on square number   
    if (mark == markX)
        ApplySurface(200 * squarex + 10, 200 * squarey + 10, x, screen);
    else if (mark == markO)
        ApplySurface(200 * squarex + 10, 200 * squarey + 10, o, screen);
}


void Logic()
{
    // Set the win surface to the previous player's mark, in case of victory.
    // Then flip the mark for the next turn.
    if (mark == markX)
    {
        win = SDL_DisplayFormat(IMG_Load("xwin.png"));
        mark = markO;
    }
    else
    {
        win = SDL_DisplayFormat(IMG_Load("owin.png"));
        mark = markX;
    }
   
    // Victory Check
    for (int i = 0; i < 3; i++)
    {
        if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != markOpen)
            ApplySurface(0, 201, win, screen);
        if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != markOpen)
            ApplySurface(0, 201, win, screen);
    }
    if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != markOpen)
        ApplySurface(0, 201, win, screen);
    if (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] != markOpen)
        ApplySurface(0, 201, win, screen);
   
    SDL_Flip(screen);
}


Got it set up with a multidimensional array, now. I think it's basically done until I want to come back and add either game states(so I can actually stop the game) or AI.
Also, lol. Never seen a topic moved OUT of trash talk.
Back to top
View users profile Send private message Add User to Ignore List Send email Visit posters website AIM Address MSN Messenger
rootbear75
Novice


Age:34
Gender:Gender:Male
Joined: Mar 10 2005
Posts: 76
Location: Hollywood, CA
Offline

PostPosted: Tue Feb 02, 2010 4:01 am    Post subject: Reply to topic Reply with quote

Feature request: Button along top or bottom that you can use to make a new game.

just make it start the program over....

like at the top have a
Code: Show/Hide

Label start;

then at the bottom
have a
Code: Show/Hide

goTo(start);


or something along that line.
Back to top
View users profile Send private message Add User to Ignore List AIM Address MSN Messenger
Samapico
No, these DO NOT look like penises, ok?


Joined: May 08 2003
Posts: 1252
Offline

PostPosted: Tue Feb 02, 2010 5:21 pm    Post subject: Reply to topic Reply with quote

Don't listen to rootbear, he wants to make you program like it's 1985 again.

You can make your main loop back at the beginning in a much cleaner way tongue.gif
You might only need to dump the initialization stuff in a function, and call that function when you hit restart.
Back to top
View users profile Send private message Add User to Ignore List
Animate Dreams
Gotta buy them all!
(Consumer whore)


Age:36
Gender:Gender:Male
Joined: May 01 2004
Posts: 821
Location: Middle Tennessee
Offline

PostPosted: Thu Feb 04, 2010 12:46 am    Post subject: Reply to topic Reply with quote

Samapico wrote:
Don't listen to rootbear, he wants to make you program like it's 1985 again.

You can make your main loop back at the beginning in a much cleaner way tongue.gif
You might only need to dump the initialization stuff in a function, and call that function when you hit restart.


Ah, there is so little initialization, I think it just clutters things to move it into a function. I understand the need in larger projects, and in one way I am trying to teach myself some of the things I'd need for a larger project, but bad decisions are still bad decisions.

I plan on using this as an intro into game states, actually:
http://lazyfoo.net/articles/article06/index.php

That's the same place I've been using to learn SDL, although I'm only on Tutorial 9. Schoolwork has just started to get rough as well... so I might not get back to the tutorials until school is out.
To be honest, I'm not opposed to using goto for game states.
Back to top
View users profile Send private message Add User to Ignore List Send email Visit posters website AIM Address MSN Messenger
Samapico
No, these DO NOT look like penises, ok?


Joined: May 08 2003
Posts: 1252
Offline

PostPosted: Thu Feb 04, 2010 8:34 am    Post subject: Reply to topic Reply with quote

Animate Dreams wrote:
Ah, there is so little initialization, I think it just clutters things to move it into a function.
Your main is cluttered sa_tongue.gif

And what I was saying is, if you want to be able to restart the game, you'll probably need to repeat the initialization somewhere in the code, so you'll want it in a function.
Back to top
View users profile Send private message Add User to Ignore List
Animate Dreams
Gotta buy them all!
(Consumer whore)


Age:36
Gender:Gender:Male
Joined: May 01 2004
Posts: 821
Location: Middle Tennessee
Offline

PostPosted: Sat Feb 06, 2010 2:13 am    Post subject: Reply to topic Reply with quote

Actually, I can do it in three lines. Something like
for (int i = 0; i < 9; i++)
board[i] = markOpen;
ApplySurface(background, screen, null, null);
SDL_Flip(screen);

okay four.
Back to top
View users profile Send private message Add User to Ignore List Send email Visit posters website AIM Address MSN Messenger
Samapico
No, these DO NOT look like penises, ok?


Joined: May 08 2003
Posts: 1252
Offline

PostPosted: Sat Feb 06, 2010 2:58 pm    Post subject: Reply to topic Reply with quote

... still, you don't want to repeat these 4 lines if you want to do the operation more than once in your code. Making a function for these 4 lines would be far from cluttering

It's not rare to see functions with even only 1 line of code
Back to top
View users profile Send private message Add User to Ignore List
Display posts from previous:   
Post new topic   Reply to topic    Server Help Forum Index -> Non-Subspace Related Coding All times are GMT - 5 Hours
Page 1 of 1

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You can attach files in this forum
You can download files in this forum
View online users | View Statistics | View Ignored List


Software by php BB © php BB Group
Server Load: 651 page(s) served in previous 5 minutes.

phpBB Created this page in 0.520707 seconds : 36 queries executed (78.7%): GZIP compression disabled