CS50-MCZ

Uma introdução aos empreendimentos intelectuais da Ciência da Computação e da arte da programação.


Lab 6: World Cup


Escreva um programa para executar simulações da Copa do Mundo FIFA.

$ python tournament.py 2018m.csv
Belgium: 20.9% chance of winning
Brazil: 20.3% chance of winning
Portugal: 14.5% chance of winning
Spain: 13.6% chance of winning
Switzerland: 10.5% chance of winning
Argentina: 6.5% chance of winning
England: 3.7% chance of winning
France: 3.3% chance of winning
Denmark: 2.2% chance of winning
Croatia: 2.0% chance of winning
Colombia: 1.8% chance of winning
Sweden: 0.5% chance of winning
Uruguay: 0.1% chance of winning
Mexico: 0.1% chance of winning

Contexto

Na Copa do Mundo de futebol, a fase de mata-mata consiste em 16 equipes. Em cada rodada, cada equipe joga contra outra equipe e as equipes perdedoras são eliminadas. Quando apenas duas equipes permanecem, o vencedor da partida final é o campeão.

No futebol, as equipes recebem classificações FIFA, que são valores numéricos que representam o nível de habilidade relativa de cada equipe. Classificações FIFA mais altas indicam resultados de jogos anteriores melhores e, dado as classificações FIFA de duas equipes, é possível estimar a probabilidade de que uma das equipes vença um jogo com base em suas classificações atuais. As classificações FIFA de duas Copas do Mundo anteriores estão disponíveis como os Classificações FIFA de Homens de maio de 2018 e as Classificações FIFA de Mulheres de março de 2019.

Usando essa informação, podemos simular o torneio inteiro repetidamente simulando rodadas até que reste apenas uma equipe. E se quisermos estimar o quão provável é que qualquer equipe dê a volta por cima no torneio, podemos simular o torneio muitas vezes (por exemplo, 1000 simulações) e contar quantas vezes cada equipe vence um torneio simulado. 1000 simulações podem parecer muitas, mas com o poder de processamento de hoje, podemos realizar essas simulações em questão de milissegundos. No final deste laboratório, vamos experimentar o quão vantajoso pode ser aumentar o número de simulações que executamos, dada a compensação de tempo de execução.

Sua tarefa neste laboratório é fazer exatamente isso usando Python!

Começando

Abra o VS Code.

Comece clicando dentro da janela do terminal e, em seguida, execute cd por si só. Você deve encontrar que seu "prompt" se assemelha ao abaixo.

$

Clique dentro dessa janela de terminal e execute

wget https://cdn.cs50.net/2022/fall/labs/6/world-cup.zip

digite Enter para baixar um arquivo ZIP chamado world-cup.zip em seu espaço de códigos. Tenha cuidado para não ignorar o espaço entre wget e a URL seguinte, ou qualquer outro caractere!

Agora execute

unzip world-cup.zip

para criar uma pasta chamada world-cup. Você não precisa mais do arquivo ZIP, então pode executar

rm world-cup.zip      

e responda com "y" seguido de Enter no prompt para remover o arquivo ZIP que você baixou.

Agora digite

cd world-cup

seguido de Enter para entrar (ou seja, abrir) nesse diretório. Seu prompt agora deve se parecer com o abaixo.

world-cup/ $    

Se tudo foi bem sucedido, você deve executar

ls    

e você deve ver os seguintes arquivos:

answers.txt  2018m.csv  2019w.csv  tournament.py

Se você encontrar algum problema, siga os mesmos passos novamente e veja se consegue determinar onde errou!

Entendendo

Comece dando uma olhada no arquivo 2018m.csv. Este arquivo contém os 16 times na rodada de mata-mata da Copa do Mundo Masculina de 2018 e as classificações de cada time. Observe que o arquivo CSV possui duas colunas, uma chamada team (representando o nome do país do time) e outra chamada rating (representando a classificação do time).

A ordem em que os times estão listados determina quais times jogarão uns contra os outros em cada rodada (na primeira rodada, por exemplo, o Uruguai jogará contra Portugal e a França jogará contra a Argentina; na próxima rodada, o vencedor do jogo Uruguai-Portugal jogará contra o vencedor do jogo França-Argentina). Portanto, certifique-se de não editar a ordem em que os times aparecem neste arquivo!

Em Python, podemos representar cada time como um dicionário que contém dois valores: o nome do time e a classificação. O Uruguai, por exemplo, gostaríamos de representar em Python como {"team": "Uruguai", "rating": 976}.

Em seguida, dê uma olhada no arquivo 2019w.csv, que contém dados formatados da mesma maneira para a Copa do Mundo Feminina de 2019.

Agora, abra o arquivo tournament.py e veja que já escrevemos algum código para você. A variável N na parte superior representa quantas simulações da Copa do Mundo devem ser executadas: neste caso, 1000.

A função simulate_game aceita dois times como entradas (lembre-se de que cada time é um dicionário contendo o nome do time e a classificação do time) e simula um jogo entre eles. Se o primeiro time vencer, a função retorna True; caso contrário, a função retorna False.

A função simulate_round aceita uma lista de times (em uma variável chamada teams) como entrada e simula jogos entre cada par de times. A função retorna uma lista de todos os times que venceram a rodada.

Na função main, observe que primeiro garantimos que len(sys.argv) (o número de argumentos de linha de comando) seja 2. Usaremos argumentos de linha de comando para informar ao Python qual arquivo CSV de times usar para executar a simulação do torneio. Em seguida, definimos uma lista chamada teams (que eventualmente será uma lista de times) e um dicionário chamado counts (que associará nomes de times ao número de vezes que o time venceu um torneio simulado). Agora, ambos estão vazios, portanto, preenchê-los é com você!

Finalmente, no final de main, classificamos os times em ordem decrescente de quantas vezes venceram as simulações (de acordo com counts) e imprimimos a probabilidade estimada de que cada time vença a Copa do Mundo.

O preenchimento de teams e counts e a escrita da função simulate_tournament são deixados para você!

Detalhes de Implementação

Complete a implementação do arquivo tournament.py, de forma que simule uma série de torneios e exiba a probabilidade de cada time vencer.

Primeiramente, na função main, leia os dados dos times a partir do arquivo CSV e armazene-os na memória do programa, adicionando cada time à lista teams.

Em seguida, implemente a função simulate_tournament. Esta função deve aceitar como entrada uma lista de equipes e simular repetidamente as rodadas até restar apenas uma equipe. A função deve retornar o nome dessa equipe.

Finalmente, dentro da função main, execute N simulações de torneio e mantenha o controle de quantas vezes cada equipe vence no dicionário counts.

Dicas

Testando

O seu programa deve se comportar de acordo com os exemplos abaixo. Como as simulações possuem aleatoriedade, é provável que a sua saída não corresponda perfeitamente aos exemplos abaixo.

$ python tournament.py 2018m.csv
Belgium: 20.9% chance of winning
Brazil: 20.3% chance of winning
Portugal: 14.5% chance of winning
Spain: 13.6% chance of winning
Switzerland: 10.5% chance of winning
Argentina: 6.5% chance of winning
England: 3.7% chance of winning
France: 3.3% chance of winning
Denmark: 2.2% chance of winning
Croatia: 2.0% chance of winning
Colombia: 1.8% chance of winning
Sweden: 0.5% chance of winning
Uruguay: 0.1% chance of winning
Mexico: 0.1% chance of winning
$ python tournament.py 2019w.csv
Germany: 17.1% chance of winning
United States: 14.8% chance of winning
England: 14.0% chance of winning
France: 9.2% chance of winning
Canada: 8.5% chance of winning
Japan: 7.1% chance of winning
Australia: 6.8% chance of winning
Netherlands: 5.4% chance of winning
Sweden: 3.9% chance of winning
Italy: 3.0% chance of winning
Norway: 2.9% chance of winning
Brazil: 2.9% chance of winning
Spain: 2.2% chance of winning
China PR: 2.1% chance of winning
Nigeria: 0.1% chance of winning

Número de Simulações

Depois de ter certeza de que seu código está correto, vamos brincar com o valor de N, a constante no topo do nosso arquivo, para ajustar o número de vezes que simulamos o torneio. Mais simulações do torneio nos darão previsões mais precisas (por quê?), ao custo de tempo.

Podemos medir o tempo dos programas, adicionando "time" antes da execução deles na linha de comando. Por exemplo, com o valor de N ajustado para 1000 (o valor padrão), execute

time python tournament.py 2018m.csv

ou

time python tournament.py 2019w.csv

que deve produzir algo como

real    0m0.037s
user    0m0.028s
sys     0m0.008s

embora seus próprios tempos possam variar.

Preste atenção à métrica real, que é o tempo total que levou para tournament.py ser executado. E observe que você é dado o tempo em minutos e segundos, com precisão até milésimos de segundo.

No arquivo answers.txt, mantenha o registro de quanto tempo leva para tournament.py simular...

Cada vez que você ajustar N, registre o tempo real no TODO apropriado em answers.txt usando o mesmo formato 0m0.000s. Após cronometrar cada cenário, responda às duas perguntas de acompanhamento, sobrescrevendo o respectivo TODO:

Veja um arquivo answers.txt formatado corretamente
Times:

10 simulations: 0m0.028s
100 simulations: 0m0.030s
1000 simulations: 0m0.041s
10000 simulations: 0m0.139s
100000 simulations: 0m1.031s
1000000 simulations: 0m11.961s

Questions:

Which predictions, if any, proved incorrect as you increased the number of simulations?:

With a small number of simulations...

Suppose you're charged a fee for each second of compute time your program uses.
After how many simulations would you call the predictions "good enough"?:

It seems like the predictions stabilized after about...

Como Testar Seu Código

Execute o código abaixo para avaliar a correção do seu código usando check50. Mas certifique-se de compilar e testá-lo por si mesmo também!

check50 cs50/labs/2023/x/worldcup

Execute o código abaixo para avaliar o estilo do seu código usando style50.

style50 tournament.py

Como enviar

No seu terminal, execute o seguinte para enviar seu trabalho.

submit50 cs50/labs/2023/x/worldcup