Program Arcade Games
With Python And Pygame

Chapter 4: Jogos de adivinhação com números aleatórios e Loops (laços)

O próximo passo antes de iniciar a criar gráficos é aprender o que são estruturas de laços de repetição loops. Muitos jogos tem laços de repetição: “loops.” Eles servem para repetir um mesmo bloco de código incontáveis número de vezes. Por exemplo, o jogo de adivinhação de número abaixo repete em um laço (loop) cada reposta que o usuário dá:

Video: The for loop
Oi! Eu pensei em um número qualquer entre 1 e 100.
--- Attempt 1
Responda qual foi o número que eu pensei: 50
Muito alto.
--- Attempt 2
Responda qual foi o número que eu pensei: 25
Muito alto.
--- Attempt 3
Responda qual foi o número que eu pensei: 17
Muito alto.
--- Attempt 4
Responda qual foi o número que eu pensei: 9
Muito baixo.
--- Attempt 5
Responda qual foi o número que eu pensei: 14
Muito baixo.
--- Attempt 6
Responda qual foi o número que eu pensei: 12
Muito alto.
--- Attempt 7
Responda qual foi o número que eu pensei: 10
Muito baixo.
Ha Ha, você completou suas tentativas. O número era 11.

Espere, o que isto tem a ver com gráficos e vídeo-games? Muito. Cada frame que é mostrado num jogo é exibido quadro a quadro em umm laço de repetição loop. Você deve se familiarizar com a estatistica de quadros por segundos (FPS) das iniciais de frames-per-second em inglês. FPS representa o número de vezes que o computador atualiza a tela a cada segundo. Quanto maior a taxa, mais suave é o jogo. (embora passar um FPS com uma taxa de 60 seja mais rápido do que qualquer tela possa atualizar, porque não haverá muitos pontos para passar.) A figura 4.1 mostra o jogo Eve Online e um gráfico mostrando quantos quadros (frames) por segundo o computador é capaz de mostrar.

fig.fps
Figure 4.1: FPS in video games

O laço (loop) num jogo como esse, funciona como o fluxograma da figura 4.2. Apesar das complexidades desse jogo, o interioir do laço (loop) e similar ao programa da calculadora que foi feito no capitulo um. Pega a entrada do usuario. Faz os cáuculos. Exibe o resultado. Num video-game, nós tentaremos repetir isto em cima da faixa de 60 vezes por segundo.

fig.game_loop
Figure 4.2: Game loop

Pode haver laços dentro de outros laços, isto é, Um (loop de loops). de uma olhada na caixa “Draw Everything”, veja a figura 4.2. Essa sequencia de código percorre os laços (loops) e desenham cada objeto desse jogo. Um laço (loop), está dentro de um outro longo laço que desenha cada quadro do jogo, como pode ser visto na figura 4.3.

fig.draw_everything
Figure 4.3: Draw everything loop

Existem dois tipos principais de laços de repetição (loops) em Python, laço for e laço while. Se você quer repetir um certo número de vezes, use um laço for. Se você quiser repetir até que aconteça algo, (tipo, o usuário clicar no botão sair) então use um laço while.

Por exemplo, um laço for pode ser usado para imprimir todos os registros de estudantes desde que o computador saiba quantos estudantes existem gravados. Um laço while deve ser usado para checar se o usuário usou algum botão do mouse, uma vez que o computador não tem ideia de quanto tempo vai precisar esperar.

4.1 For Loops

No exemplo abaixo um laço for executa um comando print 5 vezes. Ele facilmente poderia executar isso por 100 ou 1.000.000 de vezes apenas mudando o valor de 5 que está atribuido para o laço por outro valor que desejar. Note a similaridade de escrever o comando para o laço for com a forma que usamos para escrever uma declaração se if. Ambos terminam com dois pontos no final e ambos usam tabulação para especificar que linhas serão afetadas pela declaração.

for i in range(5):
    print ("Eu não irei mascar chiclete na sala de aulas.")
Output:
Eu não irei mascar chiclete na sala de aulas.
Eu não irei mascar chiclete na sala de aulas.
Eu não irei mascar chiclete na sala de aulas.
Eu não irei mascar chiclete na sala de aulas.
Eu não irei mascar chiclete na sala de aulas.

O i na linha 1 é a variável que mantém o controle de quantas vezes o programa deve percorrer o laço (loop). Esta nova variável pode ser chamada de qualquer nome permitido para variáveis. Os programadores escolhem usar o i como nome de variável porque o i é a inicial de incremento. É esta variável que controla o início e o fim do laço (loop).

A função range controla o número de vezes que o programa deve percorrer o laço (loop). neste caso, cinco vezes.

O código do próximo exemplo irá imprimir “Por favor,” 5 vezes e “Posso ir ao shoping?” apenas uma. “Posso ir ao shoping?” não está tabulada, por isso não faz parte do laço for e somente será impressa quando o laço for tiver terminado.

for i in range(5):
    print ("Por favor,")
print ("Posso ir ao shoping?")
Output:
Por favor,
Por favor,
Por favor,
Por favor,
Por favor,
Posso ir ao shoping?

No código desse exemplo, pegamos o exemplo anterior e tabulamos a linha 3. Isto irá fazer com que o programa imprima “Por favor," e "Posso ir ao shoping?” cinco vezes. Desde que a linha de comando foi tabulada, “Posso ir ao shoping?” agora faz parte do laço for que irá repetir essa linha e a linha do “Por favor," cinco vezes.

for i in range(5):
    print ("Por favor,")
    print ("Posso ir ao shoping?")
Output:
Por favor,
Posso ir ao shoping?
Por favor,
Posso ir ao shoping?
Por favor,
Posso ir ao shoping?
Por favor,
Posso ir ao shoping?
Por favor,
Posso ir ao shoping?

O código abaixo irá imprimir números de 0 a 9. Note que o laço (loop) começa com 0 e não inclui o número 10. Isto é natural de range(10), onde passamos o número 10 como parametro, mas nesse caso, a funçao irá retornar uma lista de 0 a 9.

for i in range(10):
    print(i)
Output:
0
1
2
3
4
5
6
7
8
9

Um programa não precisa usar i para nomear a variável, ela pode ser chamada do que se quiser. Por exemplo, um programador pode usar linhaNumero se ele estiver processando arquivos de texto.

Se um programador precisar usar números de 1 a 10 ao invez de 0 a 9, existem várias maneiras de se fazer isso. A primeira delas é passar dois números como parâmetro para a função range. O primeiro número é o valor inicial e o segundo é o valor final.

Tenha como prática a idéia de que o laço for irá incluir o primeiro número, mas nunca o segundo. O exemplo abaixo especifica uma faixa de (1,11), e os números de 0 a 10 serão impressos. O número 1 é incluido no início, mas nunca termina em 11.

for i in range(1,11):
    print(i)
Output:
1
2
3
4
5
6
7
8
9
10

Uma outra forma de imprimir os números de 1 a 10 seria usando range(10) e fazer a variável i a assumir os valores da faixa de 0 a 9. Para fazer isso, deve-se adicionar 1 à variável i antes de imprimir. Isto funciona, e imprimirá os números de 1 a 10, ambos os metodos funcionam bem.

# Print the numbers 1 to 10.
for i in range(10):
    print(i + 1)

4.1.1 Contando números diferentes de um

Se um programa precisar contar de 2 em 2 ou com algum outro incremental, isso é fácil. Existem duas maneiras de se fazer isso. O primeiro e mais fácil seria prover um terceiro número como parametro para a função range fazendo com que ela conte de 2 em 2. O segundo, é contar normalmente de 1 em 1, mas multiplicar a variável por 2. O código abaixo exemplifica os dois métodos.

# Duas formas de imprimir números pares de 2 até 10
for i in range(2,12,2):
    print(i)

for i in range(5):
    print ((i + 1) * 2)
Output:
2
4
6
8
10
2
4
6
8
10

Também é possível contar para traz até zero passando para a função range um número negativo como parâmetro. No exemplo abaixo, começa com 10 e vai regredindo sem incluir o 0, faz isso usando como incrementador o -1. O pior que pode acontecer ao criar estes tipos de laço (loop) é confundir acidentalmente os números inicial e final. O programacomeça de um valor grande, assim esse é que vai primeiro. O normal para os laços for é passar um valor pequeno como primeiro parâmetro para a função range.

for i in range(10, 0, -1):
    print(i)
Output:
10
9
8
7
6
5
4
3
2
1

Se os números de que um programa precisa percorrer não formam um padrão definido, é possível puxar esses números de uma lista. (Veja uma discussão completa sobre listas no Capítulo 7. Isto é apenas uma prévia do que você pode fazer.)

for i in [2,6,4,2,4,6,7,4]:
    print(i)

This prints:

2
6
4
2
4
6
7
4

4.1.2 Aninhando Laços

Tente descobrir o que o código abaixo irá imprimir. Depois, escreva este código você mesmo em sua maquina e veja se está correto.

# O que vai ser impresso? Porque?
for i in range(3):
    print ("a")
for j in range(3):
	print ("b")
Video: Nesting for loops

O próximo bloco de código é idêntico ao do acima. Ao segundo laço for foi acrecentada uma tabulação, isso faz com que ele agora fique aninhado dentro do primeiro laço. Isto muda significantemente como o código é executado, tente e veja você mesmo.

# O que vai ser impresso? Por que?
for i in range(3):
    print("a")
    for j in range(3):
        print("b")

print("Feito")

Eu não pretendo dizer o que o código retorna, vá você mesmo em um computador e veja.

Video: for loop animation

4.1.3 Keeping a Running Total

Uma operação comum ao se trabalhar com laços (loops) é para manter atualizada uma totalização. O padrão de código para uma “Totalização” como esta é usada muito usada nesse livro. para manter um total de um score em um jogo, toalizar as transações das contas das pessoas, usar a totalização para se obter uma média, etc. Você pode e deve salvar isso nos seus favoritos porque iremos nos referir a ele novamente muitas vezes mais, depois. No código abaixo, o usuário entra 5 numeros e o código totaliza os valores.

total = 0
for i in range(5):
    novoNumero = int(input("Digite um número: " ))
    total += novoNumero
print("O total é: ",total)
Video: Using a loop to keep a running total

Note que a linha 1 cria a variável total e ajusta atribui 0 como seu valor inicial. É fácil a gente se esquecer de inicializar uma variável como 0, só que sem ela, o computador irá reclamar depois quando for passar pela linha 4. Ele não poderá saber como adicionar total a novoNumero porque total não foi incializada de forma nenhuma.

Uma situação comum de confusão sobre isso é usar i como se fosse total ao invez de novoNumero. Lembre-se, nós estamos juntando os valores entrado pelo usuário em um total, não contando o total de vezes que o laço deve executar.

Falando de contadores de laço, nós podemos usar o laços para contar valores para resolver uma operação matemática. Por exemplo:

$s=\sum\limits_{n=1}^{100}n$

Se você não estiver familiarizado com fórmulas matemáticas como a de acima, com esta você deve estar, pois ela é bem simples:

$s=1+2+3+4+5 \ldots 98+99+100$

O código abaixo adiciona todos os números de 1 a 100. Isso demonstra um padrão comum ao totalizar valores dentro de um laço. Usamos aqui um nome distinto para a variável definida para armazenar o total, o nome é soma.

# Qual é o valor da soma?
soma = 0
for i in range(1,101):
    soma = soma + i
print(soma)

Veja aqui uma variação. Pegamos cinco números entrados pelo usuário e contamos o número de vezes que o usuario entrou com zero:

total = 0
for i in range(5):
    newNumber = int(input( "Digite um numero: "))
    if newNumber == 0:
        total += 1
print("Você entrou com ",total," zeros")

Um programador que entende bem o que são laços for aninhados pode facilmente prever o total retornado pela saida do código abaixo.

# Qual é o valor de a?
a = 0
for i in range(10):
    a=a+1
print(a)

# Qual é o valor de a?
a = 0
for i in range(10):
    a = a + 1
for j in range(10):
    a = a + 1
print(a)

# Qual é o valor de a?
a = 0
for i in range(10):
    a = a + 1
    for j in range(10):
        a = a + 1
print(a)

Não vá muito rápido ao fim da seção. Aproveite e tente predizer as saídas do código acima, então, copie ele para um terminal de python e rode ele para ver se você acertou. Se não conseguiu, procure saber o motivo.

4.2 Exemplos de laço (loop) for

Este exemplo mostra as formas mais comuns para o uso de laços for e mostra como eles funcionam.

# Sample Python/Pygame Programs
# Simpson College Computer Science
# http://programarcadegames.com/
# http://simpson.edu/computer-science/

# Print 'Hi' 10 times
for i in range(10):
    print("Hi")

# Print 'Hello' 5 times and 'There' once
for i in range(5):
    print("Hello")
print("There")

# Print 'Hello' 'There' 5 times
for i in range(5):
    print("Hello")
    print("There")

# Print the numbers 0 to 9
for i in range(10):
    print(i)

# Two ways to print the numbers 1 to 10
for i in range(1, 11):
    print(i)

for i in range(10):
    print(i + 1)

# Two ways to print the even numbers 2 to 10
for i in range(2, 12, 2):
    print(i)

for i in range(5):
    print((i + 1) * 2)

# Count down from 10 down to 1 (not zero)
for i in range(10, 0, -1):
    print(i)

# Print numbers out of a list
for i in [2, 6, 4, 2, 4, 6, 7, 4]:
    print(i)

# What does this print? Why?
for i in range(3):
    print("a")
    for j in range(3):
        print("b")

# What is the value of a?
a = 0
for i in range(10):
    a = a + 1
print(a)

# What is the value of a?
a = 0
for i in range(10):
    a = a + 1
for j in range(10):
    a = a + 1
print(a)

# What is the value of a?
a = 0
for i in range(10):
    a = a + 1
    for j in range(10):
        a = a + 1
print(a)

# What is the value of sum?
sum = 0
for i in range(1, 101):
    sum = sum + i

4.3 Laços Enquanto - (while Loops)

Video: The while loop

Um laço (loop) for é usado quando um programa precisa repetir um bloco de código por um numero conhecido de vezes. Um laço while é usado quando o programa precisa de um laço que se repita até que uma condição seja satisfeita.

Curiosamente, um laço while pode ser usado em qualquer lugar que um laço for. Ele pode ser usado até que uma variável de incremento atinja um determinado valor. Porque usariamos um laço for se um laço while pode fazer a mesma coisa? É que um laço for é um laço mais simples de ser usado e codificado. Um laço for é algo como isso:

for i in range(10):
    print(i)

...Pode ser feito com um laço while, que seria algo como isso:

i = 0
while i < 10:
    print(i)
    i = i + 1

Na linha 1 do laço while atribuimos um “sentinela”, ou seja, uma variável que vai ser usada para contar o número de vezes que o laço está sendo executado. Isto acontece automaticamente num laço for, eliminando uma linha de código. A linha 2 contém a chamada real para o laço while. O formato do laço while é bastante similar a uma declaração de se (if). Se passar pela condição, o código dentro do laço irá ser repetido. A linha 4 incrementa o valor da variável. Num laço for isto é feito automaticamente, eliminando outra linha de código. Como se pode ver pelo código, o laço for é mais compacto e fácil de ser lido. Muito embora programas possam fazer tudo usando um laço while.

è muito comum fazer confuzão do laço for com o laço while. O código abaixo mostra um programador que não sabe fazer distinção entre os laços for e while.

while range(10):
    print(i)
Nunca use range com um laço while!

A função range somente funciona com o laço for. Não use ela em um laço while!

4.3.1 Usando Operadores de Incremento

Operadores de incremento foram feitos para serem usados com laços enquanto (while loops). É possível encurtar mais o código:

i = i + 1

Usando como se ve abaixo:

i += 1

No laço while isto pode parecer como isso:

i = 0
while i < 10:
    print(i)
    i += 1

Isto pode ser feito tambem com subtração e multimplicação. Por exemplo:

i *= 2

É o mesmo que isso:

i = i * 2

Veja se você pode dizer o que isso vai imprimir:

i = 1
while i <= 2 ** 32:
    print(i)
    i *= 2

4.3.2 Executando um laço até o usuário querer sair

Uma operação comum para um laço é ele executar até que o usuário solicite um pedido para sair:

quit = "n"
while quit == "n":
    quit = input("Você deseja sair? ")

Existem várias formas para sair de um laço (loop). Usando uma variável booleana para disparar um evento é uma das formas, Aqui segue um exemplo:

done = False
while not done:
    quit = input("Você quer sair? ")
    if quit == "y" :
        done = True;

    attack = input("Será que seu elfo pode atacar o dragão? ")
    if attack == "y":
        print ("Péssima escolha, voce morreu.")
        done = True;

Isto não é perfeito, porque se o usuario dizer que quer sair, o código continuará perguntando se ele(a) quer atacar o dragão. Como consertar isso?

Aqui está um exemplo usando um laço while onde o código repete até que o valor chegue a zero:

value = 0
increment = 0.5
while value < 0.999:
    value += increment
    increment *= 0.5
    print(value)

4.3.3 Problemas comuns com laço while

O proramador quer contar para traz partindo de 10. O que está errado e como resolver isso?

i = 10
while i == 0:
    print (i)
    i -= 1

O que está errado com esse laço que tenta contar de 10 a 0 O que irá acontecer quando rodar? O que pode ser feito para resolver?

i = 1
while i < 10:
    print (i)

4.4 Exemplos de laços (loops) while

Aqui tem um programa que cobre diferentes usos dos laços while que foi nós falamos.

# Sample Python/Pygame Programs
# Simpson College Computer Science
# http://programarcadegames.com/
# http://simpson.edu/computer-science/

# A while loop can be used anywhere a for loop is used:
i = 0
while i < 10:
    print(i)
    i = i + 1

# This is the same as:
for i in range(10):
    print(i)

# It is possible to short hand the code:
# i = i + 1
# With the following:
# i += 1
# This can be done with subtraction, and multiplication as well.
i = 0
while i < 10:
    print(i)
    i += 1

# What would this print?
i = 1
while i <= 2**32:
    print(i)
    i *= 2

# A very common operation is to loop until the user performs
# a request to quit
quit = "n"
while quit == "n":
    quit = input("Do you want to quit? ")

# There may be several ways for a loop to quit. Using a boolean
# to trigger the event is a way of handling that.
done = False
while not done:
    quit = input("Do you want to quit? ")
    if quit == "y":
        done = True

    attack = input("Does your elf attach the dragon? ")
    if attack == "y":
        print("Bad choice, you died.")
        done = True

value = 0
increment = 0.5
while value < 0.999:
    value += increment
    increment *= 0.5
    print(value)

# -- Common problems with while loops --

# The programmer wants to count down from 10
# What is wrong and how to fix it?
i = 10
while i == 0:
    print(i)
    i -= 1

# What is wrong with this loop that tries
# to count to 10? What will happen when it is run?
i = 1
while i < 10:
    print(i)

4.5 Números Randomicos

Números Randomicos são usados em programas cientificos para computadores que envolvem jogos ou simuladores.

4.5.1 A função randrange

Video: Random Numbers

Poe padrão, o Python não conhece como fazer números ramdomicos. É necessário importar o código de uma biblioteca escrita para pytho para poder criar os números ramdomicos. Assim, para usar números ramdomicos, a primeia coisa que deve aparecer no topo de um program é um comando import:

import random

Mesmo com pygame, é importante não criar um arquivo com o mesmo nome de um que está sendo importado. Criar um arquivo chamado ramdom.py irá fazer com que o Python comece por usar esse arquivo ao invez de importar a biblioteca do sistema para criar números ramdomicos.

Depois disso, números randomicos podem ser criados com a função randrange. Por exemplo, este código cria números randomicos de 0 a 49. por padrão o limite inferior é 0.

my_number = random.randrange(50)

O próximo exemplo de código gera números randomicos de 100 a 200. Exatamente como a funççao range. O segundo paramtro especifica a limite superior não inclusive. Portanto, se você precisar de números randomicos inclusive 200, você tem de passar 201 como parametro.

my_number = random.randrange(100,201)

E se você não quiser um número, mas só um item ramdômico? Isto requer uma lista. Listas somente serão vistas no capítulo 7, mas para dar uma mostra do que é selecionar um item randomico fora de uma lista, veja abaixo:

my_list = ["pedra", "papeu", "tesoura"]
random_index = random.randrange(3)
print(my_list[random_index])

4.5.2 A função random

Todos os códigos anteriores geram um número inteiro. Se for preciso um número de ponto flutuante (decimal), um programador vai ter de usar a função random.

O código abaixo gera um número randomico de o a 1 justamente na forma 0,4355991106620656.

my_number = random.random()

Com um pouco de matemática simples, esse número pode ser ajustado. Por exemplo, o código abaixo gera um número aleatório de ponto flutuante entre 10 e 15:

my_number = random.random() * 5 + 10

4.6 Revisão

4.6.1 Teste de Múltiplas Alternativas

Click here for a multiple-choice quiz.

4.6.2 Resposta curtas escritas

Click here for the chapter worksheet.

4.6.3 Lab

Click here for the chapter lab.


You are not logged in. Log in here and track your progress.