Introdução
Neste projeto, você aprenderá como criar um jogo simples de Jogo da Velha (Tic-Tac-Toe) em C. O jogo será jogado entre dois jogadores que se revezam para marcar os espaços em uma grade 3x3. O primeiro jogador a ter três de suas marcas em uma linha, coluna ou diagonal é o vencedor. Se todos os espaços forem preenchidos e nenhum jogador tiver três marcas em uma linha, o jogo é um empate.
👀 Pré-visualização

🎯 Tarefas
Neste projeto, você aprenderá:
- Como criar um tabuleiro de jogo e inicializá-lo com espaços vazios.
- Como implementar funções para limpar a tela, exibir o tabuleiro de jogo e verificar se o jogo acabou.
- Como determinar o vencedor do jogo.
- Como implementar o loop principal do jogo para permitir que os jogadores se revezem e interajam com o jogo.
🏆 Conquistas
Após concluir este projeto, você será capaz de:
- Criar e manipular arrays em C.
- Usar loops e condicionais para implementar a lógica do jogo.
- Interagir com o usuário através da interface de linha de comando.
- Organizar o código em funções para melhor modularidade e legibilidade.
Criar os Arquivos do Projeto
Primeiro, crie um novo arquivo chamado tictactoe.c e abra-o no seu editor de código preferido.
cd ~/project
touch tictactoe.c
Definir Constantes
Agora, precisamos escrever o código C. O primeiro passo é incluir os arquivos de cabeçalho:
#include <stdio.h>
#include <stdbool.h>
Declarar o tamanho do tabuleiro:
char board[3][3];
Inicializar o Tabuleiro do Jogo
Inicialize o tabuleiro do jogo com espaços vazios.
void initializeBoard() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i][j] = ' ';
}
}
}
O primeiro for é um loop externo que usa a variável i para iterar de 0 a 2, representando o número de linhas no tabuleiro do jogo. O segundo for é um loop interno que usa a variável j para iterar de 0 a 2, representando o número de colunas no tabuleiro do jogo, por sua vez.
board[i][j] = ' ' No loop interno, define o conteúdo das casas na linha i e coluna j do tabuleiro do jogo para o caractere espaço (' '). Isso significa que todo o tabuleiro do jogo é inicializado para um estado vazio, sem jogadores jogando no tabuleiro.
Limpar a Tela Após Cada Rodada
Implemente uma função para limpar a tela após cada jogada.
void clearScreen() {
printf("\033[H\033[J");
}
A função clearScreen é usada principalmente para limpar o conteúdo da tela do terminal ou console, a fim de limpar o estado anterior do jogo e a saída no final de cada jogada. Isso é feito imprimindo uma sequência de escape especial para um fluxo de saída padrão (geralmente uma janela de terminal) que limpa o conteúdo de texto na tela.
printf("\033[H\033[J") usa sequências de escape ANSI:
\033é a representação octal do caractere de escapeASCII, que representa o início da sequência.[Hindica mover o cursor para o canto superior esquerdo da tela, equivalente a posicionar o cursor na primeira linha e na primeira coluna da tela.[Jsignifica limpar a tela. Ele limpará todo o conteúdo de texto após a posição do cursor, incluindo o estado anterior do jogo e a saída.
Isso significa que cada vez que a função clearScreen é chamada, ela limpará o conteúdo da tela atual do terminal ou console para exibir o novo estado do jogo antes da próxima sessão de jogo, resultando em uma interface mais limpa.
Exibir o Tabuleiro do Jogo
Crie a função printBoard para exibir visualmente o estado do tabuleiro do jogo atual na tela, permitindo que o jogador entenda a posição das peças no tabuleiro. Esta é uma parte do jogo usada em jogos de jogo da velha para mostrar o estado do jogo.
void printBoard() {
printf("\n");
printf(" 1 2 3\n");
printf("1 %c | %c | %c\n", board[0][0], board[0][1], board[0][2]);
printf(" ---------\n");
printf("2 %c | %c | %c\n", board[1][0], board[1][1], board[1][2]);
printf(" ---------\n");
printf("3 %c | %c | %c\n", board[2][0], board[2][1], board[2][2]);
}
Verificar se o Jogo Terminou
Implemente uma função chamada isGameOver para determinar se o jogo da velha terminou e retornar um valor booleano (true ou false).
bool isGameOver() {
// Check rows
for (int i = 0; i < 3; i++) {
if (board[i][0] != ' ' && board[i][0] == board[i][1] && board[i][0] == board[i][2]) {
return true;
}
}
// Check columns
for (int j = 0; j < 3; j++) {
if (board[0][j] != ' ' && board[0][j] == board[1][j] && board[0][j] == board[2][j]) {
return true;
}
}
// Check diagonals
if (board[0][0] != ' ' && board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
return true;
}
if (board[0][2] != ' ' && board[0][2] == board[1][1] && board[0][2] == board[2][0]) {
return true;
}
// Check for a draw
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == ' ') {
return false;
}
}
}
return true;
}
Verificar se uma linha tem um vencedor: Se todas as três células em uma linha forem ocupadas pelo mesmo jogador, há um vencedor e a função retorna true.
Verificar se uma coluna tem um vencedor: Se todas as três células em uma coluna forem ocupadas pelo mesmo jogador, há um vencedor e a função retorna true.
Verificar se há um vencedor na diagonal: Se todos os três quadrados em qualquer diagonal forem ocupados pelo mesmo jogador, há um vencedor e a função retorna true.
Verificar se houve empate: Finalmente, a função verifica se todas as células foram ocupadas, mas não há vencedor. Se este for o caso, o jogo é um empate e a função retorna true.
Determinar o Vencedor
Uma função chamada getWinner é definida com o propósito de determinar se há um vencedor em um jogo da velha e retornar a bandeira do vencedor (X ou O), ou um espaço (' ') se não houver vencedor.
char getWinner() {
// Check rows
for (int i = 0; i < 3; i++) {
if (board[i][0] != ' ' && board[i][0] == board[i][1] && board[i][0] == board[i][2]) {
return board[i][0];
}
}
// Check columns
for (int j = 0; j < 3; j++) {
if (board[0][j] != ' ' && board[0][j] == board[1][j] && board[0][j] == board[2][j]) {
return board[0][j];
}
}
// Check diagonals
if (board[0][0] != ' ' && board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
return board[0][0];
}
if (board[0][2] != ' ' && board[0][2] == board[1][1] && board[0][2] == board[2][0]) {
return board[0][2];
}
return ' '; // No winner
}
Implementar o Loop Principal do Jogo
Escreva o loop principal do jogo para permitir que os jogadores se revezem e interajam com o jogo.
int main() {
initializeBoard();
int currentPlayer = 1;
while (1) {
clearScreen();
printf("Current board state:\n");
printBoard();
int row, col;
printf("Player %d, please enter a row and column (e.g., 1 2):", currentPlayer);
while (scanf("%d %d", &row, &col) != 2) {
printf("Invalid input, please try again: ");
while (getchar() != '\n');
}
if (row < 1 || row > 3 || col < 1 || col > 3 || board[row - 1][col - 1] != ' ') {
printf("Invalid move, please try again.\n");
} else {
if (currentPlayer == 1) {
board[row - 1][col - 1] = 'X';
currentPlayer = 2;
} else {
board[row - 1][col - 1] = 'O';
currentPlayer = 1;
}
}
if (isGameOver()) {
clearScreen();
printf("Game over!\n");
printBoard();
char winner = getWinner();
if (winner != ' ') {
printf("Player %c wins!\n", winner);
} else {
printf("It's a draw!\n");
}
break;
}
}
return 0;
}
Chame a função initializeBoard para inicializar o tabuleiro do jogo, definindo todos os quadrados como espaços.
Crie uma variável inteira currentPlayer para controlar de quem é a vez. A configuração inicial é 1, indicando o jogador 1.
No loop principal while (1):
- Chame a função
clearScreenpara limpar a tela para que a exibição seja atualizada após cada turno. - Chame a função
printBoardpara imprimir o tabuleiro atual do jogo.
Entrada do jogador: Solicita ao jogador atual que insira as coordenadas da linha e da coluna por meio da função scanf, por exemplo, Player 1, please enter a row and column (e.g., 1 2):. Se a entrada for inválida (não dois inteiros), a mensagem Invalid input, please try again: é exibida e o buffer de entrada é limpo até que uma entrada válida seja obtida.
Validação da entrada: Em seguida, verifique se as coordenadas da linha e da coluna inseridas são válidas (em uma escala de 1 a 3) e se a posição selecionada é um espaço. Se a entrada for inválida ou o local selecionado já estiver ocupado, a mensagem Invalid move, please try again. é exibida e o jogador é solicitado a reinserir.
Jogada: Se a entrada for válida, o código coloca um X ou um O na posição correspondente no tabuleiro do jogo com base no jogador atual (1 ou 2).
Detecção do fim do jogo: O código então chama a função isGameOver() para verificar se o jogo acabou. Se o jogo terminar, a tela limpa e uma mensagem de que o jogo acabou é exibida, incluindo um vencedor (se houver) ou um empate.
Resultado do jogo: Se houver um vencedor, o código dirá Player X wins! ou Player O wins!, dependendo de qual jogador é o vencedor. Se não houver vencedor, o código dirá It's a draw! indicando um empate.
Compilar e Executar o Projeto
Execute o comando gcc para compilar:
cd ~/project
gcc -o tictactoe tictactoe.c
./tictactoe

Resumo
Parabéns! Você criou com sucesso um jogo da velha simples em C. Os jogadores podem se revezar e marcar suas posições na grade 3x3. O jogo verifica se há um vencedor ou um empate após cada turno e exibe o resultado de acordo. Este projeto simples demonstra os conceitos básicos da programação em C e pode servir como um ponto de partida para o desenvolvimento de jogos mais complexos.



