Bad luck and mathematica
Weekly challenge 227 — 24 July 2023
Week 227: 24 Jul 2023
You are given a year number in the range 1753 to 9999.
Write a script to find out how many dates in the year are Friday 13th. Assume that the current Gregorian calendar applies.
Input: $year = 2023 Output: 2... as 13th January and 13th October are Fridays.
To start with, note that there are only 14 different patterns of days within a year. 1 January can be any of the 7 days of the week, and any year can be a leap year or not. So we have can create the following table showing the number of Friday 13ths in each of these types of year:
1 Jan is | Not leap | Leap |
---|---|---|
Sun | 2 | 3 |
Mon | 2 | 2 |
Tue | 2 | 1 |
Wed | 1 | 2 |
Thu | 3 | 2 |
Fri | 1 | 1 |
Sat | 1 | 1 |
For example, 2024 is a leap year starting on Monday and it contains Friday 13 September and December. 2026 is a non-leap year starting on a Thursday, and it has Friday 13 February, March and November.
So first we have to establish whether the supplied year is a leap year - which is easy.
Then, slightly harder, we need to find out what day of the week the year starts on. I considered a number of ways of doing this but in the end settled on a loop from 1753 to the target year. We know from this helpful site that 1 January 1753 was a Monday. We can then step forward year by year knowing that:
Granted, for 9999 we will have to execute the loop 8246 times, but it's a very simple calculation, and even on my quite slow machine it runs in milliseconds.
(Disclosure: I submitted this challenge - before I tried solving it).
#!/usr/bin/perl use v5.16; # The Weekly Challenge - 2023-07-24 use utf8; # Week 227 task 1 - Friday 13th use strict; # Peter Campbell Smith use warnings; # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge friday_13th(2023); friday_13th(1945); friday_13th(2012); friday_13th(1753); friday_13th(9999); sub friday_13th { my ($target, $offset, $thirteenths); # 1 Jan is: sun mon tue wed thu fri sat $thirteenths = [[2, 3], [2, 2], [2, 1], [1, 2], [3, 2], [1, 1], [1, 1]]; $target = $_[0]; $offset = -1; # 1 Jan moves forward 1 day, or 2 days if previous year was leap $offset += is_leap($_- 1) ? 2 : 1 for 1753 .. $target; say qq[\nInput: $target\nOutput: ] . $thirteenths->[$offset % 7]->[is_leap($target)]; } sub is_leap { # returns 1 for leap year, 0 for non-leap # non-century year century year return ($_[0] % 100 ? ($_[0] % 4 ? 0 : 1) : ($_[0] % 400 ? 0 : 1)); }
Input: 2023 Output: 2 Input: 1945 Output: 2 Input: 2012 Output: 3 Input: 1753 Output: 2 Input: 9999 Output: 1
Any content of this website which has been created by Peter Campbell Smith is in the public domain