Projetos de Programação de Jogos em C

"Quero deixar isso mais divertido" é o melhor motor para a evolução das suas habilidades de programação.
Construa primeiro a versão básica, depois dê o seu toque pessoal com os desafios de extensão.

Como trabalhar nestes projetos: Cada jogo começa com uma "implementação básica" e depois oferece "extensões graduais". Deixe a versão básica funcionando primeiro, depois encare as extensões da forma que preferir — não existe uma resposta única.
🎯

GAME 1: Adivinhação de Número

Iniciante Random Laços Condicionais
Adivinhe o número secreto escolhido pelo computador usando dicas de "muito alto / muito baixo".
🎯 Adivinhe um número entre 1 e 100! Chute> 50 Muito baixo Chute> 75 Muito alto Chute> 63 🎉 Acertou! Em 3 tentativas!
1
Sorteie a resposta aleatoriamente: chame srand(time(NULL)) uma vez, depois rand() % 100 + 1 para obter um número de 1 a 100.
2
Leia a entrada em um laço: use um laço while que continua até o chute estar correto. Leia cada chute com scanf.
3
Compare e dê o feedback: se chute > resposta imprima "Muito alto"; se chute < resposta imprima "Muito baixo"; caso contrário, imprima "Acertou".
4
Conte as tentativas: mantenha um contador int e imprima-o quando o jogador vencer.
Desafios de Extensão
  • Classifique o jogador com base em quantas tentativas levou (≤5 = "Gênio!", ≤10 = "Nada mal", etc.).
  • Adicione seleção de dificuldade (Fácil: 1–50, Normal: 1–100, Difícil: 1–1000).
  • Implemente um "jogar de novo?" com um laço do-while.
  • Calcule e mostre o número máximo de tentativas que uma busca binária precisaria.
  • Adicione um limite de tentativas e encerre o jogo se o jogador esgotar as tentativas.
Esqueleto:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    srand((unsigned)time(NULL));
    int answer = rand() % 100 + 1;
    int guess, count = 0;

    printf("Guess a number between 1 and 100!\n");
    do {
        printf("Guess> ");
        scanf("%d", &guess);
        count++;
        if (guess > answer) printf("Too high\n");
        else if (guess < answer) printf("Too low\n");
    } while (guess != answer);

    printf("Correct! Got it in %d tries!\n", count);
    return 0;
}

GAME 2: Pedra Papel Tesoura

Iniciante switch Random Vetores
Jogue pedra-papel-tesoura contra o computador. Registre os resultados e mostre o placar de vitórias/derrotas.
✊✌✋ Pedra-Papel-Tesoura (0:Pedra 1:Tesoura 2:Papel -1:Sair) Você> 0 Você: Pedra vs CPU: Tesoura 🎉 Você venceu! Você> 2 Você: Papel vs CPU: Papel 😐 Empate! Você> -1 --- Placar --- 3V 1D 1E (taxa de vitória 60.0%)
1
Armazene os nomes das jogadas em um vetor: char *hands[] = {"Pedra","Tesoura","Papel"};
2
Lógica de pontuação: (player - cpu + 3) % 3 retorna 0 = empate, 1 = derrota, 2 = vitória.
3
Acompanhe o placar: mantenha três contadores — vitórias, derrotas e empates.
4
Saída limpa: saia do laço quando o usuário digitar -1 e depois imprima o placar.
Desafios de Extensão
  • Adicione um modo melhor de três (o primeiro a 2 vitórias ganha).
  • Acompanhe com que frequência o jogador joga cada mão e faça a CPU virar uma "IA que aprende" e contra-ataca a favorita.
  • Expanda para "Pedra-Papel-Tesoura-Lagarto-Spock" (5 escolhas).
  • Salve cada rodada em um vetor e imprima o histórico completo da partida no fim.
Truque de julgamento:
// 0=Pedra, 1=Tesoura, 2=Papel
int result = (player - cpu + 3) % 3;
if (result == 0) printf("Draw\n");
else if (result == 2) printf("You win!\n");
else printf("You lose...\n");
🎰

GAME 3: Caça-Níquel

Iniciante Random Vetores Condicionais
Gire três rolos para combinar símbolos. Acompanhe o saldo de fichas do jogador enquanto sobe e desce.
🎰 Caça-Níquel (Fichas: 100) Pressione Enter para girar (10 fichas/giro)> | 🍒 | 🍋 | 🍒 | → Sem combinação Fichas restantes: 90 Pressione Enter> | 7️ | 7️ | 7️ | → 🎉 JACKPOT! +500 fichas! Fichas restantes: 580
1
Armazene os símbolos em um vetor: por exemplo, char *symbols[] = {"🍒","🍋","🔔","⭐","7"};
2
Aleatorize os três rolos: chame rand() % num_symbols três vezes.
3
Verifique as vitórias: três iguais = jackpot, duas iguais = ganho pequeno, caso contrário sem combinação.
4
Gerencie o saldo de fichas: subtraia 10 por giro e some o prêmio em caso de combinação. Fim de jogo quando as fichas chegarem a 0.
Desafios de Extensão
  • Prêmios diferentes por símbolo (ex.: três 7's pagam mais).
  • Enviese as probabilidades dos rolos (torne o 7 raro).
  • Deixe o jogador escolher quanto apostar em cada giro.
  • Salve o histórico em arquivo e recarregue na inicialização

GAME 4: Jogo da Velha

Intermediário Vetores 2D Funções Laços
Alterne colocando O e X em um tabuleiro 3x3. Primeiro a formar uma linha vence. Use um vetor 2D para gerenciar o tabuleiro.
1 | 2 | 3 ---+---+--- 4 | 5 | 6 ---+---+--- 7 | 8 | 9 Vez de O célula#> 5 | | ---+---+--- | O | ---+---+--- | | Vez de X célula#> 1 X | | ---+---+--- | O | ---+---+--- | |
1
Represente o tabuleiro com um vetor 2D: char board[3][3]. Vazio = ' ', O = 'O', X = 'X'.
2
Escreva uma função que imprime o tabuleiro: void print_board(char board[3][3]) que desenha linhas separadoras entre as fileiras.
3
Escreva uma função de verificação de vitória: examine todas as 8 linhas (3 linhas, 3 colunas, 2 diagonais).
4
Valide a entrada: rejeite células já ocupadas e qualquer valor fora de 1–9, depois peça de novo.
Desafios de Extensão
  • Adicione um oponente CPU que joga em uma célula vazia aleatória.
  • Torne a CPU mais inteligente (prefira cantos, bloqueie vitórias iminentes do oponente).
  • Escale para um tabuleiro 4x4 ou 5x5 (quatro em linha para vencer).
  • Salve estatísticas em arquivo e exiba totais acumulados.
  • Implemente uma IA minimax perfeita (avançado).
Truque de verificação de vitória:
int check_win(char b[3][3], char c) {
    for (int i = 0; i < 3; i++) {
        if (b[i][0]==c && b[i][1]==c && b[i][2]==c) return 1; // linha
        if (b[0][i]==c && b[1][i]==c && b[2][i]==c) return 1; // coluna
    }
    if (b[0][0]==c && b[1][1]==c && b[2][2]==c) return 1; // diag
    if (b[0][2]==c && b[1][1]==c && b[2][0]==c) return 1; // diag
    return 0;
}
🏃

GAME 5: Fuga do Labirinto

Intermediário Vetores 2D Structs Funções
Represente um labirinto com um vetor 2D. Mova o jogador com WASD até o objetivo.
################ #P.....#.......# #.####.#.#####.# #......#.#...#.# ######.#.#.#.#.# #......#...#...# #.##########.### #..............G ################ Mover (w/a/s/d)> d
1
Dados do labirinto: char maze[H][W], onde '#' = parede, '.' = caminho, 'P' = jogador, 'G' = objetivo.
2
Guarde a posição do jogador em uma struct: struct Pos { int x, y; };
3
Lógica de movimento: atualize a posição se a célula-alvo não for parede; caso contrário, imprima "Não pode mover".
4
Verificação do objetivo: encerre o labirinto quando a posição do jogador alcançar 'G'.
Desafios de Extensão
  • Acompanhe o número de movimentos como pontuação.
  • Adicione uma porta trancada que exige pegar uma chave antes.
  • Adicione inimigos que se movem aleatoriamente — encostar em um encerra o jogo.
  • Carregue o labirinto de um arquivo externo.
  • Tente um algoritmo de geração de labirinto (ex.: recursive backtracker).
  • Limite a "visão" às 3 células ao redor do jogador.
🃏

GAME 6: Blackjack

Intermediário Structs Vetores Funções Random
Blackjack clássico. Chegue o mais perto possível de 21 sem estourar. Represente as cartas com uma struct.
🃏 Blackjack Sua mão: [♠A] [♥K] → Total: 21 Dealer: [♦7] [??] Pedir(h) / Parar(s)> s Mão do dealer: [♦7] [♣9] → Total: 16 Dealer pede: [♠5] → Total: 21 😐 Empate!
1
Represente uma carta como struct: struct Card { int suit; int rank; };
2
Crie e embaralhe um baralho de 52 cartas: use o embaralhamento Fisher–Yates.
3
Função de total da mão: conte cada Ás como 1 ou 11, o que mantiver o total abaixo de 22.
4
IA do dealer: continua pedindo até o total ser 17 ou mais (regra padrão).
Desafios de Extensão
  • Adicione fichas e sistema de apostas.
  • Implemente double-down, split e surrender.
  • Suporte a shoes com múltiplos baralhos (6 baralhos, etc.).
  • Adicione um modo de prática de contagem de cartas.
📝

GAME 7: Forca (Adivinhação de Palavra)

Intermediário Strings Vetores Laços
Adivinhe a palavra oculta uma letra por vez. Um número fixo de erros encerra o jogo. Ótimo exercício de manipulação de strings.
Adivinhe a palavra! (erros restantes: 6) _ _ _ _ _ _ _ _ _ Letra> e _ _ _ _ _ _ _ _ e ⭕ Letra> a Sem combinação ❌ (restam: 5) Letra> r _ r _ _ r _ _ _ e ⭕
1
Prepare uma lista de palavras como vetor: char *words[] = {"programming","computer",...};
2
Acompanhe as letras reveladas em um vetor: int revealed[MAX].
3
Verifique o chute em cada posição: use um laço for e revele toda letra que combinar.
4
Condições de fim: todas as letras reveladas → vitória; muitos erros → derrota.
Desafios de Extensão
  • Desenhe o boneco da forca progressivamente em ASCII art.
  • Altere o tamanho da palavra com base na dificuldade selecionada.
  • Exiba as letras que o jogador já tentou.
  • Carregue a lista de palavras de um arquivo externo.
  • Adicione múltiplas categorias ou idiomas de palavras.
⚔️

GAME 8: Batalha de RPG Textual

Avançado Structs Ponteiros Funções Random
Combate por turnos entre herói e monstro. Guarde os atributos em uma struct e escolha entre atacar/defender/magia.
⚔️ Um Slime aparece! Herói HP:100/100 MP:30/30 Slime HP:50/50 1:Atacar 2:Defender 3:Magia > 1 Herói ataca! Slime recebe 15 de dano! HP do Slime: 35/50 Slime ataca! Herói recebe 8 de dano! HP do Herói: 92/100
1
Struct do personagem: struct Character { char name[20]; int hp, max_hp, mp, atk, def; };
2
Função de dano: int calc_damage(int atk, int def) — adicione uma variação aleatória.
3
Seleção de comando: ramifique com base na escolha do jogador entre atacar, defender ou usar magia.
4
Laço de batalha: continue até o HP de um dos lados cair a 0 ou abaixo.
Desafios de Extensão
  • Armazene múltiplos inimigos em um vetor para batalhas consecutivas.
  • Adicione pontos de experiência e level up.
  • Inventário de itens (um vetor de itens, poções, etc.).
  • IA de inimigo mais inteligente (ex.: se cura quando o HP fica baixo).
  • Adicione efeitos especiais de luta contra chefe.
  • Salve e carregue progresso com I/O de arquivo.
💣

GAME 9: Campo Minado (Minesweeper)

Avançado Vetores 2D Recursão Funções
Evite as minas enquanto revela todas as células seguras. O desafio central é contar minas vizinhas e fazer aberturas em cascata (recursão).
1 2 3 4 5 1 . . . . . 2 . . . . . 3 . . . . . 4 . . . . . 5 . . . . . Abrir (linha coluna)> 3 3 1 2 3 4 5 1 1 . . . 2 1 2 . . 3 1 . . 4 1 2 . 5 1 .
1
Use dois vetores 2D: int mines[H][W] para as posições das minas e int visible[H][W] para o que já foi revelado.
2
Espalhe as minas aleatoriamente: distribua o número alvo de minas em células únicas.
3
Contagem de vizinhos: para cada célula, verifique as 8 ao redor e conte as minas.
4
Abertura em cascata (recursão): ao abrir uma célula com 0 minas vizinhas, abra recursivamente suas vizinhas.
Desafios de Extensão
  • Adicione marcação de bandeira para suspeitas de minas.
  • Garanta que o primeiro clique nunca acerte uma mina.
  • Deixe o jogador escolher o tamanho do tabuleiro e o número de minas.
  • Meça e mostre o tempo para limpar.
  • Salve recordes em arquivo.
🧱

GAME 10: Puzzle de Blocos Caindo (estilo Tetris)

Avançado Vetores 2D Structs Timer
Blocos caem pelo topo e são eliminados quando uma linha enche. O desafio definitivo de tetris em modo texto.
| | | | | | | ## | | ## | | | | | | # | | ### | | #### ## | +----------+ Pontuação: 100 Nível: 1
1
Represente o campo de jogo com um vetor 2D que armazene os blocos fixados.
2
Defina tetrominós com struct e vetores: 7 formas em grades 4x4.
3
Detecção de colisão: garanta que uma peça rotacionada ou movida não sobreponha paredes ou blocos fixados.
4
Eliminação de linhas: remova as linhas cheias e desça tudo acima delas.
Desafios de Extensão
  • Pré-visualização da próxima peça.
  • Aumente a velocidade de queda conforme o nível sobe.
  • Função de hold (guardar uma peça para depois).
  • Salve recordes em arquivo.
Dica: Para entrada em tempo real no terminal, você vai precisar de leituras não bloqueantes — termios.h no Linux/Mac ou conio.h no Windows. O ponto de partida mais fácil é uma versão por turnos que espera cada tecla.

Roadmap

A dificuldade aumenta conforme você avança. Comece com os GAME 1–3 e, quando se sentir confortável, passe para os 4–7.
Iniciante
Adivinhação
Iniciante
Pedra-Papel-Tesoura
Iniciante
Caça-Níquel
Intermediário
Jogo da Velha
Intermediário
Labirinto
Intermediário
Blackjack
Intermediário
Forca
Avançado
Batalha de RPG
Avançado
Minesweeper
Avançado
Estilo Tetris
Compartilhe este artigo
Compartilhar no X Compartilhar no Facebook