# Friday XIII
**Challenge 227 solutions in Perl by Matthias Muth**
## Task 1: Friday 13th
> 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.
>
> Example
> Input: $year = 2023
> Output: 2
> Since there are only 2 Friday 13th in the given year 2023 i.e. 13th Jan and 13th Oct.
Looking for an easy way to get the weekday for a given date,
the `Time::Piece` core module is an obvious choice.
`Time::Piece`'s typical usage is for dealing with 'current' times,
which are returned by the `localtime` and `gmtime` subroutines when called without parameter.
If we want to supply a different date with them,
we need to compute Unix epoch time value to do so.
We will look into that later.
But there is also the `Time::Piece->strptime(STRING, FORMAT)` subroutine that works as a constructor
for `Time::Piece` objects.
We hand in a date string like `"2023-07-13"`, and a format of `'%Y-%m-%d'`,
and there we have our time object.
So everything in one statement (but not on one line, to make it more readable!):
- month numbers from 1 to 12,
- use a `grep` code block to create the `Time::Piece` objects on the fly,
and select those who return a day_of_week of 5 (Friday),
- use `scalar` to put `grep` into a scalar context
so it returns the number of elements found instead of the list.
```perl
use v5.36;
use Time::Piece;
sub friday_13th( $year ) {
return scalar grep {
Time::Piece->strptime( "$year-$_-13", "%Y-%m-%d" )->day_of_week == 5
} 1..12;
}
```
Now maybe `strptime` is not the fastest solution,
and we could use `timegm` from `Time::Local` to create our dates
without the need of parsing a string with a format.
But using `strptime` like above looks much clearer to me than
converting month numbers from 1..12 to 0..11 and years to be offsets from 1900,
which would be necessary if we used `timegm`:
```perl
use v5.36;
use Time::Local;
use Time::Piece;
sub friday_13th( $year ) {
return scalar grep {
gmtime( timegm( 0, 0, 0, 13, $_ - 1, $year - 1900 ) )->day_of_week == 5
} 1..12;
}
```
It's also that we would be jumping between domains
(`localtime`/`gmtime` needing that 6-element list, returning an epoch time value,
then we create a Time::Piece object from that),
which does not really make it obvious what is going on.
I prefer the first version! :-)
## Task 2: Roman Maths
> Write a script to handle a 2-term arithmetic operation expressed in Roman numeral.
>
> Example
> IV + V => IX
> M - I => CMXCIX
> X / II => V
> XI * VI => LXVI
> VII ** III => CCCXLIII
> V - V => nulla (they knew about zero but didn't have a symbol)
> V / II => non potest (they didn't do fractions)
> MMM + M => non potest (they only went up to 3999)
> V - X => non potest (they didn't do negative numbers)
I'm sure it's an interesting exercise to convert Roman numerals to arabic (common) numbers
and vice versa, but here, I am not going to reinvent the wheel.
The `Roman` module from CPAN is my friend in this case.
The more interesting aspect is how to implement the arithmetic operations
in a more elegant way than a nested if-then-else statement.
I chose a hash lookup to return an anonymous subroutine that implements
the respective operation.
The rest looks quite self-explanatory to me.
Or is it only in my eyes???
```perl
use v5.36;
use Roman;
my %ops = (
'+' => sub { $_[0] + $_[1] },
'-' => sub { $_[0] - $_[1] },
'*' => sub { $_[0] * $_[1] },
'/' => sub { $_[0] / $_[1] },
'**' => sub { $_[0] ** $_[1] },
);
sub roman_maths( @input ) {
my $result = $ops{$input[1]}->( arabic( $input[0] ), arabic( $input[2] ) );
return
$result == 0
? "nulla (they knew about zero but didn't have a symbol)" :
$result != int( $result )
? "non potest (they didn't do fractions)" :
$result > 3999
? "non potest (they only went up to 3999)" :
$result < 0
? "non potest (they didn't do negative numbers)" :
Roman( $result );
}
```
#### **Thank you for the challenge!**