-
-
Save estranged42/a140ce7eded874a88e07b089ddd81485 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| https://fivethirtyeight.com/features/when-will-the-arithmetic-anarchists-attack/ | |
| From Eric Veneto, mathematical madmen are on the loose: | |
| The year is 2000, and an arithmetical anarchist group has an idea. For the next | |
| 100 years, it will vandalize a famous landmark whenever the year (in two-digit | |
| form, for example this year is “18”) is the product of the month and date (i.e. | |
| month × date = year, in the MM/DD/YY format). | |
| A few questions about the lawless ensuing century: How many attacks will happen | |
| between the beginning of 2001 and the end of 2099? What year will see the most | |
| vandalism? The least? What will be the longest gap between attacks? | |
| Run this script with: | |
| ``` | |
| $ python3 arithmetical-anarchist.py | |
| ``` | |
| Expected Output: | |
| How many attacks will happen between the beginning of 2001 and the end of 2099? | |
| 212 | |
| What year will see the most vandalism? | |
| 2024 had 7 attacks. | |
| What year will see the least vandalism? | |
| 2037,2041,2043,2047,2053,2058,2059,2061,2062,2067,2071,2073,2074,2079,2082,2083,2086,2089,2094,2097 had zero attacks. | |
| 2001,2013,2017,2019,2023,2029,2031,2034,2038,2039,2046,2049,2051,2057,2065,2068,2069,2076,2085,2087,2091,2092,2093,2095,2098 had one attack. | |
| What will be the longest gap between attacks? | |
| 1096 days between 3/19/2057 and 3/20/2060. | |
| """ | |
| # Setup our date range. | |
| years = range(1,100) | |
| months = range(1,13) | |
| days_in_months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] | |
| # Keep track of all attack events and longest gap between attacks. | |
| events = {} | |
| gap_start = "1/1/2001" | |
| gap_end = "1/1/2001" | |
| gap_len = 0 | |
| days_since_attack = 0 | |
| # Convert m d y integers to a date string. | |
| def format_attack_date(d, m, y): | |
| return "{:d}/{:d}/{:s}".format(m, d, format_year(y)) | |
| # Convert a 1 or 2 digit year to a 4 digit year string. | |
| def format_year(y): | |
| if y < 10: | |
| return "200" + str(y) | |
| else: | |
| return "20" + str(y) | |
| # Brute force all days in all years in all months | |
| for y in years: | |
| for m in months: | |
| num_days = days_in_months[m-1] # Watch out for off-by-one errors | |
| # Look out for leap years | |
| if m == 2 and (y % 4) == 0: | |
| num_days = 29 | |
| for d in range(1, num_days+1): | |
| if d * m == y: | |
| # There's an attack on this day | |
| # See if this beats the record for longest gap between attacks | |
| if days_since_attack > gap_len: | |
| gap_start = last_attack | |
| gap_end = format_attack_date(d, m, y) | |
| gap_len = days_since_attack | |
| # Keep track of the last attack (which is now this one) | |
| last_attack = format_attack_date(d, m, y) | |
| # Attack happened today, so reset days_since_attack | |
| days_since_attack = 0 | |
| # Store this attack in our events table | |
| if y not in events: | |
| events[y] = {} | |
| if m not in events[y]: | |
| events[y][m] = [] | |
| events[y][m].append(d) | |
| else: | |
| # No attack today | |
| days_since_attack += 1 | |
| # Calculate the best and worst years | |
| worst_years = [] | |
| worst_count = 0 | |
| best_years = [] | |
| one_years = [] | |
| event_total = 0 | |
| for y in years: | |
| events_this_year = 0 | |
| if y in events.keys(): | |
| # At least one attack happened this year | |
| for m in events[y].keys(): | |
| # Add this month's attacks to the year total | |
| events_this_year += len(events[y][m]) | |
| else: | |
| # No attacks happened this year | |
| best_years.append(format_year(y)) | |
| # Does this year tie with the current worst year? | |
| if events_this_year == worst_count: | |
| worst_years.append(format_year(y)) | |
| # Is this year the new worst year? | |
| if events_this_year > worst_count: | |
| worst_count = events_this_year | |
| worst_years = [format_year(y)] | |
| # If there was only one attack this year, keep track of it | |
| if events_this_year == 1: | |
| one_years.append(format_year(y)) | |
| # Add up all the events this year | |
| event_total += events_this_year | |
| print("How many attacks will happen between the beginning of 2001 and the end of 2099?") | |
| print(event_total) | |
| print() | |
| print("What year will see the most vandalism?") | |
| print("{:s} had {:d} attacks.".format(",".join(worst_years), worst_count) ) | |
| print() | |
| # This question was a bit ambiguous to me. There are years where no attacks take place, | |
| # so are those the years with the least? Or are we only looking for years where an | |
| # attack took place? I fudged and lists all years with zero or one attack. | |
| print("What year will see the least vandalism?") | |
| print("{:s} had zero attacks.".format(",".join(best_years)) ) | |
| print("{:s} had one attack.".format(",".join(one_years)) ) | |
| print() | |
| print("What will be the longest gap between attacks?") | |
| print("{:d} days between {:s} and {:s}.".format(gap_len, gap_start, gap_end) ) | |
| print() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here is a shorter version: