Mais aleatoriedade
Vamos começar revisando a função random()
do Processing, 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 Processing
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.
Se dois valores forem usados, por exemplo random (-5, 5)
serão produzidos números entre -5 e 5 (não incluso). E podemos obter números inteiros convertendo o valor usando int()
, como em sorteio_inteiro = int(random(1, 11))
que ‘sorteia’ com igual probabilidades os números de 1 a 10.
O módulo random
da biblioteca padrão do Python
No Python a funçao random()
precisa ser importada do módulo random
com a a seguinte instrução:
from random import random
Mas, se fizermos isso “matamos” o
random()
do Processing. Uma alternativa, se quisermos manter as duas, é escrever: </br>from random import random as py_random
</br> e aí usaremos o nomepy_random()
, uma outra opção ainda importar o módulo todo com outro nome </br>import random as rnd
</br> e nesse caso usaremosrnd.random()
, por exemplo. </br>
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 Processing, 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 randint()
É comum querermos produzir números pseudo-aleatórios inteiros, em Processing costumamos truncar, convertendo com int()
como em int(random(1, 6))
, mas em Python podemos fazer assim:
from random import randint
for _ in range(100):
valor = randint(1, 5) # 'sorteia' os números 1, 2, 3, 4, 5
print(valor)
# Resultado: produz 100 valores de 1 a 5, INCLUI O 5!!!
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)
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)
textAlign(CENTER, CENTER)
colorMode(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
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 Processing usamos randomSeed(numero_inteiro)
.
randomSeeed(numero_inteiro) # ajusta a semente no Processing
s = random(10, 20) # Função random() do Processing
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)
textAlign(CENTER, CENTER)
colorMode(HSB) # matiz, saturacao, brilho
def draw():
seed(mouseX)
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 randomSeed()
do Processing
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
seed = int(random(1000))
print(seed)
size(500, 500)
def draw():
randomSeed(seed)
background(240, 240, 200)
translate(250, 300)
galho(60)
def galho(tamanho): # definição do galho/árvore
ang = radians(mouseX)
reducao = .8
strokeWeight(tamanho / 10)
line(0, 0, 0, -tamanho)
if tamanho > 5:
pushMatrix()
translate(0, -tamanho)
rotate(ang)
galho(tamanho * reducao - random(0, 2))
rotate(-ang * 2)
galho(tamanho * reducao - random(0, 2))
popMatrix()
def keyPressed(): # executada quando uma tecla for precinada
if keyCode == LEFT:
seed = seed - 1
if keyCode == 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, mouseX % 360)
saveFrame(nome_arquivo)
print("PNG salvo")
Texto e imagens / text and images: CC BY-NC-SA 4.0; Código / code: GNU GPL v3.0 exceto onde explicitamente indicado por questões de compatibilidade.