Power Pointing
with Raku

by Arne Sommer

Power Pointing with Raku

[374] Published 25. November 2025.

This is my response to The Weekly Challenge #349.

Challenge #349.1: Power String

You are given a string.

Write a script to return the power of the given string.

The power of the string is the maximum length of a non-empty substring that contains only one unique character.

Example 1:
Input: $str = "textbook"
Output: 2

Breakdown: "t", "e", "x", "b", "oo", "k"
The longest substring with one unique character is "oo".
Example 2:
Input: $str = "aaaaa"
Output: 5
Example 3:
Input: $str = "hoorayyy"
Output: 3

Breakdown: "h", "oo", "r", "a", "yyy"
The longest substring with one unique character is "yyy".
Example 4:
Input: $str = "x"
Output: 1
Example 5:
Input: $str = "aabcccddeeffffghijjk"
Output: 4

Breakdown: "aa", "b", "ccc", "dd", "ee", "ffff", "g", "h", "i", "jj", "k"
The longest substring with one unique character is "ffff".
File: power-string
#! /usr/bin/env raku

unit sub MAIN ($str where $str.chars > 0, :v(:$verbose));  # [1]

sub grouped ($str, :$verbose)                              # [2] 
{
  my @parts = gather
  {
    my $curr;
    my $count = 0;
    
    for $str.comb -> $char
    {
      if $count && $curr ne $char
      {
        take $curr x $count;
	$count = 0;
      }
      $curr = $char;
      $count++;
    }
    take $curr x $count;
  } 

  say ": Grouped '$str' as { @parts.raku }" if $verbose;
  return @parts;
}

say grouped($str, :$verbose)>>.chars.max;                  # [3]

[1] Ensure a string with at least one character.

[2] The «grouped» procedure returns a list of substrings, where each substring contains the same characters. The procedure is the same as I used in «group-position», way back in week 318. See Reverse Postition with Raku for a discussion.

[3] Get the lenghts of the substrings (>>.chars) and print the highest one (.max).

Running it:

$ ./power-string textbook
2

$ ./power-string aaaaa
5

$ ./power-string hoorayyy
3

$ ./power-string x
1

$ ./power-string aabcccddeeffffghijjk
4

Looking good.

With verbose mode:

$ ./power-string -v textbook
: Grouped 'textbook' as ["t", "e", "x", "t", "b", "oo", "k"]
2

$ ./power-string -v aaaaa
: Grouped 'aaaaa' as ["aaaaa"]
5

$ ./power-string -v hoorayyy
: Grouped 'hoorayyy' as ["h", "oo", "r", "a", "yyy"]
3

$ ./power-string -v x
: Grouped 'x' as ["x"]
1

$ ./power-string -v aabcccddeeffffghijjk
: Grouped 'aabcccddeeffffghijjk' as ["aa", "b", "ccc", "dd", "ee", "ffff", \
   "g", "h", "i", "jj", "k"]
4

Challenge #349.2: Meeting Point

You are given instruction string made up of U (up), D (down), L (left) and R (right).

Write a script to return true if following the instruction, you meet (0,0) at any point along the sequence.

Example 1:
Input: $path = "ULD"
Output: false

(-1,1) <- (0,1)
   |        ^
   v        |
(-1,0)    (0,0)
Example 2:
Input: $path = "ULDR"
Output: true

 (-1,1) <- (0,1)
    |        ^
    v        |
 (-1,0) -> (0,0)
Example 3:
Input: $path = "UUURRRDDD"
Output: false

(0,3) -> (1,3) -> (2,3) -> (3,3)
  ^                          |
  |                          v
(0,2)                      (3,2)
  ^                          |
  |                          v
(0,1)                      (3,1)
  ^                          |
  |                          v
(0,0)                      (3,0)
Example 4:
Input: $path = "UURRRDDLLL"
Output: true

(0,2) -> (1,2) -> (2,2) -> (3,2)
  ^                          |
  |                          v
(0,1)                      (3,1)
  ^                          |
  |                          v
(0,0) <- (1,0) <- (1,1) <- (3,0)
Example 5:
Input: $path = "RRUULLDDRRUU"
Output: true

(0,2) <- (1,2) <- (2,2)
  |                 ^
  v                 |
(0,1)             (2,1)
  |                 ^
  v                 |
(0,0) -> (1,0) -> (2,1)

Let us disregard the «at any point along the sequence» for a moment, and just look for situations where we end up at (0,0).

File: meeting-point-quick
#! /usr/bin/env raku

unit sub MAIN ($path where $path ~~ /^ <[UDLR]>+ $/;  # [1]

my $bag = $path.comb.Bag;                             # [2]

say $bag<L> == $bag<R> && $bag<U> == $bag<D>;         # [3]

[1] Ensure the directional letters only, with at least one of them.

[2] Turn the string into individual letters, and those into a Bag, a hash like structure that counts the frequencies.

See docs.raku.org/routine/Bag for more information about Bag.

[3] Report success if the Left and Right, and the Up and Down moves cancel each other out.

Running it:

$ ./meeting-point ULD
False

$ ./meeting-point ULDR
True

$ ./meeting-point UUURRRDDD
False

$ ./meeting-point UURRRDDLLL
True

$ ./meeting-point RRUULLDDRRUU
False

Looking good, except for the last one.

So, let us un-disregard the «at any point along the sequence»:

File: meeting-point
#! /usr/bin/env raku

unit sub MAIN ($path where $path ~~ /^ <[UDLR]>+ $/, # [0]
               :v(:$verbose)); 

my $x = 0;                                           # [1]
my $y = 0;                                           # [1a]

for $path.comb -> $move                              # [2]
{
  given $move                                        # [3]
  {
    when 'L' { $x--; }                               # [3L]
    when 'R' { $x++; }                               # [3R]
    when 'U' { $y--; }                               # [3U]
    when 'D' { $y++; }                               # [3D]
  }

  say ": $move -> ($x, $y)" if $verbose;

  last if $x == $y == 0;                             # [4]
}

say $x == $y == 0;                                   # [5]

[1] The starting position.

[2] Iterate over the moves.

[3] Update the position according to the given move; L, R, U or D.

Note the we do not need a default clause to catch other values, as the regexp in [0] ensures legal moves only.

See docs.raku.org/syntax/default when for more information about given/when/default.

[4] Skip the rest of the moves if we have reached (0,0). Note that this check is done after the first move, so will not be triggered initially.

[5] Report success if we are at (0,0), and failure otherwise.

Running it with verbose mode:

$ ./meeting-point -v ULD
: U -> (0, -1)
: L -> (-1, -1)
: D -> (-1, 0)
False

$ ./meeting-point -v ULDR
: U -> (0, -1)
: L -> (-1, -1)
: D -> (-1, 0)
: R -> (0, 0)
True

$ ./meeting-point -v UUURRRDDD
: U -> (0, -1)
: U -> (0, -2)
: U -> (0, -3)
: R -> (1, -3)
: R -> (2, -3)
: R -> (3, -3)
: D -> (3, -2)
: D -> (3, -1)
: D -> (3, 0)
False

$ ./meeting-point -v UURRRDDLLL
: U -> (0, -1)
: U -> (0, -2)
: R -> (1, -2)
: R -> (2, -2)
: R -> (3, -2)
: D -> (3, -1)
: D -> (3, 0)
: L -> (2, 0)
: L -> (1, 0)
: L -> (0, 0)
True

$ ./meeting-point -v RRUULLDDRRUU
: R -> (1, 0)
: R -> (2, 0)
: U -> (2, -1)
: U -> (2, -2)
: L -> (1, -2)
: L -> (0, -2)
: D -> (0, -1)
: D -> (0, 0)
True

And that's it.