DEV Community

Bob Lied
Bob Lied

Posted on

PWC 366, Task 2, Valid Times

PWC 366 Task 2, Valid Times

Here we are at another Weekly Challenge, ticking away the moments that make up a dull day. Fritter and waste the hours in an off-hand way. Kicking around on a piece of ground in your home town, waiting for someone or something to show you the way. Here's a way.

The Requirements Phase

You are given a time in the form ‘HH:MM’. The earliest possible time is ‘00:00’ and the latest possible time is ‘23:59’. In the string time, the digits represented by the ‘?’ symbol are unknown, and must be replaced with a digit from 0 to 9. Write a script to return the count of different ways we can make it a valid time.

  • Example 1: Input: $time = "?2:34", Output: 3
    • 02:34, 12:34, 22:34
  • Example 2: Input: $time = "?4:?0", Output: 12
    • Combinations of hours 04 and 14, with minutes 00, 10, 20, 30, 40, 50
  • Example 3: Input: $time = "??:??", Output: 1440
  • Example 4: Input: $time = "?3:45", Output: 3
    • 03:45, 13:45, 23:45
  • Example 5: Input: $time = "2?:15", Output: 4
    • 20:15, 21:15, 22:15, 23:15

The Design Phase

My first thought is that it would be fun to make some kind of iterator or generator that replaces each ? with its valid possibilities. My second thought is, "Nah, that seems like a lot of work." And since the cardinal virtue of Perl programming is laziness, I moved on to something simpler.

There are 24 valid hours and 60 valid minutes. The total valid combinations is the cross-product of the two. Let's go with that.

The Implementation Phase

sub validTime($time)
{
    state @hour   = '00' .. '23';
    state @minute = '00' .. '59';

    my ($h, $m) = map { s/\?/./gr } split(/:/, $time);

    return (grep /$h/, @hour) * (grep /$m/, @minute);
}
Enter fullscreen mode Exit fullscreen mode

Notes:

  • state variables -- These reference lists only need to be set up once, and only in the scope of this function. That's what state does.

  • '00' .. '23' -- The .. sequence operator has the nice feature that if you want leading zeroes, you get them. Looking at you, bash.

  • split(/:/, $time) -- Divide the input into its components. As in so many weekly challenge tasks, I'm assuming that the input has already been sanitized and is showing up here in a valid form.

  • map { ... } -- Do something to both the hours and the minutes.

  • s/\?/./gr -- The something is to replace ? with . so that it becomes a regular expression. The ? is a meta-character, so it needs to be quoted. Adding the r flag yields the modified string; otherwise s///g would yield the number of substitutions, which is not useful in this context.

  • my ($h, $m) = ... -- Declaring and initializing two variables from a list of two things.

  • (grep /$h/, @hour) -- Select a list of the valid hours that can match the $h pattern. This is in a scalar context (numerical multiplication), so the scalar value will result -- the number of matches. Similarly for minutes.

  • We only need the count, so multiply the two. We could have generated the list of valid times by using the hours and minutes returned from grep in array context, but (I believe I already mentioned this), lazy.

The Delivery Phase

And there you have it. You run and you run to catch up with the sun, but it's sinking, and racing around to come up behind you again. The sun is the same in a relative way, but you're older, shorter of breath, and one day closer to death. But at least you solved weekly challenge 366.

Top comments (0)