5
\$\begingroup\$

First full program in C++. I'm having trouble understanding when I should use classes and when I should not. Ultimately, after this review, I would love to have a better idea of what circumstances I should use classes and how I can more efficiently write in c++.

I plan to rewrite the program using classes and re-post for further review. At the minimum, I assume I could create a player class to more efficiently track which symbol belongs to who and so forth. Written using Eclipse and MinGW GCC

main.cpp:

//TicTac Toe game for C++ dev practice
//attempting to utilize various things I have learned to produce a replayable tictac toe with drawn out game board on the console
//Lets do this
//LEEERRROOOYYYYYY JEENNNKIIINNNNSSSSS

#include <iostream>
#include "ticTacToeFunctions.h"

using namespace std;

int main()
{

    //assumes no initial play before requesting input from the user
    bool play;

    play = getUserWantToPlay(play);

    // initializes loop for game play..allows for users to play multiple times
    while(play)
    {
        char squareArray[9] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
        int playerTurn = 1;
        int playerWin = 0;

        //Round iterations
        while(playerWin == 0)
        {
            drawGameBoard(squareArray);

            cout << "Player " << playerTurn << "'s turn!" << endl;

            //Gets player move from user and alters squareArray for iteration through drawGameBoard
            getPlayerMove(playerTurn, squareArray);

            //Checks for player win
            playerWin = checkForWin(squareArray, playerTurn);

            if(playerWin == 0)
            {
                //Alternates player turn via conditional operator
                playerTurn = playerTurn == 1 ? 2 : 1;
            }
        }

        drawGameBoard(squareArray);
        cout << "Congratulations player " << playerWin << "!  You Win!" << endl;

        //retest if player wants to play a new game
        play = getUserWantToPlay(play);

    }


    cout << "Thanks for playing!" << endl;

    return(0);

}

ticTacToeFunctions.h:

* ticTacToeFunctions.h
 *
 *  Created on: Jun 9, 2016
 *
 */

#ifndef TICTACTOEFUNCTIONS_H_
#define TICTACTOEFUNCTIONS_H_

bool getUserWantToPlay(bool &play);

void drawGameBoard(char squareArray[9]);

void getPlayerMove(int playerTurn, char (&squareArray)[9]);

int checkForWin(char squareArray[9], int playerTurn);

#endif /* TICTACTOEFUNCTIONS_H_ */

functions.cpp:

//Main functions for tictactoe game

#include <iostream>
#include "ticTacToeFunctions.h"

bool getUserWantToPlay(bool &play)
{
    //test if user wants to play
    std::string response;

    std::cout << "Would you like to play a new game of TicTac Toe? " << std::endl;
    std::cin >> response;

    if(response == "Yes" || response == "yes" || response == "y" || response == "Y")
    {

        play = true;

    }
    else if(response == "No" || response == "no" || response == "n" || response == "N")
    {

        play = false;

    }
    else
    {

        std::cout << "Input was not valid...I guess you do not want to play" << std::endl;
        play = false;

    }

    return play;
}

void drawGameBoard(char squareArray[])
{
    //draws the game board with updated characters for each player

    std::cout << "Player 1 (X) - Player 2 (O)" << std::endl << std::endl << std::endl;

    std::cout << "    |     |" << std::endl;
    std::cout << " " << squareArray[0] << "  |  " << squareArray[1] << "  |  " << squareArray[2] << std::endl;

    std::cout << "____|_____|____" << std::endl;
    std::cout << "    |     |    " << std::endl;

    std::cout << " " << squareArray[3] << "  |  " << squareArray[4] << "  |  " << squareArray[5] << std::endl;

    std::cout << "____|_____|____" << std::endl;
    std::cout << "    |     |    " << std::endl;

    std::cout << " " << squareArray[6] << "  |  " << squareArray[7] << "  |  " << squareArray[8] << std::endl;
}

void getPlayerMove(int playerTurn, char (&squareArray)[9])
{
    char playerMove;
    char playerSymbol;
    bool playerMoveFound = false;

    if(playerTurn == 1)
    {
        playerSymbol = 'X';
    }
    else
    {
        playerSymbol = 'O';
    }

    while(playerMoveFound == false)
    {
        std::cout << "Player " << playerTurn << " please make a move" << std::endl;
        std::cin >> playerMove;

        for(int x = 0; x < 9; x++)
        {

            //If finds the array number makes the change to the iteration
            if(playerMove == squareArray[x])
            {

                squareArray[x] = playerSymbol;

                playerMoveFound = true;
            }

        }
        if(playerMoveFound == false)
        {
            std::cout << "Invalid player move..." << std::endl;
        }
    }
}

int checkForWin(char squareArray[9], int playerTurn)
{
    int playerWin = 0;

    if(squareArray[0] == squareArray[1] && squareArray[1] == squareArray[2])
    {
        playerWin = playerTurn;
    }
    else if(squareArray[0] == squareArray[3] && squareArray[3] == squareArray[6])
    {
        playerWin = playerTurn;
    }
    else if(squareArray[0] == squareArray[4] && squareArray[4] == squareArray[8])
    {
        playerWin = playerTurn;
    }
    else if(squareArray[1] == squareArray[4] && squareArray[4] == squareArray[7])
    {
        playerWin = playerTurn;
    }
    else if(squareArray[2] == squareArray[4] && squareArray[4] == squareArray[6])
    {
        playerWin = playerTurn;
    }
    else if(squareArray[2] == squareArray[5] && squareArray[5] == squareArray[8])
    {
        playerWin = playerTurn;
    }
    else if(squareArray[3] == squareArray[4] && squareArray[4] == squareArray[5])
    {
        playerWin = playerTurn;
    }
    else if(squareArray[6] == squareArray[7] && squareArray[7] == squareArray[8])
    {
        playerWin = playerTurn;
    }

    return(playerWin);

}
\$\endgroup\$
  • 1
    \$\begingroup\$ If you're writing C++ without classes, why wouldn't you just write in C? \$\endgroup\$ – syb0rg Jun 9 '16 at 19:28
  • \$\begingroup\$ @syb0rg I don't want to write without classes that's the thing. I want to learn to use classes. That's why i'm asking for a little focus on where I can build classes in as well as other advice. \$\endgroup\$ – StormsEdge Jun 9 '16 at 19:51
  • \$\begingroup\$ Ahh, got it. I'm going to remove the "sans classes" from the post then, since it makes it sound as if you want your code to be that way. \$\endgroup\$ – syb0rg Jun 9 '16 at 19:53
  • \$\begingroup\$ @syb0rg Got it! Thanks! Sorry about that. \$\endgroup\$ – StormsEdge Jun 9 '16 at 19:57
3
\$\begingroup\$

Learning how to use classes (or types) in C++ is definitely a great idea. Just keep on mind that you don't always need to use classes everywhere. It is just a tool and there are many more tools in C++. It is definitely possible and definitely ok to implement some minimalistic tic-tac-toe game without any class definition (well you just did it).

If you want to practice using types (classes) you could try to think about what (which entity) you need to represent in your code (maybe player, maybe board, maybe something totally different) and create class for it. You might also benefit from reading some nice book to understand basic concepts.

This question might be helpful: https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list

You can find some ideas regarding current code below.

Regarding game rules

tie

Other possible end-state apart from victory is tie. You should probably check for that too and end the game accordingly.

occupied squares

You probably don't want to allow moves to already occupied squares. What happens when players inputs 'x' as his/her new move?

Regarding design

interface

bool getUserWantToPlay(bool &play)

Why the reference? Wouldn't it be sufficient to just return the value?

bool getUserWantToPlay()

Regarding use of C++

infamous using namespace std

This is probably not a good idea as you are cluttering your scope with names you probably don't need. Try to google "c++ using namespace std" to get the idea.

player representation

Player is represented by int (e. g. playerTurn, playerWin) that is a type with at least 2 ^ 32 possible values out of which only 2 are valid. That is a huge space for bugs. Wouldn't be using something like enum or bool better?

passing array to function

Check how you are passing the squareArray array around.

void drawGameBoard(char squareArray[9]);
void getPlayerMove(int playerTurn, char (&squareArray)[9]);
int checkForWin(char squareArray[9], int playerTurn);

This answer might help: https://stackoverflow.com/a/14309142

initialization

Uninitialized variables are bugs waiting to happen. If you forgot to initialize those before reading it is undefined behaviour, about the ugliest thing in C++.

bool play;
play = getUserWantToPlay(play);

Instead of separate definition and initialization (possible several code lines apart) it is better to do it at once (safer, sometimes more efficient):

bool play = getUserWantToPlay(play);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.