Pages - Menu

Monday 8 October 2012

Implementation of a Tic Tac Toe game in C

The game allows you to customize the number of players, their names, symbols and colours to be displayed on the board, as well as the board's size and the number of symbols required for winning.

The functions  used  for console graphics have been discussed in a previous article:
#include<stdio.h>
#include"GRAPH_LIB.h"

/*--------------DATA TYPES--------------*/
typedef struct Player
{
    char *name;//player's name
    char *symbol;//player's symbol on the table
    char *colour;//player's colour on the table
    struct Player *next;//pointer to the next element of the list
} player;

typedef struct Matrix
{
    char *symbol;//symbol placed
    int column;
    int row;
    struct Matrix *next;//pointer to the next element of the list
}matrix; 

/*----------------GLOBALS----------------*/
player *firstP = NULL;//pointer to the first element of a singly linked list
                      //containing elements of type player
matrix *firstM = NULL;//pointer to the first element of a singly linked list
                      //containing elements of type matrix
int rows = 0, columns = 0;//number of rows and column of the table
int numberOfPlayers = 0;//the number of players
int symbolsToWin = 0;//the number of symbols required for victory
//arrays for the eight directions
int directionsX[] = {0,0,-1,1,-1,1,-1,1};
int directionsY[] = {-1,1,0,0,-1,-1,1,1};

/*---------------PROTOTYPES---------------*/

/*
 * Description:
 *  Prints the banner at the top
 */
void Header(void);

/*
 * Description:
 *  Adds a element of type player to a singly linked list
 * Parameters:
 *  first  - pointer to the first element of a 
             singly linked list containing elemnts of type player
 *  name   - pointer to the player's to be added name
 *  symbol - pointer to the player's to be added symbol
 *  colour - pointer to the player's to be added colour
 */
player *AddPlayer(player *first, char *name, char *symbol, char *colour);

/*
 * Description:
 *  Adds a element of type matrix to a singly linked list
 * Parameters:
 *  first  - pointer to the first element of a 
             singly linked list containing elemnts of type matrix
 *  symbol - pointer to the element of the matrix's symbol
 *  row    - number of row from the matrix
 *  column - number of column from the matrix
 */
matrix *AddToMatrix(matrix *first, char *symbol, int row, int column);

/*
 * Description:
 *  Sets all the elements of matrix structure used as table to "-"
 */
void InitialiseTable(void);

/*
 * Description:
 *  Decides the colour for each box of the table
 * Parameters:
 *  symbol - symbol
 *  colour - pointer to the colour to be painted
 */
void DecideColour(char symbol[], char *colour);

/*
 * Description:
 *  Displays the table
 * Parameters:
 *  horizontalCoordinate - horizontal starting pint of the table
 *  vericalCoordinate    - vertical starting point of the table
 */
void PrintTable(int horizontalCoordinate, int verticalCoordinate);

/*
 * Description:
 *  Selecting game properties regarding the players
 */
void CustomizePlayers(void);

/*
 * Description:
 *  Selecting game properties regarding the table
 */
void CustomizeTable(void);

/*
 * Description:
 *  Checks if the game won won by one of the players
 * Parameters:
 *  p - pointer to the first element of a singly linked list 
        containing elements of type player
 * Returns:
 *  0 - none of the players hasn't won
 *  1 - one of the players has won the game
 */
int CheckForWin(player *p);

/*
 * Description:
 *  Checks if there are any positions left unccupied on the table
 * Returns:
 *  0 - there is at least one position on the table left unoccupied
 *  1 - all the positions on the table are occupied
 */
int FullTable(void);

/*
 * Description:
 *  Contains the game's logic
 */
void Gameplay(void);

/*
 * Description:
 *  Starts the game
 */
void Launcher(void);

/*-------------IMPLEMENTATION-------------*/

void Header(void)
{
    DrawRectangle(0,0,60,5,"cyan");
    GoTo(23,1);
    Colour("cyan","white");
    printf("  TIC TAC TOE");
    GoTo(24,2);
    printf("  July 2012");
    GoTo(21,3);
    printf("  %cVINTAGE CODING",64);
}

player *AddPlayer(player *first, char *name, char *symbol, char *colour)
{
    player *p, *q;

    p = (player*)malloc(sizeof(player));
    p->name = (char*)malloc(strlen(name)+1);
    p->symbol = (char*)malloc(strlen(symbol)+1);
    p->colour = (char*)malloc(strlen(symbol)+1);

    p->next = NULL;
    strcpy(p->name,name);
    strcpy(p->symbol,symbol);
    strcpy(p->colour,colour);

    if(p == NULL || p->name == NULL || p->symbol == NULL || p->colour == NULL)
    {
        return 0;
    }
    else if (first == NULL)
    {
        return p;
    }
    else
    {
        q = first;
        while(q->next != NULL)
        {
            q = q->next;
        }
        q->next = p;
        return first;
    }
}

matrix *AddToMatrix(matrix *first, char *symbol, int row, int column)
{
    matrix *p, *q;

    p = (matrix*)malloc(sizeof(matrix));
    p->symbol = (char*)malloc(sizeof(matrix));

    p->next = NULL;
    strcpy(p->symbol,symbol);
    p->row = row;
    p->column = column;

    if(p == NULL || p->symbol == NULL)
    {
        return 0;
    }
    else if (first == NULL)
    {
        return p;
    }
    else
    {
        q = first;
        while(q->next != NULL)
        {
            q = q->next;
        }
        q->next = p;
        return first;
    }
}

void InitialiseTable(void)
{
    int i = 0, j = 0, k = 0;
    char *string = NULL;
    char row[3], column[3];

    string = (char*)malloc(7*sizeof(char));

    for(j=0; j<rows; j++)
    {
        for(i=0; i<columns; i++)
        {
            *string = NULL;
            itoa(i+1,column,10);
            itoa(j+1,row,10);
            strcpy(string,column);
            strcat(string,"-");
            strcat(string,row);
            firstM=AddToMatrix(firstM,string,j,i);
        }
    }
}

void DecideColour(char symbol[], char *colour)
{
    int ok=0;
    player *p;
    p = firstP;
    while(p != NULL)
    {
        if(strcmp(p->symbol,symbol) == 0)
        {
            strcpy(colour,p->colour);
            ok=1;
        }
        p = p->next;
    }
    if(ok == 0)
    {
        strcpy(colour,"white");
    }
}

void PrintTable(int horizontalCoordinate, int verticalCoordinate)
{
    unsigned int i = 0, j = 0;
    char colour[20];
    matrix *p = NULL;
    DrawGrid(horizontalCoordinate,verticalCoordinate,3,3,columns,rows,"black");
    for(j=0; j<rows; j++)
    {
        p=firstM;
        for(i=0; i<columns; i++)
        {
            p = firstM;
            while(p != NULL)
            {
                if((i == p->column) && (j == p->row))
                {
                    DecideColour(p->symbol,colour);
                    DrawRectangle(1+horizontalCoordinate+i+3*i,
                                  1+verticalCoordinate+j+3*j,3,3,colour);
                    GoTo(1+horizontalCoordinate+i+3*i+(3-strlen(p->symbol))/2,
                         1+verticalCoordinate+j+3*j+1);
                    Colour(colour,"dark gray");
                    puts(p->symbol);
                    break;
                }
                else
                {
                    p = p->next;
                }
            }
        }
    }
}

void CustomizePlayers(void)
{
    int i = 0;
    char name[12], symbol[3], colour[20];

    Header();
    GoTo(14,7);
    Colour("dark blue","gray");
    printf("Enter the number of players: ");
    scanf("%d",&numberOfPlayers);
    if(numberOfPlayers < 0) numberOfPlayers=1;
    if(numberOfPlayers > 5) numberOfPlayers=5;

    for(i=0; i<numberOfPlayers; i++)
    {
        DrawRectangle(18,10+i*3+i*3,22,4,"dark blue");
        GoTo(18,10+i*3+i*3);
        Colour("dark blue","gray");
        printf("       Player %d",i+1);
        GoTo(18,10+i*3+i*3+1);
        printf(" Name  : ");
        scanf("%s",name);
        GoTo(18,10+i*3+i*3+2);
        printf(" Symbol: ");
        scanf("%s",symbol);
        GoTo(18,10+i*3+i*3+3);
        printf(" Colour: ");
        scanf("%s",colour);
        firstP = AddPlayer(firstP,name,symbol,colour);
        fflush(stdin);
    }
}

void CustomizeTable(void)
{
    int i = 0;
    int orizontalCoordinate = 0;
    Header();
    GoTo(12,15);
    Colour("dark blue","gray");
    printf(" Enter the number of rows          : ");
    scanf("%d",&rows); 
    if(rows>5) rows = 5;
    GoTo(12,17);
    printf(" Enter the number of columns       : ");
    scanf("%d",&columns); 
    if(columns>5) columns = 5;
    orizontalCoordinate = (60-(rows*3+rows))/2;
    InitialiseTable();
    GoTo(12,19);
    printf(" Enter the number of symbols to win: ");
    scanf("%d",&symbolsToWin);
}

int CheckForWin(player *p)
{
    int i = 0, j = 0, k = 0;
    int counter = 0;
    int x = 0, y = 0;
    matrix *q = firstM;
    matrix *m = NULL;
    
    while(q != NULL)
    {
        if(strcmp(q->symbol,p->symbol) == 0)
        {
            counter = 1;
            for(k=0; k<8; k++)
            {
                m=firstM;
                while(counter != symbolsToWin && m != NULL)
                {
                    x = q->column+directionsX[k]*counter;
                    y = q->row+directionsY[k]*counter;
                    if(m->column == x && m->row == y && strcmp(m->symbol,p->symbol)==0
                      && x<columns && y<rows)
                    {
                        counter++;
                        if(counter == symbolsToWin)
                            return 1;
                        else m = firstM;
                    }
                    m = m->next;
                }
                counter = 1;
            }
        }
        q = q->next;
    }
    return 0;
}

int FullTable(void)
{
    matrix *p = firstM;
    char row[3], column[3];
    char *string = NULL;
    int ok = 0;
    string = (char*)malloc(7*sizeof(char));

    while(p != NULL)
    {
        *string = NULL;
        itoa(p->row+1,row,10);
        itoa(p->column+1,column,10);
        strcpy(string,column);
        strcat(string,"-");
        strcat(string,row);
        if(strcmp(string,p->symbol) == 0)
        {
            return 0;
        }
        p = p->next;
    }
    return 1;
}

void Gameplay(void)
{
    int i = 0, j = 0, k = 0;
    int ok = -1;
    int full = -1;
    int row = 0, column = 0;
    char r[3], c[3];
    char *string = NULL;
    char *buff = NULL;
    char c1, c2;
    player *p = firstP;
    matrix *q = firstM;

    string = (char*)malloc(7*sizeof(char));
    buff = (char*)malloc(7*sizeof(char));

    while(ok != 1 || full != 1)
    {
        ConsoleColours("dark gray","white");
        Header();
        PrintTable((60-(rows*3+rows))/2,8);
        full = FullTable();
        if(full == 0)
        {
            GoTo((60-strlen(p->name)-3)/2,rows*3+rows+3+5+4);
            Colour("dark blue","gray");
            printf("%s's turn",p->name);
            GoTo(10,rows*3+rows+4+5+4+2);
            printf("Enter your coordinates of choice (x-y): ");
            scanf("%s",buff);
            column = atoi(strtok(buff,"-")); column--;
            row = atoi(strtok(NULL," ")); row--;

            for(j=0; j<rows; j++)
            {
                for(i=0; i<columns; i++)
                {
                    q = firstM;
                    while(q != NULL)
                    {
                        *string = NULL;
                        itoa(q->row+1,r,10);
                        itoa(q->column+1,c,10);
                        strcpy(string,c);
                        strcat(string,"-");
                        strcat(string,r);
                        if((q->row == row) && (q->column == column) && (strcmp(q->symbol,string) == 0))
                        {
                            strcpy(q->symbol,p->symbol);
                            break;
                        }
                        else
                        {
                            q = q->next;
                        }
                    }
                }
            }

            ok = CheckForWin(p);

            if(ok == 1)
            {
                system("cls");
                ConsoleColours("dark gray","white");
                Header();
                PrintTable((60-(rows*3+rows))/2,8);
                GoTo((60-strlen(p->name)-3)/2,30);
                Colour("green","white");
                printf(" %s WON!!! ",p->name);
                GoTo(25,32);
                Colour("dark purple","gray");
                getch();
                puts("GAME OVER");
                break;
            }
            else if (ok == 0)
            {
                if(p->next !=NULL)
                {
                    p = p->next;
                }
                else
                {
                    p = firstP;
                }
                GoTo(16,rows*3+rows+17);
                Colour("red","gray");
                printf("Press any key to continue...");
                getch();
                system("cls");
            }
        }
        else if(full == 1)
        {
            Colour("dark purple","gray");
            GoTo(5,rows*3+rows+15);
            puts("There are no more positions available on the board.");
            GoTo(25,rows*3+rows+16);
            puts("GAME OVER");
            GoTo(17,rows*3+rows+17);
            puts("Neither player hasn't won!");
            GoTo(16,rows*3+rows+18);
            puts("Press any key to continue...");
            break;
        }
    }
}

void Launcher(void)
{
    char newGame[4];
    int ok = 1;
    system("title http://vintagecoding.blogspot.com TicTacToe");
    ConsoleDimensions(60,40);
    ConsoleColours("dark gray","white");
    CustomizePlayers();
    system("cls");
    ConsoleColours("dark gray","white");
    CustomizeTable();
    system("cls");
    ConsoleColours("dark gray","white");
    while(ok == 1)
    {
        Gameplay();
        getch();
        system("cls");
        ConsoleColours("dark gray","white");
        Header();
        DrawRectangle(8,10,43,5,"dark purple");
        GoTo(9,12);
        Colour("dark purple","gray");
        puts("Do you want to start a new game? [yes/no]");
        GoTo(9,13);
        scanf("%s",newGame);
        if(strcmp(newGame,"yes") == 0)
        {
            ok = 1;
            firstM = NULL;
            InitialiseTable();
            system("cls");
        }
        else
        {
            ok = 0;
        }
    }
}

int main(void)
{
    Launcher();
    getch();
    return 0;
}

Screenshots:





3 comments: