Tic-Tac-Toe

Tic-Tac-Toe

You can use system("cls") on Windows to clear the console. system("clear") should do the same on Linux & MacOS.

You may use this to clear the board if you don't want a log of the moves.

Make a Tic-Tac-Toe Game.

The game should run untill a player wins, or until it's a draw.

For each turn, the player should input 2 numbers that represents a field on the playing board. The move should be made, and the board should be checked for wins.

Hint

There are many ways to make games like this. I would recommend structuring your program like this:

- instructions for the game
infinite loop
{
	- print the board
	- get input from the player who's turn it is
	- verify input
	- check if the game is won, and break the loop if it is
	- check if the game is drawn, and break the loop if it is
	- switch to the other player and set up for the next loop cycle
}

Answer - without functions

This is a version that doesn't use functions, for those who haven't completed 1.7.7 yet. I would highly recommend using functions to improve code readability.

#include <iostream>

// Tic tac toe
int main()
{
	// Set up playing field
	int playing_field[3][3];

	for (int i = 0; i < 3; i++) 
	{
		for (int j = 0; j < 3; ++j) 
		{
			playing_field[i][j] = 0;
		}
	}

	// Print instructions
	std::cout << "Welcome to tic tac toe!\n";
	std::cout << "To play, enter the x and y coordinates of the field you want to set.\n";
	std::cout << "The x coordinate is the first number, the y coordinate is the second number.\n";
	std::cout << "The coordinates start at 0, so the top left field is 0 0, the bottom right field is 2 2.\n";
	std::cout << "The first player to get 3 in a row wins!\n\n\n";

	int player_turn = 1;
	// Game loop - runs until someone wins or the board is full
	// If we use continue before switching the players turn, the same player will play again.
	// If the player input is invalid, we can use continue to let them play again.
	while (true) 
	{
		std::cout << "\n\n-------\n";
		// Print board - loop through all fields and print them
		for (int i = 0; i < 3; i++)
		{
			for (int j = 0; j < 3; ++j)
			{
				if (playing_field[i][j] == 1)
					std::cout << " O";
				else if (playing_field[i][j] == 2)
					std::cout << " X";
				else
					std::cout << " -";
			}
			std::cout << "\n";
		}
		std::cout << "-------\n";

		// Get player input
		int x, y;
		std::cout << "Player " << player_turn << " turn: ";
		std::cin >> x >> y;

		// Check if input is valid (between 0 and 2)
		if (x < 0 || x > 2 || y < 0 || y > 2)
		{
			std::cout << "Invalid input\n";
			continue;
		}

		// Check if field is taken
		if (playing_field[y][x] != 0)
		{
			std::cout << "Field is taken\n";
			continue;
		}

		// Set field
		playing_field[y][x] = player_turn;

		// Check if player won
		bool player_won = false;
		// Diagonal check
		if ((playing_field[0][0] == player_turn && playing_field[1][1] == player_turn && playing_field[2][2] == player_turn)
			|| (playing_field[0][2] == player_turn && playing_field[1][1] == player_turn && playing_field[2][0] == player_turn))
			player_won = true;

		// We can use the same loop for horizontal and vertical check
		for (int i = 0; i < 3; i++)
		{
			// Horizontal check
			if (playing_field[i][0] == player_turn && playing_field[i][1] == player_turn && playing_field[i][2] == player_turn)
				player_won = true;

			// Vertical check
			if (playing_field[0][i] == player_turn && playing_field[1][i] == player_turn && playing_field[2][i] == player_turn)
				player_won = true;
		}

		// If player won, print winner and break out of game loop
		if (player_won)
		{
			std::cout << "Player " << player_turn << " won!\n";
			break;
		}

		player_turn = player_turn == 1 ? 2 : 1;

		// Check if board is full / if it's a draw
		bool board_full = true;
		// Search for empty fields - if we find one, the board is not full
		for (int i = 0; i < 3; i++)
		{
			for (int j = 0; j < 3; ++j)
			{
				if (playing_field[i][j] == 0)
					board_full = false;
			}
		}

		// If board is full, and there is no winner, it's a draw
		if (board_full)
		{
			std::cout << "Draw!\n";
			break;
		}
	}
}

For further gameplay you could wrap this game in a function that returns the id of the winner, or 0 if it's a draw. Then you can run a loop that keeps track of the score. This way you can play multiple games in one instance and kepe track of the score.

Answer - Using functions

#include <iostream>

void print_board(int board[3][3])
{
	std::cout << "\n\n-------\n";
	// loop through all fields and print them
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; ++j)
		{
			if (board[i][j] == 1)
				std::cout << " O";
			else if (board[i][j] == 2)
				std::cout << " X";
			else
				std::cout << " -";
		}
		std::cout << "\n";
	}
	std::cout << "-------\n";
}

// Returns false if input is invalid, and continue should be used
bool validate_input(int board[3][3], int x, int y)
{

	// Check if input is valid (between 0 and 2)
	if (x < 0 || x > 2 || y < 0 || y > 2)
	{
		std::cout << "Invalid input\n";
		return false;
	}

	// Check if field is taken
	if (board[y][x] != 0)
	{
		std::cout << "Field is taken\n";
		return false;
	}

	return true;
}

// Returns true if `player` won
bool player_win_check(int player, int board[3][3])
{
	// Diagonal check
	if ((board[0][0] == player && board[1][1] == player && board[2][2] == player) || (board[0][2] == player && board[1][1] == player && board[2][0] == player))
		return true;

	// We can use the same loop for horizontal and vertical check
	for (int i = 0; i < 3; i++)
	{
		// Horizontal check
		if (board[i][0] == player && board[i][1] == player && board[i][2] == player)
			return true;

		// Vertical check
		if (board[0][i] == player && board[1][i] == player && board[2][i] == player)
			return true;
	}

	// If we didn't return true yet, the player didn't win
	return false;
}

bool full_board_check(int board[3][3])
{
	// Search for empty fields - if we find one, the board is not full
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; ++j)
		{
			if (board[i][j] == 0)
				return false;
		}
	}

	// If we didn't return false yet, the board is full
	return true;
}

// Tic tac toe
int main()
{
	// Set up playing field
	int playing_field[3][3];

	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; ++j)
		{
			playing_field[i][j] = 0;
		}
	}

	// Print instructions
	std::cout << "Welcome to tic tac toe!\n";
	std::cout << "To play, enter the x and y coordinates of the field you want to set.\n";
	std::cout << "The x coordinate is the first number, the y coordinate is the second number.\n";
	std::cout << "The coordinates start at 0, so the top left field is 0 0, the bottom right field is 2 2.\n";
	std::cout << "The first player to get 3 in a row wins!\n\n\n";

	int player_turn = 1;
	// Game loop - runs until someone wins or the board is full
	// If we use continue before switching the players turn, the same player will play again.
	// If the player input is invalid, we can use continue to let them play again.
	while (true)
	{
		print_board(playing_field);

		// Get player input
		int x, y;
		std::cout << "Player " << player_turn << " turn: ";
		std::cin >> x >> y;
		// Continue if input is invalid
		if (!validate_input(playing_field, x, y))
			continue;

		// Set input field to player's number
		playing_field[y][x] = player_turn;

		// If player won, print winner and break out of game loop
		if (player_win_check(player_turn, playing_field))
		{
			std::cout << "Player " << player_turn << " won!\n";
			break;
		}

		// Check if board is full / if it's a draw
		// If board is full, and there is no winner, it's a draw
		if (full_board_check(playing_field))
		{
			std::cout << "Draw!\n";
			break;
		}

		// Switch player turn
		player_turn = player_turn == 1 ? 2 : 1;
	}
}

For further gameplay you could wrap this game in a function that returns the id of the winner, or 0 if it's a draw. Then you can run a loop that keeps track of the score. This way you can play multiple games in one instance and kepe track of the score.

Questions