domingo, 6 de dezembro de 2009

Estruturas de Dados e Abstracção

Regressemos à ideia de estado avançada no problema do Enforcado. Dissemos que o estado era o que andava a ser comunicado entre o programa e o utilizador. Dissemos também que a implementação seria feita com um dicionário. Existem algumas questões interessantes que se colocam. Uma primeira, prende-se com de saber como definir uma camada de abstracção entre a estrutura de dados estado e o resto do mundo. Uma segunda, é a de saber como reagir a uma modificação na implementação do estado, por exemplo, passando de dicionário para lista.


Para responder a estas questões vamos começar por definir uma estrutura de dados, a que chamaremos estado, e que, como referimos será implementada como um dicionário.

# estado como dicionário
# {'palavra':..., 'usadas':..., 'tentativas':...}
# palavra e usadas são listas de caracteres. tentativas é um inteiro não negativo

# Construtor
def cria_estado():
""" Cria estado 'vazio'."""
estado= dict(palavra=[],usadas=[],tentativas=0)
return estado

# Acessores
def get_estado(estado):
# Devolve estado
pal = ' '.join(estado['palavra'])
letras = ', '.join(estado['usadas'])
tenta = estado['tentativas']
return (pal, letra,tenta)

def get_pal(estado):
return ' '.join(estado['palavra'])

def get_letras(estado):
return ' '.join(estado['usadas'])

def get_tentativas(estado):
return estado['tentativas']

# Modificadores
def set_estado(estado, palavra,letras,tentativas):
# Altera estado
estado['palavra'] = list(palavra)
estado['usadas'] = list(letras)
estado['tentativas'] = tentativas
return estado

def set_pal(estado,pal):
estado['palavra'] = list(pal)
return estado

def set_letras(estado,letras):
estado['usadas'] = list(letras)
return estado

def set_tentativas(estado,tenta):
if tenta >= 0:
estado['tentativas'] = tenta
else:
print 'O valor não pode ser negativo. Foi indicado %d.' % tenta
return estado

def add_letra_pal(estado, letra,l_pos):
""" Junta a letra em todas as posições não ocupadas indicadas em l_pos."""
for ind in l_pos:
if estado['palavra'][ind] == '_':
estado['palavra'][ind] = letra
else:
print 'Posição %d já ocupada. Estado inalterado!' % ind
return estado

def add_letra_letras(estado, letra):
""" Junta a letra às letras usadas."""
if not letra in estado['usadas']:
estado['usadas'].append(letra)
else:
print '%s já existente. Estado inalterado!' % letra
return estado

def add_tentativas(estado,tenta):
""" Modifica o valor das tentivas em tenta."""
novo_valor = estado['tentativas'] + tenta
if novo_valor >= 0:
estado['tentativas'] = novo_valor
else:
print 'O valor não pode ser negativo. o Resultado foi %d.' % novo_valor
return estado

# Auxiliares
def mostra_estado(estado):
# Mostra palavra
print 'Palavra Actual: ',' '.join(estado['palavra'])
print
# Mostra letras usadas
print 'Letras já usadas: ',', '.join(estado['usadas'])
print
# Mostra tentativas restantes
print 'Ainda tem as tentativas: ', estado['tentativas']
print

Acabamos de mostrar como uma estrutura de dados se define através de grupos de operações. Um (ou mais) construtor, acessores (para o todo ou a parte dos elementos da estrutura), modificadores (do todo ou da parte da estrutura) e, ainda operações auxiliares. Algumas dessas operações são simétricas: uma consulta (get), a outra altera (set ou add). Com base nelas o nosso código para o enforcado pode ser reescrito.


def hang89():
# inicialização
# --- palavra secreta
palavras = open('/tempo/data/palavras.txt').read().split()
secreta = list(random.choice(palavras))
dicio = seq_to_dict(secreta)
# --- parâmetros
TAMANHO = len(secreta)
LIMITE = limite(TAMANHO)
estado = cria_estado()
estado = set_estado(estado,'_'* TAMANHO,'',LIMITE)
acertou = False
# Entra no jogo
for tentativa in range(LIMITE):
# estado actual
mostra_estado(estado)
# joga
letra = adivinha(estado['usadas'])
# analisa resposta
if letra in dicio:
# --- Acertou na letra!
indices = dicio[letra]
estado = add_letra_pal(estado,letra,indices)
# --- Acertou na palavra??
if fim(secreta,estado['palavra']):
acertou = True
mensagem_sim(secreta)
break
# actualiza estado
esatdo = add_letra_letras(estado,letra)
estado = add_tentativas(estado, -1)
# mensagem final
mensagem_fim(acertou,secreta)

A pergunta natural que se coloca é a de saber o que ganhámos com estas alterações. A resposta liga-se às duas questões iniciais. Imaginemos que decidimos altera a representação de um dicionário para uma lista. Como proceder? Nesta abordagem basta alterar as operações sobre a estrutura de dados estado. Não precisamos alterar nada no código do programa principal! Programar por camadas de abstracção tem elevados ganhos de produtividade.

Sem comentários:

Enviar um comentário