Um sistema de apostas para jogos de futebol é concebido conforme a especificação a seguir:
- deve-se armazenar um dicionário com os nomes das pessoas que apostaram em cada time e o valor individual investido por cada apostador;
- ao final do jogo, todo o montante do time perdedor é distribuído entre os apostadores do time vencedor, na mesma proporção das apostas. Além disso, o valor investido por cada usuário do time vencedor é devolvido.
Considerando esse mecanismo:
a) codifique uma classe ControladorAposta, que conta com um construtor que inicializa dicionários vazios para cada lado das apostas.
b) implemente o método adicionar_aposta, que recebe um nome de usuário (string), o valor da aposta e um lado (1 ou 2). Se não for a primeira vez que esse usuário aposta naquele time, o valor deve ser somado ao das apostas anteriores. Se esse usuário tiver apostado no outro time, o sistema deve negar a operação, retornando False. Analogamente, se a aposta for feita com sucesso, o método deve retornar True.
c) implemente o método definir_resultado recebe o lado vencedor ( 1 ou 2) e retorna um dicionário onde as chaves são nomes de usuários do lado vencedor e os valores são números contendo o saldo final de cada apostador após a definição do resultado. O saldo final de cada apostador vencedor é dado pela seguinte expressão:
onde:
-
é o valor investido por aquele usuário vencedor;
-
é o valor total de apostas no lado vencedor e
-
é o valor total de apostas no lado perdedor.
a) codifique uma classe ControladorAposta, que conta com um construtor que inicializa dicionários vazios para cada lado das apostas.
b) implemente o método adicionar_aposta, que recebe um nome de usuário (string), o valor da aposta e um lado (1 ou 2). Se não for a primeira vez que esse usuário aposta naquele time, o valor deve ser somado ao das apostas anteriores. Se esse usuário tiver apostado no outro time, o sistema deve negar a operação, retornando False. Analogamente, se a aposta for feita com sucesso, o método deve retornar True.
c) implemente o método definir_resultado recebe o lado vencedor ( 1 ou 2) e retorna um dicionário onde as chaves são nomes de usuários do lado vencedor e os valores são números contendo o saldo final de cada apostador após a definição do resultado. O saldo final de cada apostador vencedor é dado pela seguinte expressão:
Passo 1
Resumo do que o enunciado pede e informações dadas:
- Deve-se armazenar, para cada lado da aposta, um dicionário que mapeia o nome de cada apostador para o valor total que ele investiu naquele lado.
- Ao final do jogo, o montante total apostado no time perdedor deve ser distribuído entre os apostadores do time vencedor na mesma proporção das apostas de cada um. Além disso, o valor investido por cada usuário do time vencedor é devolvido.
- Perguntas que o enunciado faz:
- (a) Criar uma classe
ControladorApostacujo construtor inicializa dicionários vazios para cada lado das apostas. - (b) Implementar o método
adicionar_aposta(nome, valor, lado)que:- soma o valor à aposta anterior do mesmo usuário caso ele já tenha apostado naquele mesmo lado;
- recusa (retorna
False) se o usuário já tiver apostado no outro lado; - retorna
Truese a aposta foi aceita com sucesso.
- (c) Implementar
definir_resultado(vencedor)que recebe o lado vencedor (1 ou 2) e retorna um dicionário cujas chaves são os nomes dos apostadores vencedores e os valores são os saldos finais após a definição do resultado.
- (a) Criar uma classe
- Informação matemática fornecida no enunciado: a parcela do montante do lado perdedor atribuída a cada apostador vencedor é dada por
onde
é o valor apostado por aquele usuário,
é o total apostado no lado vencedor e
é o total apostado no lado perdedor.
- Observação importante (para não me perder na implementação): além da parcela vinda do time perdedor, o valor investido por cada apostador vencedor é devolvido. Portanto o montante final recebido por um apostador vencedor será o seu investimento
acrescido da parcela acima, ou seja
Passo 2
Escolha das estruturas e raciocínio para implementar:
- Usar dicionários do Python para armazenar, por lado, a associação nome -> valor acumulado. Dicionário é ideal porque:
- permite checar rapidamente se um nome já existe (operações de busca em tempo médio constante);
- permite acumular valores com facilidade via
d[name] = d.get(name, 0.0) + valor.
- Representação interna proposta:
self.lado1é um dicionário com apostas do lado 1;self.lado2é um dicionário com apostas do lado 2.
- Regras implementadas no método
adicionar_aposta:- se
ladoé 1 enomejá existe emself.lado2, retornaFalse(não pode apostar nos dois lados); - se
ladoé 2 enomejá existe emself.lado1, retornaFalse; - caso contrário, soma
valorao dicionário do respectivo lado e retornaTrue.
- se
- No método
definir_resultado:- identificar dicionário dos vencedores e dos perdedores;
- calcular
das apostas do lado vencedor e das apostas do lado perdedor; - para cada vencedor com aposta
, calcular a parcela recebida do lado perdedor como e o total final como ; - montar e retornar um dicionário {nome: T}.
Passo 3
Detalhes da construção do construtor:
- O construtor (
__init__) deve criar os dois dicionários vazios e inicializá-los. Em código isso será (explicação, não o método inteiro):self.lado1 = {}self.lado2 = {}
- Comentário didático: em Python
{}cria um dicionário vazio; vamos usar chaves do tipostr(nome do apostador) e valores do tipofloat(valor acumulado apostado).
Passo 4
Lógica do método adicionar_aposta passo a passo:
- Validar o parâmetro
lado— aceitar apenas1ou2. Se for outro valor, podemos recusar (retornandoFalse) pois o enunciado define só esses dois lados. - Se
lado == 1:- verificar se
nomeexiste emself.lado2. Se sim, retornarFalse(usuário já apostou no outro lado). - caso contrário, fazer
self.lado1[nome] = self.lado1.get(nome, 0.0) + float(valor)e retornarTrue.
- verificar se
- Se
lado == 2:- verificar se
nomeexiste emself.lado1. Se sim, retornarFalse. - caso contrário, acumular em
self.lado2análogo ao caso anterior e retornarTrue.
- verificar se
- Observação prática: usar
dict.get(nome, 0.0)evita ter que checarif nome in dictseparadamente para somar.
Passo 5
Lógica do método definir_resultado passo a passo com fórmulas:
- Recebemos
vencedorem. Determinamos: winners= dicionário do lado vencedor;losers= dicionário do lado perdedor.
- Calculamos os totais:
-
(soma de todos os valores no dicionário dos vencedores). -
(soma de todas as apostas do lado perdedor).
-
- Para cada apostador vencedor com aposta
: - calculamos a parcela proveniente do lado perdedor por
(Se não faz sentido dividir; nesse caso não há apostadores vencedores e o método pode retornar um dicionário vazio.) - o total final que o apostador recebe é
- calculamos a parcela proveniente do lado perdedor por
- Montamos um dicionário
resultadotal queresultado[nome] = Tpara cada nome no dicionário dos vencedores, e retornamosresultado.
- Observação sobre casos extremos:
- Se não houver apostas no lado vencedor (
), retornamos {}porque não há ninguém pra receber nada. - Se não houver apostas no lado perdedor (
), então cada vencedor simplesmente recebe de volta o seu investimento: .
- Se não houver apostas no lado vencedor (
Passo 6
Exemplo numérico para fixar o raciocínio (faço passo a passo para você entender e poder repetir na prova):
- Suponha que no lado 1 temos duas apostas: Alice
e Bob . No lado 2 temos Carol . - Então o total do lado vencedor (supondo que o vencedor seja o lado 1) é
O total do lado perdedor é - Para Alice:
Logo o total final dela é - Para Bob:
- Resultado retornado seria
{'Alice': 60.0, 'Bob': 40.0}. - Isso confirma a regra: cada vencedor recupera sua aposta e ganha uma parte proporcional do total perdido.
Passo 7
Complexidade e observações finais rápidas para a prova:
- Operações de adicionar aposta são O(1) em média (acesso e atualização de dicionário).
- Calcular o resultado exige somar as apostas (duas somas) e depois iterar sobre os vencedores — tempo O(n) onde n é número de apostadores no lado vencedor.
- Trate casos inválidos (valor de
ladoouvencedorfora de) de forma simples: recusar ou lançar erro, conforme necessidade. Aqui optei por recusar na adição e lançar ValueErroremdefinir_resultadopara sinalizar uso incorreto. - Força e coragem — isso é só implementação direta de dicionários e proporção. Você já consegue fazer isso na prova se lembrar: somar, dividir para achar fração e multiplicar pela parte perdida.
Resposta
class ControladorAposta:
def init(self):
self.lado1 = {}
self.lado2 = {}
def init(self):
self.lado1 = {}
self.lado2 = {}
def adicionar_aposta(self, nome, valor, lado):
if lado not in (1, 2):
return False
valor = float(valor)
if lado == 1:
if nome in self.lado2:
return False
self.lado1[nome] = self.lado1.get(nome, 0.0) + valor
return True
else:
if nome in self.lado1:
return False
self.lado2[nome] = self.lado2.get(nome, 0.0) + valor
return True
def definir_resultado(self, vencedor):
if vencedor not in (1, 2):
raise ValueError("vencedor deve ser 1 ou 2")
winners = self.lado1 if vencedor == 1 else self.lado2
losers = self.lado2 if vencedor == 1 else self.lado1
V = sum(winners.values())
P = sum(losers.values())
resultado = {}
if V == 0:
return resultado
for nome, u in winners.items():
share = (u / V) * P if P > 0 else 0.0
resultado[nome] = u + share
return resultado