2
\$\begingroup\$

The goal of this program is to create text based tic-tac-toe

What I know:

  1. Base level java (till arrays & functions)
  2. The same goes for c++

What I did:

I) Variable count: This used to count the number of total turns, so it can declare tie after 9 turns

II) Create 2 functions:

  1. OP(this is used to show the grid with all inputs)

  2. check(this is used to check if either player has won or lost)

What I want to improve

  1. Reduce the lines of the code
  2. Find a general or better formula for diagonals
  3. Learn why atom(the ide I am using) doesn't let me use void main()
  4. Any other improvements that I can make
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int pos[9];//positions on the grid
int result;//to check if either player has won
int count;//to declare tie after 9 turns
int OP(int a)//to output/print the grid(with the last input)
{

  for(int i=1;i<10;i++)
  {
    if(i%3==1)
    cout<<"\t";
    if(pos[i-1]==1)
    {
      cout<<"\t"<<"X";
    }
    else if(pos[i-1]==2)
    {
      cout<<"\t"<<"O";
    }
    else
    {
      cout<<"\t"<<" ";
    }
    if(i%3==0)
    {
      cout<<endl;
      cout<<"\t"<<"--------------------------------------------------"<<endl;//
      continue;
    }
    cout<<"\t"<<"|";
  }
  return 0;
}
int check(int x)//to check if X or O has won
{
  for(int i=0;i<7;i++)
  {
    if(i==4||i==5)
    continue;
    if(pos[i]==x)
    {
       result=0;
      //checking rows
      if(i==0||i==3||i==6)
      {
          if(pos[i]==pos[i+1]&&pos[i+1]==pos[i+2])
          {
            result=x;
            break;
          }
      }
        //checking colummns
      if(i==0||i==1||i==2)
      {
        if(pos[i]==pos[i+3]&&pos[i+3]==pos[i+6])
        {
          result=x;
          break;
        }
      }
      //checking diagonals(find a better formula for diagonals)
      if(i==0)
      {
        if(pos[i]==pos[i+4]&&pos[i+4]==pos[i+8])
        {
          result=x;
          break;
        }
      }
      if(i==2)
      {
        if(pos[i]==pos[2*i]&&pos[2*i]==pos[3*i])
        {
          result=x;
          break;
        }
      }
    }
  }
  count++;
  return result;
}
int main()
{
  int inp1,inp2;
  char ec;
  for(int i=1;i!=0;i++)//to loop till either wins or it ties
  {
    cout<<"Enter E to exit, C to clear screen, any other character to contine"<<endl;
    cin>>ec;
    if(ec=='E'||ec=='e')
    {
      break;
    }
    else if(ec=='C'||ec=='c')
    {
      system("cls");
    }
    cout<<"Player 1(X) Enter the position where x should be placed(1 being top left and 9 being bottom right)"<<endl;
    cin>>inp1;
    if(inp1>9||inp1<1)
    {
      cout<<"Position Exceeds Limit"<<endl;
      continue;
    }
    else if(pos[inp1-1]==1||pos[inp1-1]==2)
    {
      cout<<"This Position is already taken for this game"<<endl;
      continue;
    }
    else
    {
      pos[inp1-1]=1;
    }
    OP(0);
    result=check(1);
    if(count==9)
    {
      cout<<"Its a tie";
      break;
    }
    if(result==1)
    {
      cout<<"Player 1 wins";
      break;
    }
    for(int j=1;j!=0;j++)//so that it loops, until a correct input is used for player 2
    {
      cout<<"Player 2(O) Enter the position where O should be placed(1 being top left and 9 being bottom right)"<<endl;
      cin>>inp2;
      if(inp2>9||inp2<1)
      {
        cout<<"Position Exceeds Limit"<<endl;
        continue;
      }
      else if(pos[inp2-1]==1||pos[inp2-1]==2)
      {
        cout<<"This Position is already taken for this game"<<endl;
        continue;
      }
      else
      {
        pos[inp2-1]=2;
        j=-1;
      }
    }
    OP(0);
    result=check(2);
    if(result==2)
    {
      cout<<"Player 2 Wins";
      break;
    }
  }

  return 0;
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ One part of your question is off-topic, your IDE isn't letting you use void for main() because main() in C++ has to return an integer value to the operating system that indicates the success or failure of the program. \$\endgroup\$
    – pacmaninbw
    Feb 6, 2022 at 18:28

1 Answer 1

3
\$\begingroup\$

Header Files

You don't need the header files stdio.h since you are using C++ std::cin and std::cout for input and output. stdio.h is the header file for standard C programming and generally isn't used in C++ programs. If you are programming in C++ rather than C use #include <cstdlib> rather than #include <stdlib.h>. You should be including <iostream> which is the standard include for C++ input and output.

Avoid Global Variables

It is very difficult to read, write, debug and maintain programs that use global variables. Global variables can be modified by any function within the program and therefore require each function to be examined before making changes in the code. In C and C++ global variables impact the namespace and they can cause linking errors if they are defined in multiple files. The answers in this stackoverflow question provide a fuller explanation.

Avoid using namespace std;

If you are coding professionally you probably should get out of the habit of using the using namespace std; statement. The code will more clearly define where cout and other identifiers are coming from (std::cin, std::cout). As you start using namespaces in your code it is better to identify where each function comes from because there may be function name collisions from different namespaces. The identifiercout you may override within your own classes, and you may override the operator << in your own classes as well. This stack overflow question discusses this in more detail.

Magic Numbers

There are Magic Numbers in all the functions (9, 10, 7), it might be better to create symbolic constants for them to make the code more readble and easier to maintain. These numbers may be used in many places and being able to change them by editing only one line makes maintainence easier. In C++ you can create numeric constants using constexpr.


constexpr int MAX_PLAYS = 9;

Numeric constants in code are sometimes referred to as Magic Numbers, because there is no obvious meaning for them. There is a discussion of this on stackoverflow.

DRY Code

There is a programming principle called the Don't Repeat Yourself Principle sometimes referred to as DRY code. If you find yourself repeating the same code mutiple times it is better to encapsulate it in a function. If it is possible to loop through the code that can reduce repetition as well.

Complexity

The function main() is too complex (does too much). As programs grow in size the use of main() should be limited to calling functions that parse the command line, calling functions that set up for processing, calling functions that execute the desired function of the program, and calling functions to clean up after the main portion of the program.

There is also a programming principle called the Single Responsibility Principle that applies here. The Single Responsibility Principle states:

that every module, class, or function should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by that module, class or function.

You already have 2 functions, OP and check, getting and verifying the user input should be another function, which would also reduce any repeating of code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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