Projeto Jogo de Adivinhação

O computador pensa num número de 1 a 100 e você tenta adivinhar. A cada palpite, ele diz "mais alto" ou "mais baixo", até você acertar ou as tentativas acabarem. É um jogo pequeno, mas tem tudo o que um programa de verdade tem: um sorteio, um laço, decisões, uma conta de tentativas e a obrigação de não quebrar quando alguém digita "sete" no lugar de 7.

Você vai praticar

O que vamos construir

O jogo pronto, no terminal da Ana. Os números depois dos dois-pontos foram digitados por ela; o resto é o programa:

$ python3 adivinhacao.py
=== Jogo de Adivinhação ===
Pensei num número de 1 a 100. Você tem 7 tentativas.
Tentativa 1/7: 50
Mais alto!
Tentativa 2/7: 75
Mais baixo!
Tentativa 3/7: 62
Mais alto!
Tentativa 4/7: 68
Mais baixo!
Tentativa 5/7: 65
Mais baixo!
Tentativa 6/7: 63
Acertou em 6 tentativa(s)!
Novo recorde!
Seu recorde: 6 tentativa(s).
Jogar de novo? (s/n): s
Pensei num número de 1 a 100. Você tem 7 tentativas.
Tentativa 1/7: 50
Mais baixo!
Tentativa 2/7: 25
Mais baixo!
Tentativa 3/7: 12
Mais baixo!
Tentativa 4/7: 6
Mais alto!
Tentativa 5/7: 9
Mais baixo!
Tentativa 6/7: 7
Mais alto!
Tentativa 7/7: 8
Acertou em 7 tentativa(s)!                     « 7 não bate o recorde de 6
Seu recorde: 6 tentativa(s).
Jogar de novo? (s/n): s
Pensei num número de 1 a 100. Você tem 7 tentativas.
Tentativa 1/7: 10
Mais alto!
Tentativa 2/7: 20
Mais alto!
Tentativa 3/7: 30
Mais alto!
Tentativa 4/7: 40
Mais baixo!
Tentativa 5/7: 39
Mais baixo!
Tentativa 6/7: 38
Mais baixo!
Tentativa 7/7: 37
Mais baixo!
Suas tentativas acabaram. O número era 36.     « desta vez ela perdeu
Seu recorde: 6 tentativa(s).
Jogar de novo? (s/n): n
Até a próxima!

Cinco versões, uma novidade em cada:

  1. Um sorteio, um palpite (import random, randint, int).
  2. Dicas até acertar (while).
  3. Tentativas contadas e limitadas (for, range, break, else).
  4. Palpite validado (try/except, continue).
  5. Várias partidas e recorde (def, return, None).

Antes de começar

Este projeto usa o que você viu na Calculadora: input(), conversão, if/elif e while. Crie a pasta do jogo; o arquivo vai se chamar adivinhacao.py (sem acento e sem cedilha no nome do arquivo, que é o costume):

$ mkdir -p projetos/adivinhacao
$ cd projetos/adivinhacao

Antes de tudo: sorteio e semente

O sorteio vem do módulo random ("aleatório"), que faz parte do Python: basta um import random no começo do programa. A função random.randint(1, 100) sorteia um número inteiro de 1 a 100, com o 1 e o 100 incluídos. No modo interativo:

$ python3
Python 3.14.4 (main, Aug 20 2026, 10:41:58) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import random
>>> random.randint(1, 100)
81
>>> random.randint(1, 100)
49
>>> random.seed(42)
>>> random.randint(1, 100)
82
>>> random.randint(1, 100)
15
>>> random.seed(42)
>>> random.randint(1, 100)
82
>>> exit()

Os dois primeiros sorteios deram 81 e 49 no computador da Ana; no seu, vão dar outros números, e a cada vez outros. Agora repare no random.seed(42): depois dele, o primeiro sorteio deu 82, o segundo 15, e quando a Ana chamou random.seed(42) de novo, o sorteio voltou a dar 82.

O que é a semente (seed)

O computador não "joga dados" de verdade: ele calcula uma sequência de números que parecem aleatórios, a partir de um número inicial, a semente (em inglês, seed). Sem seed, o Python escolhe uma semente diferente a cada execução, e o jogo é imprevisível. Com random.seed(42), a semente é sempre 42, e a sequência é sempre a mesma: 82, 15, 4, 95…

Isso é ótimo para testar: se o número secreto é sempre 82, dá para conferir se o programa responde certo. Por isso, todas as missões desta página começam com random.seed(42), e o número secreto delas é sempre 82 (e, numa segunda partida, 15). No jogo de verdade, a linha do seed sai: senão a Ana decoraria a resposta.

import random

random.seed(42)
print(random.randint(1, 100), random.randint(1, 100), random.randint(1, 100))
$ python3 semente.py
82 15 4
$ python3 semente.py
82 15 4

Versão 1 · Um sorteio, um palpite

A versão mais simples: o programa sorteia, a pessoa dá um palpite, e o programa diz se ela acertou.

import random

secreto = random.randint(1, 100)
print("Pensei num número de 1 a 100.")
palpite = int(input("Seu palpite: "))

if palpite == secreto:
    print("Acertou!")
else:
    print(f"Errou! O número era {secreto}.")
import random
Traz o módulo random para o programa. Fica sempre no começo do arquivo (veja Módulos e import).
secreto = random.randint(1, 100)
Sorteia o número e guarda na variável secreto. O random. na frente diz de qual módulo vem a função.
int(input("Seu palpite: "))
Pergunta e converte o texto em número inteiro. Aqui é int, e não float: o número secreto não tem casas decimais.
if palpite == secreto:
Compara os dois números.
f"Errou! O número era {secreto}."
Quando erra, a pessoa merece saber qual era.
$ python3 adivinhacao.py
Pensei num número de 1 a 100.
Seu palpite: 50
Errou! O número era 81.
$ python3 adivinhacao.py
Pensei num número de 1 a 100.
Seu palpite: 50
Errou! O número era 39.

O mesmo palpite, dois números secretos diferentes: o sorteio funciona. Mas com um palpite só, acertar é questão de sorte (uma chance em cem). A versão 2 dá dicas.

Esquecer o import
$ python3 adivinhacao.py
Traceback (most recent call last):
  File "/home/ana/projetos/adivinhacao/adivinhacao.py", line 1, in <module>
    secreto = random.randint(1, 100)
              ^^^^^^
NameError: name 'random' is not defined. Did you forget to import 'random'?

NameError: name 'random' is not defined = "o nome random não está definido". Sem o import random, o Python não sabe o que é random; o ^^^^^^ aponta exatamente essa palavra. E o próprio Python dá a dica: "Did you forget to import 'random'?" = "Você esqueceu de importar random?". Como consertar: import random na primeira linha.

Um arquivo chamado random.py na pasta

A Ana quis testar o sorteio num arquivo à parte e o chamou de random.py, na mesma pasta do jogo (o arquivo só tinha um print("testando o sorteio")). Depois disso, o jogo parou de funcionar:

$ python3 adivinhacao.py
testando o sorteio
Traceback (most recent call last):
  File "/home/ana/projetos/adivinhacao/adivinhacao.py", line 3, in <module>
    secreto = random.randint(1, 100)
              ^^^^^^^^^^^^^^
AttributeError: module 'random' has no attribute 'randint' (consider renaming '/home/ana/projetos/adivinhacao/random.py' since it has the same name as the standard library module named 'random' and prevents importing that standard library module)

Repare no testando o sorteio logo no começo: o import random rodou o arquivo dela, e não o módulo do Python. Quando um programa faz import random, o Python procura primeiro na pasta do programa, e só depois na sua própria biblioteca. O arquivo dela não tem nenhuma função randint, daí o AttributeError ("erro de atributo": o módulo random não tem o atributo randint). A mensagem até sugere a solução: "consider renaming…" = "considere renomear o seu random.py, que tem o mesmo nome do módulo random da biblioteca padrão e impede que ele seja importado". Como consertar: dê outro nome ao arquivo de teste (teste_sorteio.py). Nunca chame um arquivo seu de random.py, math.py, csv.py…

Missão (versão 1): com a semente 42, o número secreto é 82, e a entrada da missão é justamente 82. Mesmo assim, o programa diz "Errou!". Descubra por quê (dica: o que o input() devolve?) e conserte para aparecer Acertou!.

import random

random.seed(42)  # só para a missão: o número secreto é sempre 82
secreto = random.randint(1, 100)
print("Pensei num número de 1 a 100.")
palpite = input("Seu palpite: ")

if palpite == secreto:
    print("Acertou!")
else:
    print(f"Errou! O número era {secreto}.")
import random

random.seed(42)  # só para a missão: o número secreto é sempre 82
secreto = random.randint(1, 100)
print("Pensei num número de 1 a 100.")
palpite = int(input("Seu palpite: "))

if palpite == secreto:
    print("Acertou!")
else:
    print(f"Errou! O número era {secreto}.")

O input() devolveu o texto "82", e o texto "82" não é igual ao número 82: para o Python, são coisas de tipos diferentes, e o == entre elas dá False, sem erro nenhum. Esse é um dos enganos mais comuns de quem começa.


Versão 2 · Dicas até acertar

Agora o jogo fica de verdade: enquanto o palpite for diferente do número secreto, o programa dá uma dica e pede outro palpite. "Enquanto" é while.

import random

secreto = random.randint(1, 100)
print("Pensei num número de 1 a 100. Tente adivinhar!")

palpite = int(input("Seu palpite: "))
while palpite != secreto:
    if palpite < secreto:
        print("Mais alto!")
    else:
        print("Mais baixo!")
    palpite = int(input("Seu palpite: "))

print(f"Acertou! O número era {secreto}.")
LinhaO que faz
palpite = int(input(…)) (antes do laço)O primeiro palpite. Ele precisa existir antes do while, porque a condição do laço usa palpite.
while palpite != secreto:"Enquanto o palpite for diferente do secreto". O != é "diferente de". Se a pessoa acertar de primeira, o laço nem roda.
if palpite < secreto:Palpite menor que o secreto: a resposta está mais para cima.
palpite = int(input(…)) (dentro do laço)O próximo palpite. É ele que muda a condição; sem esta linha, o laço repetiria a mesma dica para sempre (veja o cenário abaixo).
print(f"Acertou! …")Fora do laço: só chega aqui quando palpite != secreto ficar falso, ou seja, quando acertar.
$ python3 adivinhacao.py
Pensei num número de 1 a 100. Tente adivinhar!
Seu palpite: 50
Mais alto!
Seu palpite: 75
Mais alto!
Seu palpite: 88
Mais baixo!
Seu palpite: 81
Mais baixo!
Seu palpite: 78
Mais alto!
Seu palpite: 79
Mais alto!
Seu palpite: 80
Acertou! O número era 80.
A estratégia da Ana: sempre o meio

Repare nos palpites: 50 (o meio de 1 a 100), depois 75 (o meio de 51 a 100), depois 88… A cada dica, ela chuta o meio do que sobrou, e a quantidade de números possíveis cai pela metade: 100, 50, 25, 12, 6, 3, 1. Com essa estratégia (em programação ela se chama busca binária), 7 palpites sempre bastam para 100 números, porque 2 elevado a 7 é 128, mais que 100. É por isso que a versão 3 vai dar 7 tentativas.

Esquecer o int(): TypeError

Sem o int() nos dois input(), o primeiro palpite já derruba o jogo:

$ python3 adivinhacao.py
Pensei num número de 1 a 100. Tente adivinhar!
Seu palpite: 50
Traceback (most recent call last):
  File "/home/ana/projetos/adivinhacao/adivinhacao.py", line 8, in <module>
    if palpite < secreto:
       ^^^^^^^^^^^^^^^^^
TypeError: '<' not supported between instances of 'str' and 'int'

TypeError: '<' not supported between instances of 'str' and 'int' = "erro de tipo: o < não funciona entre um texto (str) e um inteiro (int)". Na versão 1, a comparação == entre texto e número só dava False, calada; o < não aceita a mistura e para o programa. Pelo menos aqui o erro aparece. Repare que o while palpite != secreto da linha 7 passou sem erro (e deu verdadeiro, porque "50" é diferente de qualquer número): o problema só apareceu na linha 8. Como consertar: int(input(…)).

Esquecer o novo palpite dentro do laço

Se a última linha de dentro do while (o segundo palpite = int(input(…))) sumir, o palpite nunca muda. A condição palpite != secreto continua verdadeira para sempre, e o programa fica escrevendo "Mais alto!" sem parar, sem nunca mais perguntar nada. É um laço infinito. Para interromper, aperte Ctrl+C (o Python mostra um KeyboardInterrupt). Regra prática: dentro de um while, sempre tem de haver alguma linha que mude a condição.

Missão (versão 2): o programa dá a dica, mas só aceita um palpite. Troque o if por um while palpite != secreto: que dê a dica e peça outro palpite, e deixe o Acertou! para depois do laço. A entrada da missão é 50, 75, 88, 82 (o secreto é 82).

import random

random.seed(42)  # só para a missão: o número secreto é sempre 82
secreto = random.randint(1, 100)
print("Pensei num número de 1 a 100. Tente adivinhar!")

palpite = int(input("Seu palpite: "))
if palpite == secreto:
    print("Acertou!")
elif palpite < secreto:
    print("Mais alto!")
else:
    print("Mais baixo!")
import random

random.seed(42)  # só para a missão: o número secreto é sempre 82
secreto = random.randint(1, 100)
print("Pensei num número de 1 a 100. Tente adivinhar!")

palpite = int(input("Seu palpite: "))
while palpite != secreto:
    if palpite < secreto:
        print("Mais alto!")
    else:
        print("Mais baixo!")
    palpite = int(input("Seu palpite: "))

print(f"Acertou! O número era {secreto}.")

Versão 3 · Tentativas contadas e limitadas

Com tentativas infinitas, ninguém perde. A versão 3 dá 7 tentativas e mostra em qual a pessoa está. Quando já se sabe quantas vezes no máximo algo vai se repetir, o laço natural é o for com range().

import random

MAXIMO = 7
secreto = random.randint(1, 100)
print(f"Pensei num número de 1 a 100. Você tem {MAXIMO} tentativas.")

for tentativa in range(1, MAXIMO + 1):
    palpite = int(input(f"Tentativa {tentativa}/{MAXIMO}: "))
    if palpite == secreto:
        print(f"Acertou em {tentativa} tentativa(s)!")
        break
    elif palpite < secreto:
        print("Mais alto!")
    else:
        print("Mais baixo!")
else:
    print(f"Suas tentativas acabaram. O número era {secreto}.")
MAXIMO = 7
O limite num lugar só, em MAIÚSCULAS (o costume para um valor fixo). Para mudar a dificuldade, basta mudar esta linha.
for tentativa in range(1, MAXIMO + 1):
A variável tentativa vale 1, 2, 3… até 7. O range(1, 8) não inclui o 8: por isso o + 1 (veja range()).
f"Tentativa {tentativa}/{MAXIMO}: "
A pergunta mostra o número da tentativa: Tentativa 3/7:.
break
Acertou: sai do for na hora, sem gastar as tentativas que sobraram.
else: (alinhado com o for)
O else de um laço roda só se o laço terminar sem break, ou seja, se as 7 tentativas passaram sem acerto. É exatamente o "perdeu". Repare na indentação: ele está na mesma coluna do for, e não do if. Mais em else nos Laços.

Uma vitória e uma derrota no terminal da Ana. Na segunda, ela tentou ir de 10 em 10:

$ python3 adivinhacao.py
Pensei num número de 1 a 100. Você tem 7 tentativas.
Tentativa 1/7: 50
Mais baixo!
Tentativa 2/7: 25
Mais baixo!
Tentativa 3/7: 12
Mais baixo!
Tentativa 4/7: 6
Mais alto!
Tentativa 5/7: 9
Mais alto!
Tentativa 6/7: 10
Mais alto!
Tentativa 7/7: 11
Acertou em 7 tentativa(s)!                     « por pouco
$ python3 adivinhacao.py
Pensei num número de 1 a 100. Você tem 7 tentativas.
Tentativa 1/7: 10
Mais alto!
Tentativa 2/7: 20
Mais alto!
Tentativa 3/7: 30
Mais alto!
Tentativa 4/7: 40
Mais alto!
Tentativa 5/7: 50
Mais alto!
Tentativa 6/7: 60
Mais alto!
Tentativa 7/7: 70
Mais baixo!
Suas tentativas acabaram. O número era 67.     « o else do for
while ou for?

A versão 2 não sabia quantas voltas ia dar ("até acertar"): while. A versão 3 sabe o máximo ("no máximo 7"): for com range, e ainda ganha o contador tentativa de graça. Dá para fazer a versão 3 com while também, com um contador manual; compare em Formas diferentes.

Palpite que não é número: ValueError
$ python3 adivinhacao.py
Pensei num número de 1 a 100. Você tem 7 tentativas.
Tentativa 1/7: sete
Traceback (most recent call last):
  File "/home/ana/projetos/adivinhacao/adivinhacao.py", line 8, in <module>
    palpite = int(input(f"Tentativa {tentativa}/{MAXIMO}: "))
ValueError: invalid literal for int() with base 10: 'sete'

A mensagem do int() é diferente da do float(): "invalid literal for int() with base 10: 'sete'" = "texto inválido para o int() na base 10: 'sete'". A base 10 é a nossa, de algarismos de 0 a 9. O jogo inteiro acabou por causa de um palpite digitado por extenso. A versão 4 conserta.

Missão (versão 3): quando as 7 tentativas acabam sem acerto, o programa termina calado. Acrescente o else do for (alinhado com o for, não com o if) mostrando Suas tentativas acabaram. O número era 82. (use {secreto}). A entrada da missão vai de 10 em 10, de 10 a 70, e o secreto é 82: ela perde.

import random

random.seed(42)  # só para a missão: o número secreto é sempre 82
MAXIMO = 7
secreto = random.randint(1, 100)
print(f"Pensei num número de 1 a 100. Você tem {MAXIMO} tentativas.")

for tentativa in range(1, MAXIMO + 1):
    palpite = int(input(f"Tentativa {tentativa}/{MAXIMO}: "))
    if palpite == secreto:
        print(f"Acertou em {tentativa} tentativa(s)!")
        break
    elif palpite < secreto:
        print("Mais alto!")
    else:
        print("Mais baixo!")
import random

random.seed(42)  # só para a missão: o número secreto é sempre 82
MAXIMO = 7
secreto = random.randint(1, 100)
print(f"Pensei num número de 1 a 100. Você tem {MAXIMO} tentativas.")

for tentativa in range(1, MAXIMO + 1):
    palpite = int(input(f"Tentativa {tentativa}/{MAXIMO}: "))
    if palpite == secreto:
        print(f"Acertou em {tentativa} tentativa(s)!")
        break
    elif palpite < secreto:
        print("Mais alto!")
    else:
        print("Mais baixo!")
else:
    print(f"Suas tentativas acabaram. O número era {secreto}.")

Versão 4 · Palpite validado

A leitura do palpite vira uma função, ler_palpite, que só devolve um palpite quando ele é um inteiro e está entre 1 e 100. Palpite inválido não gasta tentativa: a função simplesmente pergunta de novo.

import random

MENOR = 1
MAIOR = 100
MAXIMO = 7


def ler_palpite(pergunta):
    """Pergunta até a pessoa digitar um inteiro entre MENOR e MAIOR."""
    while True:
        texto = input(pergunta).strip()
        try:
            palpite = int(texto)
        except ValueError:
            print(f'"{texto}" não é um número inteiro.')
            continue
        if MENOR <= palpite <= MAIOR:
            return palpite
        print(f"O número é de {MENOR} a {MAIOR}.")


secreto = random.randint(MENOR, MAIOR)
print(f"Pensei num número de {MENOR} a {MAIOR}. Você tem {MAXIMO} tentativas.")

for tentativa in range(1, MAXIMO + 1):
    palpite = ler_palpite(f"Tentativa {tentativa}/{MAXIMO}: ")
    if palpite == secreto:
        print(f"Acertou em {tentativa} tentativa(s)!")
        break
    elif palpite < secreto:
        print("Mais alto!")
    else:
        print("Mais baixo!")
else:
    print(f"Suas tentativas acabaram. O número era {secreto}.")
MENOR = 1 e MAIOR = 100
Os limites do sorteio também viraram constantes: o randint, a mensagem e a validação usam os mesmos valores. Para jogar de 1 a 1000, muda-se um lugar só.
try: palpite = int(texto)
Tenta converter. Se der ValueError, o Python pula para o except.
continue
"Continuar": volta direto para o começo do while, pulando o resto da volta. Sem ele, o programa seguiria para o if com uma variável palpite que não foi criada (veja break e continue).
if MENOR <= palpite <= MAIOR:
Uma comparação "encadeada": 1 <= palpite <= 100 quer dizer "palpite maior ou igual a 1 e menor ou igual a 100", como na matemática. Poucas linguagens deixam escrever assim.
return palpite
Palpite bom: devolve e sai da função (e do while True).
print(f"O número é de …")
Só chega aqui um inteiro fora da faixa. Depois do aviso, o while True pergunta de novo.
$ python3 adivinhacao.py
Pensei num número de 1 a 100. Você tem 7 tentativas.
Tentativa 1/7: abc
"abc" não é um número inteiro.
Tentativa 1/7: 150
O número é de 1 a 100.
Tentativa 1/7: 7.5
"7.5" não é um número inteiro.                 « int() não aceita casas decimais
Tentativa 1/7: 50
Mais alto!
Tentativa 2/7: 75
Mais baixo!
Tentativa 3/7: 62
Mais baixo!
Tentativa 4/7: 56
Mais baixo!
Tentativa 5/7: 53
Mais alto!
Tentativa 6/7: 54
Acertou em 6 tentativa(s)!

Os três palpites inválidos ficaram todos na "Tentativa 1/7": nenhum foi contado. O for só avança quando ler_palpite devolve um palpite válido.

Missão (versão 4): a função ler_palpite ainda aceita qualquer coisa, e o abc da entrada da missão (abc, 150, 82) derruba o jogo. Escreva o corpo da função como na versão 4: while True, try/except ValueError com continue, e o teste MENOR <= palpite <= MAIOR. O resultado deve ser Acertou em 1 tentativa(s)!, porque os dois palpites inválidos não contam.

import random

random.seed(42)  # só para a missão: o número secreto é sempre 82
MENOR = 1
MAIOR = 100
MAXIMO = 7


def ler_palpite(pergunta):
    """Pergunta até a pessoa digitar um inteiro entre MENOR e MAIOR."""
    return int(input(pergunta))


secreto = random.randint(MENOR, MAIOR)
print(f"Pensei num número de {MENOR} a {MAIOR}. Você tem {MAXIMO} tentativas.")

for tentativa in range(1, MAXIMO + 1):
    palpite = ler_palpite(f"Tentativa {tentativa}/{MAXIMO}: ")
    if palpite == secreto:
        print(f"Acertou em {tentativa} tentativa(s)!")
        break
    elif palpite < secreto:
        print("Mais alto!")
    else:
        print("Mais baixo!")
else:
    print(f"Suas tentativas acabaram. O número era {secreto}.")
import random

random.seed(42)  # só para a missão: o número secreto é sempre 82
MENOR = 1
MAIOR = 100
MAXIMO = 7


def ler_palpite(pergunta):
    """Pergunta até a pessoa digitar um inteiro entre MENOR e MAIOR."""
    while True:
        texto = input(pergunta).strip()
        try:
            palpite = int(texto)
        except ValueError:
            print(f'"{texto}" não é um número inteiro.')
            continue
        if MENOR <= palpite <= MAIOR:
            return palpite
        print(f"O número é de {MENOR} a {MAIOR}.")


secreto = random.randint(MENOR, MAIOR)
print(f"Pensei num número de {MENOR} a {MAIOR}. Você tem {MAXIMO} tentativas.")

for tentativa in range(1, MAXIMO + 1):
    palpite = ler_palpite(f"Tentativa {tentativa}/{MAXIMO}: ")
    if palpite == secreto:
        print(f"Acertou em {tentativa} tentativa(s)!")
        break
    elif palpite < secreto:
        print("Mais alto!")
    else:
        print("Mais baixo!")
else:
    print(f"Suas tentativas acabaram. O número era {secreto}.")

Versão 5 · Várias partidas e recorde

Para jogar de novo sem rodar o programa outra vez, a partida inteira vira uma função, jogar(), e o programa principal chama essa função dentro de um while True. A função devolve o resultado da partida: quantas tentativas a pessoa usou, ou None se ela perdeu. Com isso, o programa principal guarda o recorde: o menor número de tentativas numa vitória.

import random

MENOR = 1
MAIOR = 100
MAXIMO = 7


def ler_palpite(pergunta):
    """Pergunta até a pessoa digitar um inteiro entre MENOR e MAIOR."""
    while True:
        texto = input(pergunta).strip()
        try:
            palpite = int(texto)
        except ValueError:
            print(f'"{texto}" não é um número inteiro.')
            continue
        if MENOR <= palpite <= MAIOR:
            return palpite
        print(f"O número é de {MENOR} a {MAIOR}.")


def jogar():
    """Uma partida. Devolve quantas tentativas a pessoa usou, ou None se ela perdeu."""
    secreto = random.randint(MENOR, MAIOR)
    print(f"Pensei num número de {MENOR} a {MAIOR}. Você tem {MAXIMO} tentativas.")
    for tentativa in range(1, MAXIMO + 1):
        palpite = ler_palpite(f"Tentativa {tentativa}/{MAXIMO}: ")
        if palpite == secreto:
            print(f"Acertou em {tentativa} tentativa(s)!")
            return tentativa
        if palpite < secreto:
            print("Mais alto!")
        else:
            print("Mais baixo!")
    print(f"Suas tentativas acabaram. O número era {secreto}.")
    return None


print("=== Jogo de Adivinhação ===")
recorde = None

while True:
    resultado = jogar()
    if resultado is not None and (recorde is None or resultado < recorde):
        recorde = resultado
        print("Novo recorde!")
    if recorde is not None:
        print(f"Seu recorde: {recorde} tentativa(s).")

    if input("Jogar de novo? (s/n): ").strip().lower() != "s":
        break

print("Até a próxima!")
PeçaO que mudou
def jogar():O que era o programa da versão 4 (sorteio, mensagem e for) foi para dentro da função. A cada chamada, um sorteio novo.
return tentativaNo lugar do break: o return sai do for e da função de uma vez, levando o número de tentativas.
print(…acabaram…) e return NoneNo lugar do else do for: se o laço terminou, é porque ninguém deu return lá dentro, ou seja, perdeu. O return None deixa isso explícito (uma função sem return já devolveria None, mas escrito fica mais claro).
recorde = NoneAntes da primeira partida, ainda não há recorde: None é o "nada ainda" (veja O Valor None).
resultado is not None and (recorde is None or resultado < recorde)"Ganhou, e (é o primeiro recorde ou é melhor que o antigo)". Os parênteses importam: sem eles, o and seria feito antes do or (veja Precedência).
if input(…).strip().lower() != "s":Pergunta e decide na mesma linha, sem guardar a resposta numa variável, porque ela só é usada ali.
$ python3 adivinhacao.py
=== Jogo de Adivinhação ===
Pensei num número de 1 a 100. Você tem 7 tentativas.
Tentativa 1/7: 50
Mais alto!
Tentativa 2/7: 75
Mais baixo!
Tentativa 3/7: 62
Mais alto!
Tentativa 4/7: 68
Mais baixo!
Tentativa 5/7: 65
Mais baixo!
Tentativa 6/7: 63
Acertou em 6 tentativa(s)!
Novo recorde!
Seu recorde: 6 tentativa(s).
Jogar de novo? (s/n): s
Pensei num número de 1 a 100. Você tem 7 tentativas.
Tentativa 1/7: 50
Mais baixo!
Tentativa 2/7: 25
Mais baixo!
Tentativa 3/7: 12
Mais baixo!
Tentativa 4/7: 6
Mais alto!
Tentativa 5/7: 9
Mais baixo!
Tentativa 6/7: 7
Mais alto!
Tentativa 7/7: 8
Acertou em 7 tentativa(s)!
Seu recorde: 6 tentativa(s).
Jogar de novo? (s/n): n
Até a próxima!

Na primeira partida, 6 tentativas: como ainda não havia recorde, recorde is None deu verdadeiro, e veio o "Novo recorde!". Na segunda, 7 tentativas: 7 < 6 é falso, e o recorde continuou 6.

Missão (versão 5): o jogo já repete as partidas, mas nunca atualiza o recorde. No lugar do comentário, escreva o if que guarda o resultado em recorde (e mostra Novo recorde!) quando a pessoa ganhou e o resultado é o primeiro ou é menor que o recorde. Com a semente 42, a primeira partida tem o secreto 82 (a entrada acerta em 4) e a segunda tem o 15 (a entrada acerta em 1): devem aparecer Seu recorde: 4 tentativa(s). e depois Seu recorde: 1 tentativa(s).

import random

random.seed(42)  # só para a missão: os secretos são 82 e depois 15
MENOR = 1
MAIOR = 100
MAXIMO = 7


def ler_palpite(pergunta):
    """Pergunta até a pessoa digitar um inteiro entre MENOR e MAIOR."""
    while True:
        texto = input(pergunta).strip()
        try:
            palpite = int(texto)
        except ValueError:
            print(f'"{texto}" não é um número inteiro.')
            continue
        if MENOR <= palpite <= MAIOR:
            return palpite
        print(f"O número é de {MENOR} a {MAIOR}.")


def jogar():
    """Uma partida. Devolve quantas tentativas a pessoa usou, ou None se ela perdeu."""
    secreto = random.randint(MENOR, MAIOR)
    print(f"Pensei num número de {MENOR} a {MAIOR}. Você tem {MAXIMO} tentativas.")
    for tentativa in range(1, MAXIMO + 1):
        palpite = ler_palpite(f"Tentativa {tentativa}/{MAXIMO}: ")
        if palpite == secreto:
            print(f"Acertou em {tentativa} tentativa(s)!")
            return tentativa
        if palpite < secreto:
            print("Mais alto!")
        else:
            print("Mais baixo!")
    print(f"Suas tentativas acabaram. O número era {secreto}.")
    return None


print("=== Jogo de Adivinhação ===")
recorde = None

while True:
    resultado = jogar()
    # atualize o recorde aqui

    if recorde is not None:
        print(f"Seu recorde: {recorde} tentativa(s).")

    if input("Jogar de novo? (s/n): ").strip().lower() != "s":
        break

print("Até a próxima!")
import random

random.seed(42)  # só para a missão: os secretos são 82 e depois 15
MENOR = 1
MAIOR = 100
MAXIMO = 7


def ler_palpite(pergunta):
    """Pergunta até a pessoa digitar um inteiro entre MENOR e MAIOR."""
    while True:
        texto = input(pergunta).strip()
        try:
            palpite = int(texto)
        except ValueError:
            print(f'"{texto}" não é um número inteiro.')
            continue
        if MENOR <= palpite <= MAIOR:
            return palpite
        print(f"O número é de {MENOR} a {MAIOR}.")


def jogar():
    """Uma partida. Devolve quantas tentativas a pessoa usou, ou None se ela perdeu."""
    secreto = random.randint(MENOR, MAIOR)
    print(f"Pensei num número de {MENOR} a {MAIOR}. Você tem {MAXIMO} tentativas.")
    for tentativa in range(1, MAXIMO + 1):
        palpite = ler_palpite(f"Tentativa {tentativa}/{MAXIMO}: ")
        if palpite == secreto:
            print(f"Acertou em {tentativa} tentativa(s)!")
            return tentativa
        if palpite < secreto:
            print("Mais alto!")
        else:
            print("Mais baixo!")
    print(f"Suas tentativas acabaram. O número era {secreto}.")
    return None


print("=== Jogo de Adivinhação ===")
recorde = None

while True:
    resultado = jogar()
    if resultado is not None and (recorde is None or resultado < recorde):
        recorde = resultado
        print("Novo recorde!")
    if recorde is not None:
        print(f"Seu recorde: {recorde} tentativa(s).")

    if input("Jogar de novo? (s/n): ").strip().lower() != "s":
        break

print("Até a próxima!")

Formas diferentes de fazer

Contar as tentativas: for ou while

A versão 3 usou for com break e else. O mesmo jogo com while precisa de um contador feito à mão (abaixo, só o trecho do laço):

tentativa = 1
acertou = False
while tentativa <= MAXIMO and not acertou:
    palpite = int(input(f"Tentativa {tentativa}/{MAXIMO}: "))
    if palpite == secreto:
        acertou = True
    # … as dicas …
    tentativa += 1

Funciona, mas há mais coisas para lembrar: criar o contador, somar 1 no fim de cada volta (esquecer o tentativa += 1 dá um laço infinito) e criar uma variável acertou só para sair. O for faz a contagem sozinho.

Sortear o número

$ python3
Python 3.14.4 (main, Aug 20 2026, 10:41:58) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import random
>>> random.seed(42)
>>> random.randint(1, 100)
82
>>> random.seed(42)
>>> random.randrange(1, 101)
82
>>> exit()

O randrange(1, 101) funciona como o range: o fim (101) fica de fora. Com a mesma semente, ele dá o mesmo 82 que o randint(1, 100), porque, por dentro, o randint(a, b) chama o randrange(a, b + 1).

FormaQuando usar
for tentativa in range(1, MAXIMO + 1) com break/elseNúmero máximo de voltas conhecido. O contador vem pronto.
while com contadorQuando a condição de parar é mais complicada que "no máximo N vezes". Cuidado com o contador.
while palpite != secretoRepetir até acontecer algo, sem limite (versão 2).
random.randint(1, 100)Sortear um inteiro com os dois extremos incluídos. O mais fácil de ler.
random.randrange(1, 101)Mesma coisa, no estilo do range (o fim fica de fora). Aceita um passo: randrange(0, 101, 10) sorteia 0, 10, 20…

Ideias para continuar

  • Níveis de dificuldade: antes de começar, pergunte "fácil, médio ou difícil" e mude MAIOR e MAXIMO (1 a 10 com 4 tentativas, 1 a 100 com 7, 1 a 1000 com 10).
  • Avise quando a pessoa repetir um palpite que já deu (guarde os palpites numa lista).
  • Dica de "quente" e "frio": se a diferença entre o palpite e o secreto for menor que 5, diga "Está quente!" (use abs(), veja Funções Embutidas).

Referência rápida do projeto

EscritaPara que serviu
import randomTrazer o módulo do sorteio
random.randint(1, 100)Sortear um inteiro de 1 a 100 (os dois incluídos)
random.seed(42)Fixar a semente: o sorteio passa a dar sempre a mesma sequência (para testar)
while palpite != secreto:Repetir até acertar
for tentativa in range(1, MAXIMO + 1):Repetir no máximo MAXIMO vezes, contando
break / else: do laçoSair ao acertar / fazer algo só se o laço terminou sem break
continueVoltar ao começo do laço (palpite inválido)
MENOR <= palpite <= MAIORConferir se está na faixa
return tentativa / return NoneA partida devolve o resultado
SintomaCausa provável
Digitou o número certo e o jogo disse "Errou!"Faltou o int(): o texto "82" não é igual ao número 82
TypeError: '<' not supported between instances of 'str' and 'int'Faltou o int() e o programa comparou texto com número
NameError: name 'random' is not defined. Did you forget to import 'random'?Faltou o import random
AttributeError: module 'random' has no attribute 'randint' (consider renaming …)Há um arquivo seu chamado random.py na pasta
ValueError: invalid literal for int() with base 10: 'sete'Palpite que não é inteiro, sem try/except
A mesma dica aparece sem pararLaço infinito: faltou pedir o novo palpite dentro do while
As tentativas acabam e nada apareceFaltou o else do for (ou ele está alinhado com o if)

Exercícios

1. O sorteio

Complete para sortear um número de 1 a 6, como um dado:

lado = random.(1, 6)

2. O range das tentativas

Complete para a variável tentativa valer 1, 2, 3, 4 e 5:

for tentativa in range(1, ):

3. Pular o resto da volta

Complete a palavra que volta para o começo do laço depois de um palpite inválido:

except ValueError:
    print("Não é um número.")
    

4. Quando roda o else que está alinhado com o for?

5. Para que servem as missões começarem com random.seed(42)?

6. A Ana salvou um teste como random.py na pasta do jogo, e o jogo passou a dar AttributeError. Por quê?


Resumo

  • import random e random.randint(1, 100) sorteiam um inteiro de 1 a 100, com os dois extremos.
  • random.seed(42) fixa a semente: a sequência sorteada passa a ser sempre a mesma. Ótimo para testar; no jogo de verdade, sem semente.
  • O texto "82" não é igual ao número 82: converta o palpite com int().
  • while repete "até acontecer"; for com range repete "no máximo N vezes" e já conta as voltas.
  • O else de um laço roda só quando o laço termina sem break: é o "perdeu" do jogo.
  • try/except com continue pede de novo sem gastar tentativa; MENOR <= x <= MAIOR confere a faixa.
  • Uma função que devolve o resultado (return tentativa ou None) deixa o programa principal cuidar do recorde.
  • Nunca dê a um arquivo seu o nome de um módulo do Python (random.py).