Projeto Jogo de Adivinhação
O computador pensa num número de 1 a 100, e você tenta adivinhar. A cada palpite ele diz "é maior" ou "é menor", e você vai fechando o cerco. É o projeto clássico para treinar laços (o jogo repete até você acertar), decisões (maior, menor ou acertou) e números aleatórios. No fim, o jogo tem limite de tentativas e pergunta se você quer jogar outra partida.
- Comparar o palpite com o segredo usando if e else if.
- Repetir com while e contar as tentativas.
- Sortear um número com Random.Shared.Next (e o cuidado com o limite).
- Aceitar só números com TryParse e tratar o fim da entrada.
- Limitar as tentativas com uma constante e um
bool. - Perguntar "jogar de novo?" com do while e separar a partida num método.
O que vamos construir
O jogo pronto, numa tarde em que a Ana jogou duas partidas:
$ dotnet run adivinhacao.cs === Jogo de Adivinhação === Partida 1: pensei num número de 1 a 100. Você tem 7 tentativas. Palpite 1 de 7: 10 O número é maior que 10. Palpite 2 de 7: 20 O número é maior que 20. Palpite 3 de 7: 30 O número é maior que 30. Palpite 4 de 7: 40 O número é maior que 40. Palpite 5 de 7: 60 O número é maior que 60. Palpite 6 de 7: 70 O número é maior que 70. Palpite 7 de 7: 80 O número é menor que 80. Suas 7 tentativas acabaram. O número era 78. Jogar de novo? (s/n): talvez Jogar de novo? (s/n): s Partida 2: pensei num número de 1 a 100. Você tem 7 tentativas. Palpite 1 de 7: 50 O número é menor que 50. Palpite 2 de 7: 25 O número é maior que 25. Palpite 3 de 7: 37 O número é maior que 37. Palpite 4 de 7: 43 Acertou! Tentativas: 4. Jogar de novo? (s/n): n Partidas: 2. Até a próxima!
Na segunda partida, a Ana usou a melhor estratégia: chutar sempre o meio do que sobrou (50, depois 25 ou 75…). Cada palpite corta as possibilidades pela metade, e assim 7 palpites sempre bastam para 100 números. Essa ideia tem nome: busca binária.
- Um palpite contra um número fixo.
- Repetir até acertar e contar as tentativas.
- Sortear o número e aceitar só números.
- No máximo 7 tentativas.
- Jogar de novo (
do whilee um método).
Antes de começar
Você precisa ter visto if e else, else if, while, Ler do Teclado e Parse e TryParse; para as versões finais, Números Aleatórios, do while e Métodos. É um arquivo só, adivinhacao.cs (sem acento no nome do arquivo, para evitar problemas no terminal):
$ mkdir -p cs/adivinhacao $ cd cs/adivinhacao
Versão 1 · Um palpite contra um número fixo
Antes de sortear, vamos fazer o jogo funcionar com um número que nós escolhemos: 42. Assim dá para testar e saber a resposta certa. O programa lê um palpite e diz se acertou, se o número é maior ou se é menor.
const int Segredo = 42;
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine("Pensei num número de 1 a 100.");
Console.Write("Seu palpite: ");
int palpite = int.Parse(Console.ReadLine()!);
if (palpite == Segredo)
{
Console.WriteLine("Acertou!");
}
else if (palpite < Segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
- const int Segredo = 42;
- Uma constante: um valor com nome que nunca muda. Por convenção, constantes têm nome em PascalCase.
- int.Parse(Console.ReadLine()!)
- Lê o palpite e converte em
int(inteiro). Por enquanto, sem proteção: a versão 3 troca porTryParse. - if (palpite == Segredo)
==compara ("é igual a?"). Não confunda com=, que guarda um valor (Operadores de Comparação).- else if (palpite < Segredo)
- Só é testado se o primeiro
iffoi falso. Se o palpite é menor que o segredo, a dica é "o número é maior". - else
- Sobrou um caso: o palpite é maior que o segredo.
$ dotnet run adivinhacao.cs === Jogo de Adivinhação === Pensei num número de 1 a 100. Seu palpite: 30 O número é maior que 30. $ dotnet run adivinhacao.cs === Jogo de Adivinhação === Pensei num número de 1 a 100. Seu palpite: 50 O número é menor que 50. $ dotnet run adivinhacao.cs === Jogo de Adivinhação === Pensei num número de 1 a 100. Seu palpite: 42 Acertou!
Testamos os três caminhos do if: maior, menor e igual. É um bom hábito: para cada decisão do programa, um teste que passa por ela.
Missão (versão 1): falta o último caso. Acrescente o else que mostra O número é menor que 50. (use {palpite}, não o número escrito). A entrada da missão é o palpite 50.
const int Segredo = 42;
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine("Pensei num número de 1 a 100.");
Console.Write("Seu palpite: ");
int palpite = int.Parse(Console.ReadLine()!);
if (palpite == Segredo)
{
Console.WriteLine("Acertou!");
}
else if (palpite < Segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
// acrescente o else
const int Segredo = 42;
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine("Pensei num número de 1 a 100.");
Console.Write("Seu palpite: ");
int palpite = int.Parse(Console.ReadLine()!);
if (palpite == Segredo)
{
Console.WriteLine("Acertou!");
}
else if (palpite < Segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
Versão 2 · Repetir até acertar e contar as tentativas
Um palpite só não é jogo. A pergunta e o if vão para dentro de um while (true), que repete até o break do acerto. E uma variável tentativas conta os palpites.
const int Segredo = 42;
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine("Pensei num número de 1 a 100.");
int tentativas = 0;
while (true)
{
Console.Write("Seu palpite: ");
int palpite = int.Parse(Console.ReadLine()!);
tentativas++;
if (palpite == Segredo)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
break;
}
else if (palpite < Segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
- int tentativas = 0;
- Fica fora do laço: se ficasse dentro, voltaria a 0 a cada palpite (veja Escopo).
- while (true)
- Repete "para sempre". Quem para o laço é o
break. - int palpite = …;
- Agora fica dentro do laço: cada volta lê um palpite novo.
- tentativas++;
- Soma 1 a cada palpite (++ e --).
- break;
- Acertou: sai do
while, e o programa termina.
$ dotnet run adivinhacao.cs === Jogo de Adivinhação === Pensei num número de 1 a 100. Seu palpite: 50 O número é menor que 50. Seu palpite: 25 O número é maior que 25. Seu palpite: 37 O número é maior que 37. Seu palpite: 43 O número é menor que 43. Seu palpite: 40 O número é maior que 40. Seu palpite: 42 Acertou! Tentativas: 6.
CS0165
A Ana tentou um laço diferente, que repete "enquanto o palpite for diferente do segredo":
const int Segredo = 42;
int palpite;
while (palpite != Segredo)
{
Console.Write("Seu palpite: ");
palpite = int.Parse(Console.ReadLine()!);
}
Console.WriteLine("Acertou!");
$ dotnet run adivinhacao.cs /home/ana/cs/adivinhacao/adivinhacao.cs(4,8): error CS0165: Uso de variável local não atribuída "palpite" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: na linha 4, coluna 8, o while compara palpite com o segredo, mas palpite ainda não recebeu nenhum valor (em inglês, Use of unassigned local variable). O C# não deixa ler uma variável local antes de guardar algo nela, para você nunca usar um valor "lixo".
Como consertar: dê um valor inicial que com certeza não é o segredo (int palpite = 0;), ou use o while (true) com break da versão 2, que lê o palpite antes de comparar. Um do while também resolve, porque roda o corpo antes de testar a condição.
Missão (versão 2): o jogo repete, mas sempre diz Tentativas: 0.. Conte cada palpite com tentativas++; logo depois de ler o número. A entrada da missão são os palpites 50, 25 e 42.
const int Segredo = 42;
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine("Pensei num número de 1 a 100.");
int tentativas = 0;
while (true)
{
Console.Write("Seu palpite: ");
int palpite = int.Parse(Console.ReadLine()!);
// conte o palpite
if (palpite == Segredo)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
break;
}
else if (palpite < Segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
const int Segredo = 42;
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine("Pensei num número de 1 a 100.");
int tentativas = 0;
while (true)
{
Console.Write("Seu palpite: ");
int palpite = int.Parse(Console.ReadLine()!);
tentativas++;
if (palpite == Segredo)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
break;
}
else if (palpite < Segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
Versão 3 · Sortear o número e aceitar só números
Com o 42 fixo, o jogo perde a graça na segunda vez. Agora o computador sorteia. E, já que o jogo vai ser usado de verdade, ele precisa aguentar um palpite como abc sem cair.
int segredo = Random.Shared.Next(1, 101);
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine("Pensei num número de 1 a 100.");
int tentativas = 0;
while (true)
{
Console.Write("Seu palpite: ");
string? texto = Console.ReadLine();
if (texto is null)
{
Console.WriteLine();
Console.WriteLine("Jogo interrompido.");
return;
}
if (!int.TryParse(texto, out int palpite))
{
Console.WriteLine("Digite um número inteiro.");
continue;
}
tentativas++;
if (palpite == segredo)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
break;
}
else if (palpite < segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
- Random.Shared.Next(1, 101)
- Sorteia um inteiro de 1 a 100. O primeiro número entra no sorteio; o segundo não (é o "limite de fora"). Por isso 101.
Random.Sharedé um sorteador pronto, que o .NET cria uma vez e todo o programa compartilha (veja Números Aleatórios). - int segredo
- Não é mais
const: o valor só é conhecido quando o programa roda. Por isso o nome volta para camelCase. - string? texto = Console.ReadLine();
- Primeiro guardamos o texto. O
?diz que ele pode sernull: é o que oReadLinedevolve quando a entrada acaba (com Ctrl+D no terminal, ou no fim de um arquivo). Veja Referências Anuláveis. - if (texto is null) { …; return; }
- Sem entrada, não há jogo: avisa e termina. O cenário "laço infinito" abaixo mostra o que acontece sem essas linhas.
- if (!int.TryParse(texto, out int palpite)) { …; continue; }
- Se não é um número, avisa e volta para o começo do laço (
continue), sem contar a tentativa.
$ dotnet run adivinhacao.cs === Jogo de Adivinhação === Pensei num número de 1 a 100. Seu palpite: abc Digite um número inteiro. Seu palpite: 50 O número é maior que 50. Seu palpite: 75 O número é maior que 75. Seu palpite: 88 O número é maior que 88. Seu palpite: 94 O número é maior que 94. Seu palpite: 97 O número é maior que 97. Seu palpite: 99 O número é maior que 99. Seu palpite: 100 Acertou! Tentativas: 7.
O abc não contou como tentativa, e o 100 foi sorteado: o limite de 101 funcionou. Rodando de novo, o número é outro.
Next(1, 100): o 100 nunca sai
Na primeira tentativa, a Ana escreveu Random.Shared.Next(1, 100), achando que era "de 1 a 100". Para conferir, ela sorteou um milhão de vezes e guardou o maior:
int maior = 0;
for (int i = 0; i < 1_000_000; i++)
{
int sorteado = Random.Shared.Next(1, 100);
maior = Math.Max(maior, sorteado);
}
Console.WriteLine($"Maior número sorteado em 1 milhão de vezes: {maior}");
$ dotnet run limite.cs Maior número sorteado em 1 milhão de vezes: 99
O que significa: em Next(mínimo, máximo), o máximo não entra. Não é um erro de compilação nem uma exceção: o jogo funciona, só que quem pensa no 100 nunca ganha. Esse tipo de erro "por um" (em inglês, off-by-one) é um dos mais comuns em programação.
Como consertar: Next(1, 101). Para não esquecer, leia o segundo número como "até antes de".
Numa versão anterior, a Ana leu o palpite com string texto = Console.ReadLine() ?? "";, sem o if (texto is null). Para testar, ela mandou dois palpites de um arquivo (veja Sobre os Projetos):
$ cat palpites.txt 50 75 $ dotnet run adivinhacao.cs < palpites.txt === Jogo de Adivinhação === Pensei num número de 1 a 100. Seu palpite: O número é menor que 50. Seu palpite: O número é menor que 75. Seu palpite: Digite um número inteiro. Seu palpite: Digite um número inteiro. Seu palpite: Digite um número inteiro. Seu palpite: Digite um número inteiro. Seu palpite: Digite um número inteiro. … « sem parar, até a Ana apertar Ctrl+C ^C
O que aconteceu: depois do 75, o arquivo acabou. Dali em diante, cada ReadLine() devolve null na hora, o ?? "" troca por texto vazio, o TryParse("") falha e o continue volta ao começo, para sempre. Com uma pessoa digitando isso não aparece, mas com um arquivo (ou num teste automático) o programa nunca termina.
Como consertar: trate o null separadamente, como na versão 3: "a entrada acabou, então o jogo acaba". Para parar um programa travado no terminal, aperte Ctrl+C.
Missão (versão 3): o segredo ainda é o 42 fixo. Troque a primeira linha por um sorteio de 1 a 100: int segredo = Random.Shared.Next(1, 101);, e use segredo no lugar de Segredo nas comparações. Para a missão funcionar com qualquer número sorteado, a entrada são os palpites 1, 2, 3… até 100: um deles acerta.
const int Segredo = 42;
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine("Pensei num número de 1 a 100.");
int tentativas = 0;
while (true)
{
Console.Write("Seu palpite: ");
string? texto = Console.ReadLine();
if (texto is null)
{
Console.WriteLine();
Console.WriteLine("Jogo interrompido.");
return;
}
if (!int.TryParse(texto, out int palpite))
{
Console.WriteLine("Digite um número inteiro.");
continue;
}
tentativas++;
if (palpite == Segredo)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
break;
}
else if (palpite < Segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
int segredo = Random.Shared.Next(1, 101);
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine("Pensei num número de 1 a 100.");
int tentativas = 0;
while (true)
{
Console.Write("Seu palpite: ");
string? texto = Console.ReadLine();
if (texto is null)
{
Console.WriteLine();
Console.WriteLine("Jogo interrompido.");
return;
}
if (!int.TryParse(texto, out int palpite))
{
Console.WriteLine("Digite um número inteiro.");
continue;
}
tentativas++;
if (palpite == segredo)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
break;
}
else if (palpite < segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
Versão 4 · No máximo 7 tentativas
Sem limite, qualquer um ganha chutando 1, 2, 3… Com 7 tentativas, só ganha quem pensa (7 é exatamente o que a busca binária precisa para 100 números). O laço deixa de ser "para sempre": ele roda enquanto ainda há tentativas. Ao sair, o programa precisa saber por que saiu (acertou ou acabaram as tentativas), e para isso usamos um bool.
const int MaxTentativas = 7;
int segredo = Random.Shared.Next(1, 101);
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine($"Pensei num número de 1 a 100. Você tem {MaxTentativas} tentativas.");
int tentativas = 0;
bool acertou = false;
while (tentativas < MaxTentativas)
{
Console.Write($"Palpite {tentativas + 1} de {MaxTentativas}: ");
string? texto = Console.ReadLine();
if (texto is null)
{
Console.WriteLine();
Console.WriteLine("Jogo interrompido.");
return;
}
if (!int.TryParse(texto, out int palpite))
{
Console.WriteLine("Digite um número inteiro.");
continue;
}
tentativas++;
if (palpite == segredo)
{
acertou = true;
break;
}
else if (palpite < segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
if (acertou)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
}
else
{
Console.WriteLine($"Suas {MaxTentativas} tentativas acabaram. O número era {segredo}.");
}
- const int MaxTentativas = 7;
- O limite com nome. Quer um modo fácil, com 10? Muda uma linha.
- bool acertou = false;
- Uma "bandeira" (em inglês, flag): começa abaixada e só sobe quando a Ana acerta (bool).
- while (tentativas < MaxTentativas)
- Roda enquanto a Ana tiver tentativas: na 7ª,
tentativasvira 7 e o laço para sozinho. - $"Palpite {tentativas + 1} de {MaxTentativas}: "
- Mostra qual palpite é: o primeiro é o 1, quando
tentativasainda vale 0. - acertou = true; break;
- Levanta a bandeira e sai do laço antes do fim.
- if (acertou) … else …
- Depois do laço, a bandeira diz como ele terminou.
$ dotnet run adivinhacao.cs === Jogo de Adivinhação === Pensei num número de 1 a 100. Você tem 7 tentativas. Palpite 1 de 7: 50 O número é maior que 50. Palpite 2 de 7: 75 O número é maior que 75. Palpite 3 de 7: 88 O número é maior que 88. Palpite 4 de 7: 94 O número é maior que 94. Palpite 5 de 7: 97 O número é maior que 97. Palpite 6 de 7: 99 Acertou! Tentativas: 6. $ dotnet run adivinhacao.cs === Jogo de Adivinhação === Pensei num número de 1 a 100. Você tem 7 tentativas. Palpite 1 de 7: 1 O número é maior que 1. Palpite 2 de 7: 2 O número é maior que 2. Palpite 3 de 7: 3 O número é maior que 3. Palpite 4 de 7: 4 O número é maior que 4. Palpite 5 de 7: 5 O número é maior que 5. Palpite 6 de 7: 6 O número é maior que 6. Palpite 7 de 7: 7 O número é maior que 7. Suas 7 tentativas acabaram. O número era 60.
Missão (versão 4): o jogo ainda não tem limite. Troque o while (true) por while (tentativas < MaxTentativas) e, no else do fim, mostre Suas 7 tentativas acabaram. O número era … com o segredo. A entrada são os palpites 1 a 7: dependendo do sorteio, a Ana ganha ou perde, e as duas saídas valem.
const int MaxTentativas = 7;
int segredo = Random.Shared.Next(1, 101);
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine($"Pensei num número de 1 a 100. Você tem {MaxTentativas} tentativas.");
int tentativas = 0;
bool acertou = false;
while (true)
{
Console.Write($"Palpite {tentativas + 1} de {MaxTentativas}: ");
string? texto = Console.ReadLine();
if (texto is null)
{
Console.WriteLine();
Console.WriteLine("Jogo interrompido.");
return;
}
if (!int.TryParse(texto, out int palpite))
{
Console.WriteLine("Digite um número inteiro.");
continue;
}
tentativas++;
if (palpite == segredo)
{
acertou = true;
break;
}
else if (palpite < segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
if (acertou)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
}
else
{
// mostre que as tentativas acabaram e qual era o número
}
const int MaxTentativas = 7;
int segredo = Random.Shared.Next(1, 101);
Console.WriteLine("=== Jogo de Adivinhação ===");
Console.WriteLine($"Pensei num número de 1 a 100. Você tem {MaxTentativas} tentativas.");
int tentativas = 0;
bool acertou = false;
while (tentativas < MaxTentativas)
{
Console.Write($"Palpite {tentativas + 1} de {MaxTentativas}: ");
string? texto = Console.ReadLine();
if (texto is null)
{
Console.WriteLine();
Console.WriteLine("Jogo interrompido.");
return;
}
if (!int.TryParse(texto, out int palpite))
{
Console.WriteLine("Digite um número inteiro.");
continue;
}
tentativas++;
if (palpite == segredo)
{
acertou = true;
break;
}
else if (palpite < segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
if (acertou)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
}
else
{
Console.WriteLine($"Suas {MaxTentativas} tentativas acabaram. O número era {segredo}.");
}
Versão 5 · Jogar de novo
Para jogar outra partida, a Ana tinha de rodar o programa de novo. Na versão final, o programa pergunta "Jogar de novo?". Duas mudanças:
- A partida inteira vai para um método
Jogar(). O programa principal fica só com o "jogar enquanto a Ana quiser". - Dois do while: um para as partidas e outro para a pergunta. O
do whileroda o corpo pelo menos uma vez e só depois testa a condição: perfeito para "jogue uma partida, depois pergunte" e para "pergunte até a resposta ser s ou n".
const int MaxTentativas = 7;
Console.WriteLine("=== Jogo de Adivinhação ===");
int partidas = 0;
string resposta;
do
{
partidas++;
Console.WriteLine();
Console.WriteLine($"Partida {partidas}: pensei num número de 1 a 100. Você tem {MaxTentativas} tentativas.");
Jogar();
do
{
Console.Write("Jogar de novo? (s/n): ");
resposta = (Console.ReadLine() ?? "n").Trim().ToLower();
} while (resposta != "s" && resposta != "n");
} while (resposta == "s");
Console.WriteLine($"Partidas: {partidas}. Até a próxima!");
static void Jogar()
{
int segredo = Random.Shared.Next(1, 101);
int tentativas = 0;
while (tentativas < MaxTentativas)
{
Console.Write($"Palpite {tentativas + 1} de {MaxTentativas}: ");
string? texto = Console.ReadLine();
if (texto is null)
{
Console.WriteLine();
Console.WriteLine("Jogo interrompido.");
return;
}
if (!int.TryParse(texto, out int palpite))
{
Console.WriteLine("Digite um número inteiro.");
continue;
}
tentativas++;
if (palpite == segredo)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
return;
}
if (palpite < segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
Console.WriteLine($"Suas {MaxTentativas} tentativas acabaram. O número era {segredo}.");
}
- string resposta;
- Declarada antes do
do, porque owhile (resposta == "s")do fim fica fora das chaves e precisa enxergá-la (Escopo). Não precisa de valor inicial: o C# vê que odosempre guarda algo nela antes do teste. - do { … } while (resposta == "s");
- Joga uma partida, pergunta, e repete se a resposta for
s. Repare no;depois dowhile: nodo whileele é obrigatório. - (Console.ReadLine() ?? "n").Trim().ToLower()
- Se a entrada acabou, vale "n". O
Trim()tira os espaços das pontas e oToLower()passa para minúsculas:" S "vira"s"(Métodos de String). - while (resposta != "s" && resposta != "n")
- Pergunta de novo enquanto a resposta não for nem
snemn:talveznão vale (&&). - static void Jogar()
- A partida inteira.
voidquer dizer "não devolve nada". Osegredoe astentativasagora são variáveis do método: cada partida começa do zero. - return; (dentro de Jogar)
- Termina só a partida e volta para quem chamou. O
bool acertounão é mais necessário: se o laço acabar semreturn, as tentativas acabaram. - MaxTentativas dentro de Jogar()
- Um
staticlocal enxerga as constantes do programa principal (mas não as variáveis comuns, comopartidas; veja Funções Locais).
A saída é a do começo da página, em "O que vamos construir".
Missão (versão 5): o jogo repete, mas o fim sempre diz Partidas: 0. (e as partidas aparecem como "Partida 0"). No começo do do de fora, conte a partida com partidas++;. A entrada joga duas partidas (palpites 1 a 7, s, palpites 1 a 7, n); quando a Ana acerta antes do 7º palpite, os números que sobram são respondidos na pergunta "Jogar de novo?", que os recusa até chegar o s ou o n.
const int MaxTentativas = 7;
Console.WriteLine("=== Jogo de Adivinhação ===");
int partidas = 0;
string resposta;
do
{
// conte a partida
Console.WriteLine();
Console.WriteLine($"Partida {partidas}: pensei num número de 1 a 100. Você tem {MaxTentativas} tentativas.");
Jogar();
do
{
Console.Write("Jogar de novo? (s/n): ");
resposta = (Console.ReadLine() ?? "n").Trim().ToLower();
} while (resposta != "s" && resposta != "n");
} while (resposta == "s");
Console.WriteLine($"Partidas: {partidas}. Até a próxima!");
static void Jogar()
{
int segredo = Random.Shared.Next(1, 101);
int tentativas = 0;
while (tentativas < MaxTentativas)
{
Console.Write($"Palpite {tentativas + 1} de {MaxTentativas}: ");
string? texto = Console.ReadLine();
if (texto is null)
{
Console.WriteLine();
Console.WriteLine("Jogo interrompido.");
return;
}
if (!int.TryParse(texto, out int palpite))
{
Console.WriteLine("Digite um número inteiro.");
continue;
}
tentativas++;
if (palpite == segredo)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
return;
}
if (palpite < segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
Console.WriteLine($"Suas {MaxTentativas} tentativas acabaram. O número era {segredo}.");
}
const int MaxTentativas = 7;
Console.WriteLine("=== Jogo de Adivinhação ===");
int partidas = 0;
string resposta;
do
{
partidas++;
Console.WriteLine();
Console.WriteLine($"Partida {partidas}: pensei num número de 1 a 100. Você tem {MaxTentativas} tentativas.");
Jogar();
do
{
Console.Write("Jogar de novo? (s/n): ");
resposta = (Console.ReadLine() ?? "n").Trim().ToLower();
} while (resposta != "s" && resposta != "n");
} while (resposta == "s");
Console.WriteLine($"Partidas: {partidas}. Até a próxima!");
static void Jogar()
{
int segredo = Random.Shared.Next(1, 101);
int tentativas = 0;
while (tentativas < MaxTentativas)
{
Console.Write($"Palpite {tentativas + 1} de {MaxTentativas}: ");
string? texto = Console.ReadLine();
if (texto is null)
{
Console.WriteLine();
Console.WriteLine("Jogo interrompido.");
return;
}
if (!int.TryParse(texto, out int palpite))
{
Console.WriteLine("Digite um número inteiro.");
continue;
}
tentativas++;
if (palpite == segredo)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
return;
}
if (palpite < segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
Console.WriteLine($"Suas {MaxTentativas} tentativas acabaram. O número era {segredo}.");
}
As missões desta página nunca dependem do número sorteado: a entrada cobre todos os casos (os palpites de 1 a 100, ou "ganhou ou perdeu, tanto faz"). Outra técnica, muito usada em testes automáticos, é criar o sorteador com uma semente fixa, new Random(123), que sorteia sempre a mesma sequência. Veja Números Aleatórios e Testes.
O programa completo
A versão final é a versão 5, acima. O que o projeto juntou: const, if e else if, while, do while, break e continue, Random.Shared, TryParse, string? e um método void.
Agora, jogue de verdade. Esta caixa traz a versão final, sem nenhuma entrada pronta. Quando o jogo pedir um palpite, aparece um campo no terminal da caixa, logo depois da pergunta: digite o número e tecle Enter. O número secreto continua o mesmo durante toda a partida, e Ctrl+D encerra a entrada (o jogo mostra Jogo interrompido. e termina).
const int MaxTentativas = 7;
Console.WriteLine("=== Jogo de Adivinhação ===");
int partidas = 0;
string resposta;
do
{
partidas++;
Console.WriteLine();
Console.WriteLine($"Partida {partidas}: pensei num número de 1 a 100. Você tem {MaxTentativas} tentativas.");
Jogar();
do
{
Console.Write("Jogar de novo? (s/n): ");
resposta = (Console.ReadLine() ?? "n").Trim().ToLower();
} while (resposta != "s" && resposta != "n");
} while (resposta == "s");
Console.WriteLine($"Partidas: {partidas}. Até a próxima!");
static void Jogar()
{
int segredo = Random.Shared.Next(1, 101);
int tentativas = 0;
while (tentativas < MaxTentativas)
{
Console.Write($"Palpite {tentativas + 1} de {MaxTentativas}: ");
string? texto = Console.ReadLine();
if (texto is null)
{
Console.WriteLine();
Console.WriteLine("Jogo interrompido.");
return;
}
if (!int.TryParse(texto, out int palpite))
{
Console.WriteLine("Digite um número inteiro.");
continue;
}
tentativas++;
if (palpite == segredo)
{
Console.WriteLine($"Acertou! Tentativas: {tentativas}.");
return;
}
if (palpite < segredo)
{
Console.WriteLine($"O número é maior que {palpite}.");
}
else
{
Console.WriteLine($"O número é menor que {palpite}.");
}
}
Console.WriteLine($"Suas {MaxTentativas} tentativas acabaram. O número era {segredo}.");
}
Desafios extras
- Recorde. Faça o
Jogar()devolver umint(as tentativas, ou 0 se perdeu) e mostre no fim o menor número de tentativas das partidas (veja Valor de Retorno). - Níveis. Pergunte o nível antes de cada partida: fácil (1 a 50, 10 tentativas), normal (1 a 100, 7) e difícil (1 a 1000, 10). Um enum e uma expressão switch ajudam.
- Esquentando. Além de "maior" ou "menor", diga "está quente!" quando o palpite estiver a menos de 5 do segredo (
Math.Abs(palpite - segredo) < 5, veja Math). - Fora da faixa. Recuse palpites menores que 1 ou maiores que 100 sem gastar tentativa.
- O computador adivinha. Inverta o jogo: você pensa no número, e o programa chuta o meio e pergunta "maior, menor ou acertei?".
Exercícios
1. Quais números Random.Shared.Next(1, 7) pode sortear?
2. Qual a diferença entre while e do while?
3. Por que int tentativas = 0; fica fora do while?
4. O que o CS0165 ("Uso de variável local não atribuída") quer dizer?
5. Complete o sorteio de um número de 1 a 100:
6. Complete o laço que pergunta até a resposta ser s ou n:
Resumo
- Comece com um segredo fixo para testar; sorteie só quando o jogo funcionar.
Random.Shared.Next(1, 101)sorteia de 1 a 100: o segundo número não entra.while (true)combreakrepete até acertar;while (tentativas < MaxTentativas)repete enquanto há tentativas, e umbooldiz como o laço terminou.TryParsecomcontinuerecusa palpites que não são números sem gastar tentativa.- Trate o
nulldoReadLine(fim da entrada), senão um laço comcontinuenunca termina. do whileroda pelo menos uma vez: ótimo para "jogar de novo?" e para repetir uma pergunta até a resposta valer.
Próximo projeto: Boletim de Notas.