perl logo Perl logo (Thanks to Olaf Alders)

The weekly challenge 313 - Task 1: Broken Keys

 1 #!/usr/bin/env perl
 2 # https://theweeklychallenge.org/blog/perl-weekly-challenge-313/#TASK1
 3 #
 4 # Task 1: Broken Keys
 5 # ===================
 6 #
 7 # You have a broken keyboard which sometimes type a character more than once.
 8 #
 9 # You are given a string and actual typed string.
10 #
11 # Write a script to find out if the actual typed string is meant for the given
12 # string.
13 #
14 ## Example 1
15 ##
16 ## Input: $name = "perl", $typed = "perrrl"
17 ## Output: true
18 ##
19 ## Here "r" is pressed 3 times instead of 1 time.
20 #
21 ## Example 2
22 ##
23 ## Input: $name = "raku", $typed = "rrakuuuu"
24 ## Output: true
25 #
26 ## Example 3
27 ##
28 ## Input: $name = "python", $typed = "perl"
29 ## Output: false
30 #
31 ## Example 4
32 ##
33 ## Input: $name = "coffeescript", $typed = "cofffeescccript"
34 ## Output: true
35 #
36 ############################################################
37 ##
38 ## discussion
39 ##
40 ############################################################
41 #
42 # We walk $name from left to right and do the same with $typed,
43 # keeping track of the position in both strings. If at the current
44 # position, the characters don't match, we compare the character
45 # in $typed against the previous character from $name because we're
46 # still fine if we have a match this way. If we're through with $typed,
47 # but not with $name, we can return "false". Otherwise, once we're
48 # through with $name we only need to check if all remaining characters
49 # from $typed are the same as the last character in $name. If we have
50 # any remainder in $typed, then we can return false as well.
51 # If we've used up all characters from both strings successfully, we
52 # can return "true".
53 
54 use v5.36;
55 
56 broken_keys("perl", "perrrl");
57 broken_keys("raku", "rrakuuuu");
58 broken_keys("python", "perl");
59 broken_keys("coffeescript", "cofffeescccript");
60 
61 sub broken_keys($name, $typed) {
62    say "Input: \"$name\", \"$typed\"";
63    my @name = split //, $name;
64    my @typed = split //, $typed;
65    my $prev = "";
66    my $j = 0;
67    foreach my $i (0..$#name) {
68       if($name[$i] eq $typed[$j]) {
69          $j++;
70          $prev = $name[$i];
71          next;
72       }
73       while($prev eq $typed[$j]) {
74          $j++;
75       }
76       $prev = $name[$i];
77       if($j > $#typed and $i < $#name) {
78          return say "Output: false";
79       }
80    }
81    while($j < $#typed and $prev eq $typed[$j]) {
82       $j++;
83    }
84    if($j < $#typed) {
85       return say "Output: false";
86    }
87    say "Output: true";
88 }