• 0

[C++] Tic Tac Toe with Variable Size Board


Question

We've just started learning arrays and the what-not in my C++ class. Our assignment is to create a tic tac toe program that has a user-set variable size board (3x3, 4x4, 9x9, etc). He gave us an example 3x3 tic tac toe program listed below a week back or so and told us to play around with it to make it multi-sized. I've started playing with it slightly, but for the most part, am I just going to change the constant values of 3 to variables? I thought you could not set an array to size variable?

#include <stdio.h>
#include <stdlib.h>

char matrix[3][3];  /* the tic tac toe matrix */

char check(void);
void init_matrix(void);
void get_player_move(void);
void get_computer_move(void);
void disp_matrix(void);

int main(void)
{
  char done;

  printf("This is the game of Tic Tac Toe.\n");
  printf("You will be playing against the computer.\n");

  done =  ' ';
  init_matrix();

  do {
	disp_matrix();
	get_player_move();
	done = check(); /* see if winner */
	if(done!= ' ') break; /* winner!*/
	get_computer_move();
	done = check(); /* see if winner */
  } while(done== ' ');

  if(done=='X') printf("You won!\n");
  else printf("I won!!!!\n");
  disp_matrix(); /* show final positions */

  return 0;
}

/* Initialize the matrix. */
void init_matrix(void)
{
  int i, j;

  for(i=0; i<3; i++)
	for(j=0; j<3; j++) matrix[i][j] =  ' ';
}

/* Get a player's move. */
void get_player_move(void)
{
  int x, y;

  printf("Enter X,Y coordinates for your move: ");
  scanf("%d%*c%d", &x, &y);

  x--; y--;

  if(matrix[x][y]!= ' '){
	printf("Invalid move, try again.\n");
	get_player_move();
  }
  else matrix[x][y] = 'X';
}

/* Get a move from the computer. */
void get_computer_move(void)
{
  int i, j;
  for(i=0; i<3; i++){
	for(j=0; j<3; j++)
	  if(matrix[i][j]==' ') break;
	if(matrix[i][j]==' ') break;
  }

  if(i*j==9)  {
	printf("draw\n");
	exit(0);
  }
  else
	matrix[i][j] = 'O';
}

/* Display the matrix on the screen. */
void disp_matrix(void)
{
  int t;

  for(t=0; t<3; t++) {
	printf(" %c | %c | %c ",matrix[t][0],
			matrix[t][1], matrix [t][2]);
	if(t!=2) printf("\n---|---|---\n");
  }
  printf("\n");
}

/* See if there is a winner. */
char check(void)
{
  int i;

  for(i=0; i<3; i++)  /* check rows */
	if(matrix[i][0]==matrix[i][1] &&
	   matrix[i][0]==matrix[i][2]) return matrix[i][0];

  for(i=0; i<3; i++)  /* check columns */
	if(matrix[0][i]==matrix[1][i] &&
	   matrix[0][i]==matrix[2][i]) return matrix[0][i];

  /* test diagonals */
  if(matrix[0][0]==matrix[1][1] &&
	 matrix[1][1]==matrix[2][2])
	   return matrix[0][0];

  if(matrix[0][2]==matrix[1][1] &&
	 matrix[1][1]==matrix[2][0])
	   return matrix[0][2];

  return ' ';
}

9 answers to this question

Recommended Posts

  • 0

Yes, you could start with a maximum size matrix and the jsut replace the 3's by a variable N (which would be the size)

also you'll need a double loop in

for(i=0; i<3; i++)  /* check rows */
	if(matrix[i][0]==matrix[i][1] &&
	   matrix[i][0]==matrix[i][2]) return matrix[i][0];

  for(i=0; i<3; i++)  /* check columns */
	if(matrix[0][i]==matrix[1][i] &&
	   matrix[0][i]==matrix[2][i]) return matrix[0][i];

  /* test diagonals */
  if(matrix[0][0]==matrix[1][1] &&
	 matrix[1][1]==matrix[2][2])
	   return matrix[0][0];

  if(matrix[0][2]==matrix[1][1] &&
	 matrix[1][1]==matrix[2][0])
	   return matrix[0][2];

which will allow you to check the entire row or column

  • 0

You could also use the STL (standard template library) vector class for a dynamic array size based on user input. There's plenty of examples online (cplusplus.com for instance). Consider it if you absolutely have to have a dynamic size board that could be any size - otherwise, the past comments about a max size would work too and probably be more familiar to you.

  • 0
  rpgfan said:
Or if you feel experienced enough, you could always create it dynamically yourself... Just remember that the amount of memory available is finite. In other words, don't forget to delete[] what you allocate! ^_^

Good tip! :) It is very important to take care of the garbage collection functionality (e.g. cleanup any unneeded resources). It is a good habit to get into.

Also, for this task couldn't you simply create a variable called "rows" and a variable called "columns" and have the user enter the number for each? Then, if I am correct, you would simply pass the array that you create the values that were entered.

Edited by winlonghorn
  • 0

Thanks for all the replies guys...considering my experience and the scope of the course, I believe I'll stick with setting a constant for the matrix. Now I'm trying to actually get the matrix to display correctly.

char matrix[26][26];  // the tic tac toe matrix

char check(void);
void init_matrix(int BOARD_SIZE);
void get_player_move(void);
void get_computer_move(void);
void disp_matrix(int BOARD_SIZE);
void get_player2_move(void);
void get_computer2_move(void);

/* Initialize the matrix. */
void init_matrix(int BOARD_SIZE)
{
  int i, j;

  for(i=0; i<BOARD_SIZE; i++)
	for(j=0; j<BOARD_SIZE; j++) matrix[i][j] =  ' ';
}

//Display the matrix
void disp_matrix(int BOARD_SIZE)
{
int t; int u;
//Cosmetic bar above |---|---|---|
	printf("|");
	for (t=0; t<BOARD_SIZE; t++)
	do{
	if (t != BOARD_SIZE) printf("---|");}
	while(t>BOARD_SIZE);

//Bar t
	printf("\n|");
	do{
	for (u=0; u<BOARD_SIZE; u++)
	printf(" %c |", matrix [0][u]);
	}while(u>BOARD_SIZE);


//Cosmetic bar below |---|---|---|
	printf("\n|");
	for (t=0; t<BOARD_SIZE; t++)
	do{
	if (t != BOARD_SIZE) printf("---|");}
	while(t>BOARD_SIZE);
	printf("\n");

}

I'm slowly getting it. This will display only one vertical bar, but with the correct amount of spaces horizontally. I believe I just need to add another for loop....for (t=0, t<BOARD_SIZE; t++)....is this correct?

Edited by entropypl
  • 0

Take the habit of typing your loops in full, it'll save you a lot of subtle bugs. Later when you feel very confident and are working alone on a project, you can do one-line loops with no brackets.

When you write a for loop, for instance, start by writing :

for ([initialization]; [break condition]; [increment]) {

}

Next, write what's inside the loop :

for ([initialization]; [break condition]; [increment]) {
	[statement 1];
	[statement 2];
	....
}

The same goes for if statements, functions, classes, while loops, anything that has a body. Except maybe individual cases in a switch statement.

I say this because your code is pretty hard to understand as it is, and it could break the minute you do any kind of modification to it. Take for instance this :

  for(i=0; i&lt;BOARD_SIZE; i++)
	for(j=0; j&lt;BOARD_SIZE; j++) matrix[i][j] =  ' ';

Let's say you have a second matrix, overlayed upon the first, which you'll want to initialize in the same spot. You might want to write :

  for(i=0; i&lt;BOARD_SIZE; i++)
	for(j=0; j&lt;BOARD_SIZE; j++) matrix1[i][j] =  ' '; matrix2[i][j] = ' ';

If this compiles, it will not do what you want. Can you tell why? Actually, the compiler will save you there, but it can't do the guesswork all the time. Just write the loops properly :

for(i=0; i&lt;BOARD_SIZE; i++) {
	for(j=0; j&lt;BOARD_SIZE; j++) { 
		matrix1[i][j] =  ' ';
		matrix2[i][j] = ' ';
	}
}

  • 0
  Dr_Asik said:
Take the habit of typing your loops in full, it'll save you a lot of subtle bugs. Later when you feel very confident and are working alone on a project, you can do one-line loops with no brackets.

I understand. Sometimes I guess I get excited and get ahead of myself :rolleyes:. I also need to start practicing proper indentation much more. I'll go through my project and clean it up after this post.

  Quote
We will play on a variable-size board. Your program should define the following integer constants:

BOARD_SIZE

determines both the width and height of the game board (which is always square)

WIN_LENGTH

determines the number of Xs or Os in a row (either horizontally, vertically, or diagonally) that a player needs in order to win

so that the game can be played on different size boards simply by changing these values.

I've completed my disp_matrix function and it works flawlessly, now onto the hardest part, checking for a winner with a variable sized board AND variable sized WIN_LENGTH. Will a double loop work for the check() function? I was thinking I would have to totally butcher it and start anew.

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • It is fundamentally impossible to secure delete files, especially on newer HDDs and all SSDs. You never know how the controller firmware is going to layout data or copy data around to optimize access or invoke wear leveling. The only way to securely “delete” something is to put it on an encrypted file system and forget the encryption key, assuming any apps you open the files in don’t copy the files to a local cache on the boot volumes.
    • TBF, it has had PST support for quite a while now. But I still want them to add the ability to drag & drop between accounts / PSTs.
    • LibreOffice closes in on Office, leaves Windows 7/8 behind in 25.8 Beta 1 by David Uzondu The Document Foundation has released LibreOffice 25.8 Beta 1 for public testing on Linux, macOS, and Windows. This is the second pre-release for the 25.8 cycle and the foundation says that the final, stable version of LibreOffice 25.8 is expected to land at the end of August 2025. Starting off with Writer, LibreOffice's Word, the developers have finally addressed some long-standing annoyances, including a new command to easily insert a paragraph break right before a table. This beta also introduces a useful privacy feature in its Auto-Redact tool, letting you strip all images from a document with a single option. To use it, go to Tools and select the Auto-Redact option: The application has improved its ability to handle different languages for punctuation, preventing mix-ups in multilingual documents. Other notable improvements have also been made. A new hyphenation rule lets you choose to prevent a word from splitting at the end of a page, moving the whole line to the next page instead. Microsoft Word has had this feature for years now. The Navigator now displays a handy tooltip with word and character counts for headings and their sub-outlines. Scrolling behavior when selecting text has been improved, making it less erratic. A new command with a keyboard shortcut was added for converting fields into plain text. Calc gets a lot of new functions that bring it closer to its competitors like Excel, including TEXTSPLIT, VSTACK, and WRAPROWS. Impress now properly supports embedded fonts in PPTX files, which should reduce headaches when sharing presentations with PowerPoint users. Alongside these additions, the project is also cleaning house; support for Windows 7, 8, and 8.1 has been completely dropped. There are also smaller UI tweaks across the suite, like allowing a single click to enter rotation mode for objects in Writer and Calc. macOS users get better integration, with proper support for native full screen mode and new window management features from the Sequoia update. In terms of performance, the team has optimized everything from loading huge DOC files and XLSX spreadsheets with tons of conditional formatting to simply switching between sheets in Calc. These improvements should be noticeable, especially when working with complex documents. A new application-wide "Viewer mode" has also been implemented, which opens all files in a read-only state for quick, safe viewing. On a related note, The Document Foundation has joined efforts by the likes of KDE to encourage Windows 10 users to switch to Linux. Also, you might have heard that Denmark, in a bid to lessen its reliance on Microsoft, has decided to make a full switch to LibreOffice, with plans to begin phasing out Office 365 in certain ministries as early as next month. If you're interested in this release, you can read the full release notes and download the binaries for your platform: Windows, macOS (Intel | Apple Silicon), or Linux (DEB | RPM). You can also get the latest stable version from our software stories page.
  • Recent Achievements

    • Explorer
      Case_f went up a rank
      Explorer
    • Conversation Starter
      Jamie Smith earned a badge
      Conversation Starter
    • First Post
      NeoToad777 earned a badge
      First Post
    • Week One Done
      JoeV earned a badge
      Week One Done
    • One Month Later
      VAT Services in UAE earned a badge
      One Month Later
  • Popular Contributors

    1. 1
      +primortal
      545
    2. 2
      ATLien_0
      227
    3. 3
      +FloatingFatMan
      160
    4. 4
      Michael Scrip
      113
    5. 5
      +Edouard
      104
  • Tell a friend

    Love Neowin? Tell a friend!