Personal tools
You are here: Home Blog (português) Solução para a provinha do Google Developer Day 2011 em Python

Solução para a provinha do Google Developer Day 2011 em Python

Posted by Ricardo Bánffy at Aug 22, 2011 03:20 PM |

Esse ano, resolvi tratar com um pouco mais de respeito a prova do GDD. Ano passado, eu resolvi com o prompt do Python aberto, olhando o browser em uma janela e o prompt na outra. Esse ano, as perguntas eram um pouco mais trabalhosas e as strings maiores e isso me fez, em vez disso, escrever um programa. Mais tarde eu coloco o programa no github, mas, por hora, eu transcrevo e comento aqui a minha solução.

A prova apresenta dois textos escritos no idioma Googlon, com os quais vamos trabalhar, e quatro perguntas. Para ajudar (eles são realmente bonzinhos), eles dão as soluções para o primeiro texto, o que ajuda a testar se o código está correto.

Letras foo, bar e preposições

A primeira pergunta explica que algumas letras são chamadas de "letras foo" e todas as demais, "letras bar" e que preposições são palavras de cinco letras que começam com uma letra bar e não contém a letra "q" (é muito provável que a sua prova seja diferente da minha e que elas sejam geradas aleatoriamente - é como eu faria). Para ajudar a resolver, eu escrevi algumas funções

def foo(l):
    return l in "snrbg"

def bar(l):
    return not foo(l)

def preposicao(p):
    return len(p) == 5 and bar(p[-1]) and 'q' not in p

Aí, testar a resposta dada no enunciado é fácil:

>>> palavras_a = texto_a.split(' ')
>>> len(filter(preposicao, palavras_a))
63

Assim como responder a pergunta:

>>> palavras_b= texto_b.split(' ')
>>> len(filter(preposicao, palavras_b))
57

Verbos e verbos em primeira pessoa

A segunda pergunta ensina que verbos são palavras de 6 letras que terminam em uma letra bar. Se ele também começar com uma letra bar, estará em primeira pessoa.

def verbo(p):
    return len(p) >= 6 and bar(p[-1])

def verbo_primeira_pessoa(p):
    return verbo(p) and bar(p[0])

Agora podemos testar nosso código com o dado do enunciado:

>>> len(filter(verbo, palavras_a)) == 216
True
>>> len(filter(verbo_primeira_pessoa, palavras_a)) == 160
True

E descobrir a nossa própria resposta:

>>> len(filter(verbo, palavras_b))
224
>>> len(filter(verbo_primeira_pessoa, palavras_b))
154

No meu caso, eu tinha 224 verbos, dos quais 154 em primeira pessoa.

Vocabulário

Agora o problema pede para criar uma lista com o vocabulário, ordenado segundo o alfabeto googlon. Para isso, eu vou usar o ordenador que já vem embutido nas listas do Python e vou produzir uma função de comparação. Essa função pode ser facilmente plugada em seu próprio sort, se você quiser muito:

def cmp_googlon(p1, p2):
    v = 'jgptzmqskbclrhdfnvwx'
    for l1, l2 in zip(p1, p2):
        if v.index(l1) != v.index(l2):
            return v.index(l1) - v.index(l2)
    return len(p1) - len(p2)

E podemos testar com os dados do enunciado:

>>> vocabulario_a_unsorted = list(set(palavras_a))
>>> ' '.join(sorted(vocabulario_a_unsorted, 
...                        cmp = cmp_googlon)) == vocabulario_a
True

Nota: ao construir um set com as palavras do texto A, eu eliminei as repetições. Como objetos do tipo set não são ordenáveis, eu transformei o conjunto em uma lista. 

Agora podemos encontrar nossa resposta:

>>> vocabulario_b_unsorted = list(set(palavras_b))
>>> vocabulario_b = ' '.join(sorted(vocabulario_b_unsorted, cmp = cmp_googlon))
>>> vocabulario_b
'jgspd jgv jpgzkx jzvjw jmrmlq jmdxx jmntpzq jqw jspk jkc jbb jcphbk jch jcv jlkm...

Números

Agora a prova nos explica que todas as palavras em googlon tem um valor numérico. Em googlon, os números são escritos do dígito menos significativo para o mais significativo e em base 20. Pra isso, precisamos de mais uma função:

def valor_numerico(p):
    v = 'jgptzmqskbclrhdfnvwx'
    vn = 0
    i = 0
    for c in p:
        vn += v.index(c) * (20 ** i)
        i += 1
    return vn

que, podemos testar contra o enunciado:

>>> valor_numerico('blsmgpz') == 262603029
True

Essa parte está certa. Mas a pergunta pede para contarmos os números bonitos. Para eles, números bonitos são divisíveis por 5 e maiores que 492528.

def numero_bonito(p):
    return valor_numerico(p) > 492528 and (valor_numerico(p) % 5 == 0)  

Agora podemos testar:

>>> len(filter(numero_bonito, vocabulario_a.split(' '))) == 75
True

E chegar na nossa resposta:

>>> len(filter(numero_bonito, vocabulario_b.split(' '))) 
71

Conclusão

Foi difícil? Nem um pouco. Se você não conseguiu responder por conta própria, precisa estudar mais. Foi mais trabalhosa do que a do ano passado? Um pouco. Por outro lado, ela tinha informações suficientes para você poder testar suas próprias soluções - e isso ajudou quem teve mais problemas para resolver a prova a aprender alguma coisa. Prova boa é assim - você aprende enquanto faz.

Uma última observação: eu gosto de list comprehensions, mas também gosto de map, filter e reduce. O código fica mais limpo quando eles são bem empregados.