Introdução à programação
com Python em um contexto visual


Mais aleatoriedade

Vamos começar revisando a função random() do py5, que produz números pseudo-aleatórios e já vimos anteriormente, em seguida vamos ver um pouco do módulo random de Python que pode ser importado (com a instrução import no início do código), que e tem uma função random() e algumas outras funções relacionadas.

A função random() do py5

Cada vez que chamamos a função random() com um valor de argumento, como em sorteio = random(1); um número entre zero e o argumento passado (servindo de limite superior, mas não incluso) é produzido.

image

Se dois valores forem usados, por exemplo random (-5, 5) serão produzidos números de ponto flutuante (float) entre -5 e 5 (não incluso o 5 final).

O módulo random da biblioteca padrão do Python

No Python a função random() precisa ser importada do módulo random com a a seguinte instrução:

from random import random

image

Mas, se fizermos isso “matamos” o random() do py5. Uma alternativa, se quisermos manter as duas, é escrever:

from random import random as py_random

Dessa forma ao chamar a função escreveremos py_random(), uma outra opção ainda é importar o módulo todo com outro nome.

import random as rnd

E nesse caso usaremos rnd.random(), por exemplo.

Note que a função random() em Python não recebe argumentos (isto é não vai nada dentro dos parênteses) e devolve o equivalente a random(1) no py5, por esse motivo não me parece tão flexível e útil. No entanto, o módulo random de Python oferece outras funções muito simpáticas, quero dizer, interessantes: choice(), sample(), e shuffle().

Produzindo números inteiros com random.randint ou py5.random_int

É comum querermos produzir números pseudo-aleatórios inteiros, vejamos trê maneiras:

Selecionando um único item com choice()

A função choice(colection) devolve um item de uma coleção (tupla, lista, conjunto). Para cada execução um item é escolhido (pseudo-)aleatoriamente.

from random import choice

frutas = ("uva", "jaca", "melancia", "ubu", "pitanga")
sorteio = choice(frutas)  # 'sorteia' fruta da tupla de frutas
print(sorteio)
# Um resultado possível no console:
# jaca

Veja também outro exemplo, mais visual.

from random import choice

cores = [color(200, 0, 0), color(0, 200, 0), color(0, 0, 200)]

def draw():
    c = choice(cores) # sorteia uma cor da lista de cores
    fill(c)
    rect(25, 25, 50, 50)

random_choice

Selecionando uma amostra (sem repetição de itens)

Sample significa amostra, e usamos sample(colection, k) onde k é o tamanho da amostra (e não pode ser maior que tamanho da população) para obter uma lista com k itens.

from random import sample

cores = (color(200, 0, 0),
         color(200, 200, 0),
         color(0, 200, 200),
         color(200, 0, 200),
         color(0, 200, 0),
         color(0, 0, 200))

# uma lista com duas cores
duas_cores = sample(cores, 2)

print(len(duas_cores))  # resultado: 2

Misturando a ordem de uma sequência mutável

Ao executar shuffle(minha_sequencia) fazemos com que minha_sequencia, que, atenção, não pode ser uma sequência vazia, seja reordenada ‘aleatoriamente’.

from random import shuffle

letras = ['A', 'B', 'C', 'D', 'E']
shuffle(letras)
print(letras)
# a cada execução uma ordem diferente:
# ['C', 'B', 'D', 'A', 'E']
# ['D', 'C', 'E', 'B', 'A']
# ...

A coleção precisa ser ordenada e mutável, como uma lista, não pode ser uma tupla, que é imutável, ou um conjunto que não guarda a ordem dos elementos.

Veja um outro exemplo de shuffle(), embaralhando uma lista de tuplas que representam as posições em uma grade. As cores e os números são relativos à ordem dos elementos na lista (0, vermelho) é o primeiro quadrado da lista.

from random import shuffle 

tam = 80

def setup():
    size(400, 400)
    text_align(CENTER, CENTER)
    color_mode(HSB)  # matiz, saturacao, brilho
    frameRate(1)

def draw():
    posicoes = []  # lista vazia
    for y in range(0, height, tam):
        for x in range(0, width, tam): 
            posicoes.append((x, y))  # tupla (x, y)

    shuffle(posicoes)  # Embaralha a lista gerada 

    for i, (x, y) in enumerate(posicoes):  # desenha os quadrados 
        fill(i * 10, 200, 200) # i influencia o matiz
        rect(x, y, tam, tam)
        fill(0)
        text(i, x + tam / 2, y + tam / 2) # escrevendo o números   

random_choice

Sementes dos geradores pseudo-aleatórios (random seed)

Como os números produzidos por random() não são verdadeiramente aleatórios, e sim produzidos por algorítmos geradores determinísticos, é possível fixar um parâmetro inical, conhecido como semente (seed), o que permite reproduzir novamente a mesma sequência de números.

Para fixar o início do gerador de random() no py5 usamos random_seed(numero_inteiro).

random_seeed(numero_inteiro)  # ajusta a semente no py5
s = random(10, 20)  # Função random() do py5

Já para as funções do módulo random do Python usamos a função seed() do módulo random.

from random import random, choice, seed 

seed(numero_inteiro)
c = choice(('A', 'B', 'C'))
r = random() * 100  # random do Python sobrepôs o random do Processing

ou ainda

import random as rnd

rnd.seed(numero_inteiro)
c = rnd.choice(('A', 'B', 'C'))
r = rnd.random() * 100

Um exemplo de uso do random.seed() do Python

Modificando o exemplo anterior com shuffle.

from random import shuffle, seed

tam = 80

def setup():
    size(400, 400)
    text_align(CENTER, CENTER)
    color_mode(HSB)  # matiz, saturacao, brilho

def draw():
    seed(mouse_x)
    posicoes = []  # lista vazia
    for y in range(0, height, tam):
        for x in range(0, width, tam): 
            posicoes.append((x, y))  # tupla (x, y)

    shuffle(posicoes)  # Embaralha a lista gerada 

    for i, (x, y) in enumerate(posicoes):  # desenha os quadrados 
        fill(i * 10, 200, 200) # i influencia o matiz
        rect(x, y, tam, tam)
        fill(0)
        text(i, x + tam / 2, y + tam / 2) # escrevendo o números 

Um exemplo do random_seed() do py5

Neste exemplo abaixo usamos uma semente para manter ‘congelados’ os números gerados por random() entre frames do draw(), mantendo a interatividade de ajuste do ângulo da árvore com o mouse. Quando uma imagem é exportada, o nome do arquivo contém a semente (seed) do gerador de números pseudo-aleatórios.

def setup():
    global seed
    size(500, 500)
    seed = int(random(1000))
    print(seed)

def draw():
    random_seed(seed)
    background(240, 240, 200)
    translate(250, 300)
    galho(60)

def galho(tamanho):  # definição do galho/árvore
    ang = radians(mouse_x)
    reducao = .8
    stroke_weight(tamanho / 10)
    line(0, 0, 0, -tamanho)
    if tamanho > 5:
        push_matrix()
        translate(0, -tamanho)
        rotate(ang)
        galho(tamanho * reducao - random(0, 2))
        rotate(-ang * 2)
        galho(tamanho * reducao - random(0, 2))
        pop_matrix()

def key_pressed():  # executada quando uma tecla for precinada
    if key_code == LEFT:
        seed = seed - 1
    if key_code == RIGHT:
        seed = seed + 1
    if key == ' ':  # barra de espaço precionada, sorteia nova "seed"
        seed = int(random(100000))
        print(seed)
    if key == 's':  # tecla "s" precionada, salva a imagem PNG
        nome_arquivo = 'arvore-s{}-a{}.png'.format(seed, mouse_x % 360)
        save_frame(nome_arquivo)
        print("PNG salvo")

image


Texto e imagens: CC BY-NC-SA 4.0; Código: GNU GPL v3.0 exceto onde explicitamente indicado por questões de compatibilidade.