#!/usr/bin/env python3 import random, datetime, os, math, decimal MAX_SIMULATIONS = 100_000 class ProgressBar: def __init__(self, size=100, prompt=None): self.size = size self.prompt = prompt self.at = 0 self.columns = os.get_terminal_size().columns self.space = self.columns - 9 self.percent = None self.moved = None if self.prompt is not None: self.space -= len(self.prompt) + 1 decimal.getcontext().prec = 4 def move(self, amt=1): self.at += amt self.percent = decimal.Decimal.from_float(self.at / self.size) self.moved = math.floor(self.space * self.percent) def render_bar(self): return ("\u2588" * self.moved) + (" " * (self.space - self.moved)) def progress(self): percent = self.percent * 100 if percent.compare(decimal.Decimal(100)) == decimal.Decimal(-1): return f"{percent:05.2f}" else: return f"{percent:.1f}" def render(self): if self.prompt is not None: return f"{self.prompt} [{self.render_bar()}] {self.progress()}%" else: return f"[{self.render_bar()}] {self.progress()}%" def __str__(self): return self.render() count = int(input(f"Total birthdays: ")) matches = 0 prog_bar = ProgressBar(size=MAX_SIMULATIONS, prompt="Running simulations") for simulation in range(MAX_SIMULATIONS): birthdays = { } for idx in range(count): year = datetime.date(2001, 1, 1) days = datetime.timedelta(random.randint(0, 364)) birthday = year + days if birthday in birthdays: matches += 1 break else: birthdays[birthday] = 0 prog_bar.move(1) end = "" if simulation == MAX_SIMULATIONS - 1: end = "\n" print(f"\r{prog_bar}", end=end) percent = decimal.Decimal.from_float(matches / MAX_SIMULATIONS) * 100 if matches == MAX_SIMULATIONS: print(f"Calculated {percent:.1f}% people shared a birthday.") else: print(f"Calculated {percent:05.2f}% people shared a birthday.")