<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matthias Muth</title>
    <description>The latest articles on DEV Community by Matthias Muth (@muthm).</description>
    <link>https://dev.to/muthm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1091985%2F01f06e10-778b-44d1-b30d-b51f27a3935b.jpg</url>
      <title>DEV Community: Matthias Muth</title>
      <link>https://dev.to/muthm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/muthm"/>
    <language>en</language>
    <item>
      <title>Arrange Any Aligned Average (PWC 304)</title>
      <dc:creator>Matthias Muth</dc:creator>
      <pubDate>Sun, 19 Jan 2025 23:53:15 +0000</pubDate>
      <link>https://dev.to/muthm/arrange-any-aligned-average-34j2</link>
      <guid>https://dev.to/muthm/arrange-any-aligned-average-34j2</guid>
      <description>&lt;p&gt;&lt;strong&gt;Challenge 304 solutions in Perl by Matthias Muth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These are my &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-304/#TASK1" rel="noopener noreferrer"&gt;Challenge 304 Task 1 and 2&lt;/a&gt; solutions in Perl&lt;br&gt;
for &lt;a href="https://theweeklychallenge.org/" rel="noopener noreferrer"&gt;The Weekly Challenge&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://manwar.org/" rel="noopener noreferrer"&gt;Mohammad Sajid Anwar&lt;/a&gt; for two more great challenges this week! &lt;/p&gt;
&lt;h2&gt;
  
  
  Task 1: Arrange Binary
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given a list of binary digits (0 and 1) and a positive integer, \$n.&lt;br&gt;
Write a script to return true if you can re-arrange the list by replacing at least \$n digits with 1 in the given list so that no two consecutive digits are 1 otherwise return false.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @digits = (1, 0, 0, 0, 1), $n = 1
Output: true
Re-arranged list: (1, 0, 1, 0, 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @digits = (1, 0, 0, 0, 1), $n = 2
Output: false
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The task description contains the words 'replacing' and 'digits'.&lt;br&gt;
The first thing that I think of when I hear 'replacing' in a Perl context is 'What's the regular expression that I can use?'. So here we go.&lt;/p&gt;

&lt;p&gt;The array of digits is easily turned into a string of zeroes and ones by &lt;code&gt;join&lt;/code&gt;ing together the array elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    my $string = join "", $digits-&amp;gt;@*;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we match the places where we can put in ones instead of zeroes.&lt;br&gt;
The condition for replacing a &lt;code&gt;'0'&lt;/code&gt; by a &lt;code&gt;'1'&lt;/code&gt; is that neither left of it nor right of it there is a &lt;code&gt;'1'&lt;/code&gt; already.&lt;br&gt;
We can translate this directly to a regular expression, using a negative lookbehind and a negative lookahead. Using the &lt;code&gt;x&lt;/code&gt; modifier to make those more easily recognizable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;    &lt;span class="nv"&gt;$string&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/ (?&amp;lt;!1) 0 (?!1) /1/x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We cannot simply use the &lt;code&gt;g&lt;/code&gt; modifier to replace all those zeroes in one go, because our substitutions are not taken into account for finding the next match. For sequences like &lt;code&gt;'00000'&lt;/code&gt; we would end up with &lt;code&gt;'11111'&lt;/code&gt;, because every &lt;code&gt;'0'&lt;/code&gt; in the &lt;em&gt;original&lt;/em&gt; string fulfils the critera to be replaced by a &lt;code&gt;'1'&lt;/code&gt;.&lt;br&gt;
That means that we need to put the substitution into a &lt;code&gt;while&lt;/code&gt; loop. Within the loop body, we decrement &lt;code&gt;$n&lt;/code&gt; by one, because we were able to do a replacement.&lt;br&gt;
So:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$string&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/ (?&amp;lt;!1) 0 (?!1) /1/x&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In production software, or with longer strings, I would probably try to avoid restarting the search for the next match at the beginning of the string again and again. I would probably do so by setting &lt;code&gt;pos $string&lt;/code&gt; to the place behind the recent successful replacement, before re-iterating.&lt;/p&gt;

&lt;p&gt;For the challenge examples, this here works well enough already:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;( $digits, $n ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="p"&gt;"",&lt;/span&gt; &lt;span class="nv"&gt;$digits&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$string&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/ (?&amp;lt;!1) 0 (?!1) /1/x&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have your own solution, you might try with these additional testcases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Test2::&lt;/span&gt;&lt;span class="nv"&gt;V0&lt;/span&gt; &lt;span class="sx"&gt;qw( -no_srand )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Example 1: arrange_binary( [1, 0, 0, 0, 1], 1 ) is true&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Example 2: arrange_binary( [1, 0, 0, 0, 1], 2 ) is false&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 1: arrange_binary( [], 0 ) is true&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 2: arrange_binary( [], 1 ) is false&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 3: arrange_binary( [ 0 ], 1 ) is true&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 4: arrange_binary( [ 1 ], 1 ) is false&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 5: arrange_binary( [ 0 ], 2 ) is false&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 6: arrange_binary( [0, 0], 1 ) is true&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 7: arrange_binary( [0, 0], 2 ) is false&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 8: arrange_binary( [0, 1], 1 ) is false&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 9: arrange_binary( [0, 0, 0], 2 ) is true&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 10: arrange_binary( [1, 0, 0], 1 ) is true&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 11: arrange_binary( [0, 1, 0], 1 ) is false&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 12: arrange_binary( [0, 0, 1], 1 ) is true&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 13: arrange_binary( [0, 0, 0, 0, 0], 3 ) is true&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;arrange_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test 14: arrange_binary( [0, 0, 0, 0, 0], 4 ) is false&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;

&lt;span class="nv"&gt;done_testing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Task 2: Maximum Average
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an array of integers, @ints and an integer, $n which is less than or equal to total elements in the given array.&lt;br&gt;
Write a script to find the contiguous subarray whose length is the given integer, $n, and has the maximum average. It should return the average.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (1, 12, -5, -6, 50, 3), \$n = 4
Output: 12.75
Subarray: (12, -5, -6, 50)
Average: (12 - 5 - 6 + 50) / 4 = 12.75
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (5), \$n = 1
Output: 5
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;So finding 'contiguous subarrays'.&lt;br&gt;
Good that we know the length of each of those subarrays -- it's &lt;code&gt;$n&lt;/code&gt;.&lt;br&gt;
Which makes it easier, because we don't need to find &lt;em&gt;all&lt;/em&gt; possible contiguous subarrays of the input arrays, but only those with that given length.&lt;br&gt;
What we really do is a 'sliding window' search, taking the first &lt;code&gt;$n&lt;/code&gt; elements of the array, then the &lt;code&gt;$n&lt;/code&gt; elements starting with the second element, and so on.&lt;/p&gt;

&lt;p&gt;In a loop, the first starting index for the sliding window is &lt;code&gt;0&lt;/code&gt;, of course.&lt;br&gt;
The last index is the one that uses the last &lt;code&gt;$n&lt;/code&gt; elements for the window.&lt;br&gt;
If we have a window size of &lt;code&gt;$n == 1&lt;/code&gt;, the last window starts at &lt;code&gt;$ints-&amp;gt;$#*&lt;/code&gt;. Generalizing from there, the last index for any &lt;code&gt;$n&lt;/code&gt; is &lt;code&gt;$ints-&amp;gt;$#* - ( $n - 1 )&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To get the values in the window, we can simply use Perl's &lt;em&gt;arrays slice&lt;/em&gt; construct. Starting at index &lt;code&gt;$_&lt;/code&gt;, the window is &lt;code&gt;@int[ $_ .. ( $_ + $n - 1 ) ]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I put this together into one statement, using &lt;code&gt;map&lt;/code&gt; to iterate through the windows, &lt;code&gt;sum&lt;/code&gt; to sum up each window, &lt;code&gt;max&lt;/code&gt;to find the largest window sum, and &lt;code&gt;/ $n&lt;/code&gt; to reduce that to the largest average.&lt;/p&gt;

&lt;p&gt;In my environment, the array data are handed into the subroutine as an arrayref, so instead of &lt;code&gt;@ints&lt;/code&gt; we have &lt;code&gt;$ints&lt;/code&gt; pointing to the data.&lt;br&gt;
I prefer using the 'Postfix Dereferencing Syntax' (&lt;code&gt;$ints-&amp;gt;@*[...]&lt;/code&gt;) for accessing the array data (and also &lt;code&gt;$ints-&amp;gt;$#*&lt;/code&gt; for the last index into that array), because I find it easier to read and more logical to write most of the times.&lt;/p&gt;

&lt;p&gt;So here it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="sx"&gt;qw( sum max )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;maximum_average&lt;/span&gt;&lt;span class="p"&gt;( $ints, $n ) {&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="nv"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="c1"&gt;#* - ( $n - 1 )  )&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Thank you for the challenge!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Find the complete source code for both tasks, including tests, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-304/challenge-304/matthias-muth" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
      <category>challenge304</category>
    </item>
    <item>
      <title>Maximally Indexed Indices (PWC 298)</title>
      <dc:creator>Matthias Muth</dc:creator>
      <pubDate>Sun, 08 Dec 2024 23:56:17 +0000</pubDate>
      <link>https://dev.to/muthm/maximally-indexed-indices-2a3p</link>
      <guid>https://dev.to/muthm/maximally-indexed-indices-2a3p</guid>
      <description>&lt;p&gt;&lt;strong&gt;Challenge 298 solutions in Perl by Matthias Muth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://manwar.org/" rel="noopener noreferrer"&gt;Mohammad Sajid Anwar&lt;/a&gt; for two more great challenges this week! &lt;/p&gt;

&lt;p&gt;These are my &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-298/#TASK1" rel="noopener noreferrer"&gt;Challenge 298 Task 1 and 2&lt;/a&gt; solutions in Perl&lt;br&gt;
for &lt;a href="https://theweeklychallenge.org/" rel="noopener noreferrer"&gt;The Weekly Challenge&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Task 1: Maximal Square&lt;/strong&gt;&lt;br&gt;
Quite classical: nested loops for rows and columns, and then for the width of the possible square.&lt;br&gt;
The trick here is to &lt;em&gt;extend&lt;/em&gt; the square by stripes to the right and below until it doesn't match the criteria anymore.&lt;br&gt;
Finding the maximum of all size on the fly is easy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task 2: Right Interval&lt;/strong&gt;&lt;br&gt;
Sorting the &lt;em&gt;indices&lt;/em&gt; of the given intervals by their &lt;code&gt;start_i&lt;/code&gt; values, resulting in indices of indices. Then go through the sorted array to more easily find the 'right' interval. Don't get mixed up by the level of indexation!  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;:&lt;br&gt;
Find the complete source code for both tasks, including tests, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-298/challenge-298/matthias-muth#readme" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Task 1: Maximal Square
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an m x n binary matrix with 0 and 1 only.&lt;br&gt;
Write a script to find the largest square containing only 1's and return it’s area.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @matrix = ([1, 0, 1, 0, 0],
                  [1, 0, 1, 1, 1],
                  [1, 1, 1, 1, 1],
                  [1, 0, 0, 1, 0])
Output: 4
Two maximal square found with same size marked as 'x':
[1, 0, 1, 0, 0]
[1, 0, x, x, 1]
[1, 1, x, x, 1]
[1, 0, 0, 1, 0]
[1, 0, 1, 0, 0]
[1, 0, 1, x, x]
[1, 1, 1, x, x]
[1, 0, 0, 1, 0]
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @matrix = ([0, 1],
                  [1, 0])
Output: 1
Two maximal square found with same size marked as 'x':
[0, x]
[1, 0]
[0, 1]
[x, 0]
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @matrix = ([0])
Output: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;I chose a classical approach, using two nested loops for rows and columns.&lt;/p&gt;

&lt;p&gt;At any given position, if the field is &lt;code&gt;1&lt;/code&gt;, we already have a matrix, of size 1.&lt;br&gt;
Now we can try to extend our matrix by one column to the right and one row below. If all fields at the right edge of that extended matrix are &lt;code&gt;1&lt;/code&gt;, as well as all fields at its bottom edge, the extended matrix is a valid square. We repeat that until the test fails, or the extended matrix hits the border of the original grid.&lt;/p&gt;

&lt;p&gt;For checking the right and bottom border for 'all ones', the &lt;code&gt;all&lt;/code&gt; function from the &lt;code&gt;List::Util&lt;/code&gt; core module comes in handy.&lt;/p&gt;

&lt;p&gt;We update the maximum square width in each iteration, and return the squared maximum width (the size of the largest square) at the end.&lt;/p&gt;

&lt;p&gt;Three nested loops, but quite straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="sx"&gt;qw( all max )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;maximal_square&lt;/span&gt;&lt;span class="p"&gt;( $matrix ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$last_r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$last_c&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$matrix&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="c1"&gt;#*, $matrix-&amp;gt;[0]-&amp;gt;$#* );&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$r&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="nv"&gt;$last_r&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="nv"&gt;$last_c&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;next&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$matrix&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$r&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$r&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$last_r&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$last_c&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;all&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$matrix&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$r&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt; &lt;span class="p"&gt;][&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;all&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$matrix&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$r&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="p"&gt;][&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nv"&gt;$max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$max&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Task 2: Right Interval
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an array of @intervals, where \$intervals[i] = [starti, endi] and each starti is unique.&lt;br&gt;
The right interval for an interval i is an interval j such that startj &amp;gt;= endi and startj is minimized. Please note that i may equal j.&lt;br&gt;
Write a script to return an array of right interval indices for each interval i. If no right interval exists for interval i, then put -1 at index i.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @intervals = ([3,4], [2,3], [1,2])
Output: (-1, 0, 1)
There is no right interval for [3,4].
The right interval for [2,3] is [3,4] since start0 = 3 is the smallest start that is &amp;gt;= end1 = 3.
The right interval for [1,2] is [2,3] since start1 = 2 is the smallest start that is &amp;gt;= end2 = 2.
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @intervals = ([1,4], [2,3], [3,4])
Output: (-1, 2, -1)
There is no right interval for [1,4] and [3,4].
The right interval for [2,3] is [3,4] since start2 = 3 is the smallest start that is &amp;gt;= end1 = 3.
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @intervals = ([1,2])
Output: (-1)
There is only one interval in the collection, so it outputs -1.
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 4&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @intervals = ([1,4], [2, 2], [3, 4])
Output: (-1, 1, -1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;I want to find the interval to the right of each interval that meets a given criteria, but the intervals in the input data are ordered randomly. So best is to &lt;code&gt;sort&lt;/code&gt; the intervals first, using their &lt;code&gt;start_i&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;In the sorted array, we only store the &lt;em&gt;indices&lt;/em&gt; into the original array, because we will need the original index for building up the results to return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@sorted_indices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$intervals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$intervals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;keys&lt;/span&gt; &lt;span class="nv"&gt;$intervals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use the &lt;code&gt;keys ARRAY&lt;/code&gt; standard Perl function instead of &lt;code&gt;0..$#ARRAY&lt;/code&gt; for getting the list of all indices of &lt;code&gt;ARRAY&lt;/code&gt;. This is shorter, easier to type, and less prone to typing errors. It has been available since Perl 5.12 (so since the year 2010!).&lt;/p&gt;

&lt;p&gt;The indices of the sorted array point to the indices of the original array. We have indexed the indices! (Hence the title of this blog.)&lt;/p&gt;

&lt;p&gt;We can then find the 'right' interval for each original interval by getting the &lt;code&gt;first&lt;/code&gt; entry in the sorted array that points to an interval that meets the criteria of having a &lt;code&gt;start_i&lt;/code&gt; value equal to or greater that the &lt;code&gt;end_i&lt;/code&gt; value of the current interval:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$end_i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;first&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$intervals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nv"&gt;$end_i&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;@sorted_indices&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;$intervals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works, and is a good enough solution for the test data.&lt;/p&gt;

&lt;p&gt;But as usual, I try to not repeat doing things that aren't necessary. You may call it 'runtime optimization', but I think that if it is algorithmically unnecessary, it's a waste of resources, and not a good solution. &lt;/p&gt;

&lt;p&gt;What bothers me is this:&lt;br&gt;
Each time we want a 'right' interval for an original interval, we go through the sorted array &lt;em&gt;from the beginning&lt;/em&gt; again.&lt;/p&gt;

&lt;p&gt;Looking for a way to avoid this, we could walk through the &lt;em&gt;sorted&lt;/em&gt; array instead of the original array. Then we can start searching at the current interval instead of the beginning of the array. And typically the search will return one of the first few intervals that are to the right of the current interval (skipping only those that start &lt;em&gt;inside&lt;/em&gt; our current interval, and thus are not 'right' intervals).&lt;/p&gt;

&lt;p&gt;The downside is that we get the results in a seemingly random order. But we have the original index, so we can put each result into a &lt;code&gt;@result&lt;/code&gt; array at the correct place, and just return that array in the end.&lt;/p&gt;

&lt;p&gt;That solution then looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;right_interval&lt;/span&gt;&lt;span class="p"&gt;( $intervals ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@sorted_indices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$intervals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$intervals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nb"&gt;keys&lt;/span&gt; &lt;span class="nv"&gt;$intervals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$si_i&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="nv"&gt;$#sorted_indices&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$sorted_indices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$si_i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$end_i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$intervals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nv"&gt;$results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;first&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$intervals&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nv"&gt;$end_i&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nv"&gt;@sorted_indices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$si_i&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$#sorted_indices&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;@results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feeling good about not heating the CPU too much, by indexing indices!&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Thank you for the challenge!&lt;/strong&gt;
&lt;/h4&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
      <category>challenge298</category>
    </item>
    <item>
      <title>Ups and Downs, Beginnings and Ends (PWC 297)</title>
      <dc:creator>Matthias Muth</dc:creator>
      <pubDate>Sun, 01 Dec 2024 06:41:09 +0000</pubDate>
      <link>https://dev.to/muthm/ups-and-downs-beginnings-and-ends-pwc-297-4hc8</link>
      <guid>https://dev.to/muthm/ups-and-downs-beginnings-and-ends-pwc-297-4hc8</guid>
      <description>&lt;p&gt;&lt;strong&gt;Challenge 297 solutions in Perl by Matthias Muth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These are my &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-297/#TASK1" rel="noopener noreferrer"&gt;Challenge 297 Task 1 and 2&lt;/a&gt; solutions in Perl&lt;br&gt;
for &lt;a href="https://theweeklychallenge.org/" rel="noopener noreferrer"&gt;The Weekly Challenge&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Task 1: Contiguous Array&lt;/strong&gt;&lt;br&gt;
The trick is to use &lt;em&gt;ups and downs&lt;/em&gt; (&lt;code&gt;+1&lt;/code&gt; and &lt;code&gt;-1&lt;/code&gt;) instead of binary (1, 0), and add up those numbers. The sum will be the same before and after each subarray with an equal number of the two values, because they will inhibit each other.&lt;br&gt;
Then find the longest stretch between positions having the same sum value.&lt;br&gt;
One pass through the array only, 

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task 2: Semi-Ordered Permutation&lt;/strong&gt;&lt;br&gt;
Determine the positions of '1' and 'n' (the largest number). The number of moves needed is their distance from the left and right end of the array, respectively. Minus one if the '1' was at the right of the 'n' originally.&lt;br&gt;
Not actually doing the moves!&lt;br&gt;
One pass, again, for finding the positions, even with an early loop exit (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
, too).&lt;br&gt;
Then a simple formula.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;:&lt;br&gt;
Find the complete source code for both tasks, including tests, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-297/challenge-297/matthias-muth#readme" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Task 1: Contiguous Array
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an array of binary numbers, @binary.&lt;br&gt;
Write a script to return the maximum length of a contiguous subarray with an equal number of 0 and 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @binary = (1, 0)
Output: 2
(1, 0) is the longest contiguous subarray with an equal number of 0 and 1.
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @binary = (0, 1, 0)
Output: 2
(1, 0) or (0, 1) is the longest contiguous subarray with an equal number of 0 and 1.
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 3&lt;/strong&gt;*&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @binary = (0, 0, 0, 0, 0)
Output: 0
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 4&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @binary = (0, 1, 0, 0, 1, 0)
Output: 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;I'm using a trick for making it easier to detect subarrays with an equal number of the two values:&lt;br&gt;
I translate binary 1 and 0 into values +1 and -1, or '&lt;strong&gt;ups and downs&lt;/strong&gt;'.&lt;/p&gt;

&lt;p&gt;Then, for any contiguous subarray with an equal number of +1 and -1,&lt;br&gt;
the sum of its values will be zero.&lt;/p&gt;

&lt;p&gt;Now, I built a cumulated sum, walking through the array.&lt;br&gt;
Whenever a cumulated sum value occurs twice,&lt;br&gt;
there is a subarray with an equal number of ups and&lt;br&gt;
downs in between, and its length is the difference between the indexes where&lt;br&gt;
the sum values occurred.&lt;/p&gt;

&lt;p&gt;For the the program, I therefore mark the index of the&lt;br&gt;
first occurrence of each sum value in a hash lookup as I walk through the array.&lt;br&gt;
Then I remember the maximum of the length values while iterating.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;contiguous_array&lt;/span&gt;&lt;span class="p"&gt;( @binary ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$max_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;# The sum value of zero appears *before* the first number.&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%first_appearance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;keys&lt;/span&gt; &lt;span class="nv"&gt;@binary&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# Add -1 or +1 to the running sum.&lt;/span&gt;
        &lt;span class="nv"&gt;$sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nv"&gt;$binary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$first_appearance&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$first_appearance&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nv"&gt;$max_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$length&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$max_length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$max_length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Glad to have found a solution that needs only one loop over the array,&lt;br&gt;
without repeated counting of subarrays.&lt;br&gt;

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 rules!&lt;/p&gt;
&lt;h2&gt;
  
  
  Task 2: Semi-Ordered Permutation
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given permutation of \$n integers, @ints.&lt;br&gt;
Write a script to find the minimum number of swaps needed to make the @ints a semi-ordered permutation.&lt;br&gt;
A permutation is a sequence of integers from 1 to n of length n containing  each number exactly once.&lt;br&gt;
A permutation is called semi-ordered if the first number is 1 and the last number equals n.&lt;br&gt;
You are ONLY allowed to pick adjacent elements and swap them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (2, 1, 4, 3)
Output: 2
Swap 2 &amp;lt;=&amp;gt; 1 =&amp;gt; (1, 2, 4, 3)
Swap 4 &amp;lt;=&amp;gt; 3 =&amp;gt; (1, 2, 3, 4)
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (2, 4, 1, 3)
Output: 3
Swap 4 &amp;lt;=&amp;gt; 1 =&amp;gt; (2, 1, 4, 3)
Swap 2 &amp;lt;=&amp;gt; 1 =&amp;gt; (1, 2, 4, 3)
Swap 4 &amp;lt;=&amp;gt; 3 =&amp;gt; (1, 2, 3, 4)
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (1, 3, 2, 4, 5)
Output: 0
Already a semi-ordered permutation.
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;There's no need for actually doing all the swaps to move the numbers!&lt;br&gt;
It's enough to find the positions of '1' and 'n' (the largest number).&lt;br&gt;
I chose &lt;em&gt;not&lt;/em&gt; to use two calls to &lt;code&gt;find&lt;/code&gt; (from &lt;code&gt;List::Util&lt;/code&gt;) for that, but to keep it simple, in a single loop. I exit the loop early once both positions are known.&lt;/p&gt;

&lt;p&gt;The number of moves needed than can be computed with a simple formula, adding.&lt;br&gt;
the distance of the '1' from the left end of the array (which is its position, actually) and the distance of the 'n' from its right end.&lt;/p&gt;

&lt;p&gt;If we find the '1' to the right of the 'n', that saves us one swap, because as they pass each other, that single swap will move them both in their respective desired direction.&lt;/p&gt;

&lt;p&gt;Actually, the main exercise here is finding nice variable names...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;semi_ordered_permutation&lt;/span&gt;&lt;span class="p"&gt;( @ints ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$one_index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$n_index&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;keys&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$one_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$n_index&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;last&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt; &lt;span class="nv"&gt;$one_index&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt; &lt;span class="nv"&gt;$n_index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$moves_for_one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$one_index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$moves_for_n&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$n_index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$moves_for_one&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$moves_for_n&lt;/span&gt;
        &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$one_index&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$n_index&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, again, it's looping over the array only once, even exiting the loop early.&lt;br&gt;
So 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 again! &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Thank you for the challenge!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Find the complete source code for both tasks, including tests, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-297/challenge-297/matthias-muth#readme" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
      <category>challenge297</category>
    </item>
    <item>
      <title>The Run-Length of Matchsticks (PWC 296)</title>
      <dc:creator>Matthias Muth</dc:creator>
      <pubDate>Sun, 24 Nov 2024 22:28:02 +0000</pubDate>
      <link>https://dev.to/muthm/the-run-length-of-matchsticks-pwc-296-24b4</link>
      <guid>https://dev.to/muthm/the-run-length-of-matchsticks-pwc-296-24b4</guid>
      <description>&lt;p&gt;&lt;strong&gt;Challenge 296 solutions in Perl by Matthias Muth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These are my &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-296/#TASK1" rel="noopener noreferrer"&gt;Challenge 296 Task 1 and 2&lt;/a&gt; solutions in Perl&lt;br&gt;
for &lt;a href="https://theweeklychallenge.org/" rel="noopener noreferrer"&gt;The Weekly Challenge - Perl and Raku&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Task 1: String Compression&lt;/strong&gt;&lt;br&gt;
Detecting runs of same characters? Regular expression!&lt;br&gt;
Replacing it by its run-length encoding? In the same statement!&lt;br&gt;
Reversing the compression as a BONUS? Even simpler!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task 2: Matchstick Square&lt;/strong&gt;&lt;br&gt;
A short solution based on a CPAN module works well for the examples and is short, but it doesn't really scale for larger sets of matchsticks.&lt;br&gt;
In my own implementation, a 'target sum' iterator selects groups of matchsticks that have the needed length of one side of the square, leaving the rest of matchsticks for two more calls for the second and third side.&lt;br&gt;
Blindingly fast, even for larger sets (try with 15, 20 or 25 matchsticks, for example!).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;:&lt;br&gt;
Find the complete source code for both tasks, including more tests, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-296/challenge-296/matthias-muth#readme" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Task 1: String Compression
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given a string of alphabetic characters, $chars.&lt;br&gt;
Write a script to compress the string with run-length encoding, as shown in the examples.&lt;br&gt;
A compressed unit can be either a single character or a count followed by a character.&lt;br&gt;
BONUS: Write a decompression function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: \$chars = "abbc"
Output: "a2bc"
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: \$chars = "aaabccc"
Output: "3ab3c"
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: \$chars = "abcc"
Output: "ab2c"
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;This is an easy task for Perl's built-in regular expressions:&lt;/p&gt;

&lt;p&gt;We capture any character as our first character of the run. Then we use a &lt;em&gt;backreference&lt;/em&gt; to that captured first character to accept only the same character again, 1 or more times.&lt;/p&gt;

&lt;p&gt;For replacing that sequence of characters by their run-length-encoded form, we use a &lt;code&gt;s/PATTERN/REPLACEMENT/&lt;/code&gt; substitution.&lt;br&gt;
We add three options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/e&lt;/code&gt;&lt;br&gt;
causes the REPLACEMENT to be evaluated as an expression. In our case, this will be a string with the run-length-encoded form of the matched sequence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/g&lt;/code&gt;&lt;br&gt;
for doing a global substitution, for all sequences we can find.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/r&lt;/code&gt;&lt;br&gt;
to return the result string instead of the number of substitutions done.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of that is just one statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;string_compression&lt;/span&gt;&lt;span class="p"&gt;( $chars ) {&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$chars&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/(.)\g1+/ length( $&amp;amp; ) . $1 /&lt;/span&gt;&lt;span class="nv"&gt;egr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The BONUS implementation is even easier, because we don't need any backreferences. We simply capture an integer number and the (non-number) character that follows it, and replace it by the character repeated  times. The Perl &lt;code&gt;x&lt;/code&gt; operator is probably the easiest and best way to do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;string_uncompress&lt;/span&gt;&lt;span class="p"&gt;( $chars ) {&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$chars&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/(\d+)(\D)/ $2 x $1 /&lt;/span&gt;&lt;span class="nv"&gt;egr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Task 2: Matchstick Square
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an array of integers, @ints.&lt;br&gt;
Write a script to find if it is possible to make one square using the sticks as in the given array @ints where $ints[ì] is the length of ith stick.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (1, 2, 2, 2, 1)
Output: true
Top: $ints[1] = 2
Bottom: $ints[2] = 2
Left: $ints[3] = 2
Right: $ints[0] and $ints[4] = 2
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (2, 2, 2, 4)
Output: false
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (2, 2, 2, 2, 4)
Output: false
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 4&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (3, 4, 1, 4, 3, 1)
Output: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The simple solution reaches the limits too soon
&lt;/h3&gt;

&lt;p&gt;My first, simple solution uses the CPAN &lt;code&gt;Algorithm::Combinatorics&lt;/code&gt; module. It contains a &lt;code&gt;partitions&lt;/code&gt; function, which generates all possible subsets of a given set of numbers (our matchsticks). It can be parameterized to return exactly four subsets (for the four sides of our square).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;builtin&lt;/span&gt; &lt;span class="sx"&gt;qw( true false )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="sx"&gt;qw( sum all )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Algorithm::&lt;/span&gt;&lt;span class="nv"&gt;Combinatorics&lt;/span&gt; &lt;span class="sx"&gt;qw( partitions )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;matchstick_square_AC&lt;/span&gt;&lt;span class="p"&gt;( @ints ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;
        &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="nv"&gt;$total&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$side_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$p&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;partitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;@ints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@sums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="nv"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;$p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;all&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$side_length&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;@sums&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works for the examples, and the solution is short.&lt;/p&gt;

&lt;p&gt;But generating &lt;em&gt;all&lt;/em&gt; possible sets, we have to throw most of them away because already the first one doesn't give us the needed side length of the square.&lt;br&gt;
For bigger numbers of matchsticks, the memory for keeping all the partitions gets really high.&lt;br&gt;
For 15 matchsticks, on my server the process runs out of memory already.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;partitions&lt;/code&gt; function can also return an iterator (when used in scalar context), so that we don't need the memory to store all possible partitions at the same time.&lt;br&gt;
For the same number of matchsticks, the memory footprint then stays low, but the run time is at around four minutes already.&lt;/p&gt;

&lt;p&gt;This is an easy solution, but it doesn't make my programmer's heart happy.&lt;/p&gt;
&lt;h3&gt;
  
  
  My own 'target sum' iterator
&lt;/h3&gt;

&lt;p&gt;I therefore did a second solution, based on these thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The sum of the matchstick lengths has to be divisible by 4. If not, it will be impossible to distribute them to four equal sides.&lt;/li&gt;
&lt;li&gt;The length of one side then is that sum divided by four.
&lt;/li&gt;
&lt;li&gt;For the first side of the square, we select groups of matchsticks &lt;em&gt;that have the correct length&lt;/em&gt; for that side. This is much less complex than finding all combinations of four groups that &lt;em&gt;all&lt;/em&gt; have the correct length.
It removes a lot of useless tries much earlier. &lt;/li&gt;
&lt;li&gt;For the second and third side, we do the same, based on the matchsticks remaining from the previous step.&lt;/li&gt;
&lt;li&gt;For the fourth side, the remaining matchsticks automatically sum up to the right length.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this solution is based on finding groups of numbers that sum up exactly to a given target number (our side length).&lt;/p&gt;

&lt;p&gt;We can implement a function to do that any way we want. I will be using a simple tree traversal algorithm.&lt;/p&gt;

&lt;p&gt;My implementation will be an iterator, in order to avoid memory problems for storing all the combinations (even there will be much less combinations than in the previous solution!).&lt;/p&gt;

&lt;p&gt;The skeleton of that function and its usage can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;get_exactly&lt;/span&gt;&lt;span class="p"&gt;( $target_sum, $ints ) {&lt;/span&gt;
    &lt;span class="c1"&gt;# Setup the closure data.&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;# Return the iterator function.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$used&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rest&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;# array_refs&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$side_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;get_exactly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$side_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$used&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rest&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$iterator&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# Here, the sum of the numbers in $used-&amp;gt;@* equal $side_length,&lt;/span&gt;
    &lt;span class="c1"&gt;# and $rest-&amp;gt;@* are the remaining (unused) numbers.&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That makes this main function possible for solving the task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;builtin&lt;/span&gt; &lt;span class="sx"&gt;qw( true false )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="sx"&gt;qw( sum )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;matchstick_square&lt;/span&gt;&lt;span class="p"&gt;( @ints ) {&lt;/span&gt;

    &lt;span class="c1"&gt;# The total sum of the matchstick lengths must be divisible by 4.&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$total_sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$total_sum&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;vsay&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;total sum( &lt;/span&gt;&lt;span class="si"&gt;$total&lt;/span&gt;&lt;span class="s2"&gt; ) is not divisible by 4&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$side_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$total_sum&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# Get a combination for the first side of the square.&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$iterator_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;get_exactly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$side_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;@ints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$used_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rest_1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$iterator_1&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# We got a combination for the first side.&lt;/span&gt;
        &lt;span class="c1"&gt;# Use the remaining matchsticks to get a combination&lt;/span&gt;
        &lt;span class="c1"&gt;# for the second side.&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$iterator_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;get_exactly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$side_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rest_1&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$used_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rest_2&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$iterator_2&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;# ... and the same for the third side.&lt;/span&gt;
            &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$iterator_3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;get_exactly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$side_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rest_2&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$used_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rest_3&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$iterator_3&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;# Here, we have found combinations for three sides.&lt;/span&gt;
                &lt;span class="c1"&gt;# The remaining matchsticks automatically sum up to&lt;/span&gt;
                &lt;span class="c1"&gt;# the correct length of the fourth side.&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;# No combination found.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it still remains to implement the &lt;code&gt;get_exactly&lt;/code&gt; iterator.&lt;/p&gt;

&lt;p&gt;As I said before, I am using a tree traversal algorithm. In fact, it is a 'breadth first search' (BFS). It is based on a queue of possible continuations, that are processed within a loop until the queue runs empty. Every entry in the queue carries some context data, to be able to process that queue entry when it its turn. The context consists of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;    &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$used&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$next_index&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the loop, if the end condition is met (&lt;code&gt;$sum == $target_sum&lt;/code&gt;), we return that combination (the &lt;code&gt;$used&lt;/code&gt; and &lt;code&gt;$rest&lt;/code&gt; array_refs).&lt;br&gt;
If not, we loop through the remaining numbers in the array that &lt;code&gt;$rest&lt;/code&gt; references, starting from the number at &lt;code&gt;$next_index&lt;/code&gt; (to not repeat number that we have already tried). We add a candidate combination to the queue that includes that number, by creating a new context for it. If a number would exceed the target sum, we just skip it.&lt;/p&gt;

&lt;p&gt;That means that all candidate combination in the queue are either smaller than or exactly equal to the target sum.&lt;/p&gt;

&lt;p&gt;So here it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;get_exactly&lt;/span&gt;&lt;span class="p"&gt;( $target_sum, $ints ) {&lt;/span&gt;
    &lt;span class="c1"&gt;# Initialize the closure data for the iterator&lt;/span&gt;
    &lt;span class="c1"&gt;# ( $used, $sum, $rest, $next_index ).&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;# Return the iterator function.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# Check whether we have reached the end before.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="nv"&gt;@queue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;# Find the next matching combination.&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;@queue&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$used&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$next_index&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt; &lt;span class="nv"&gt;@queue&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="c1"&gt;# dsay ":queue", pp ( $used, $sum, $rest, $start_index );&lt;/span&gt;

            &lt;span class="c1"&gt;# Check the success criteria and return if it is met.&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$used&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$rest&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$sum&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$target_sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;# If not, add more candidates.&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$next_index&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$rest&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="c1"&gt;#* ) {&lt;/span&gt;
                &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$rest&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$new_used&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$used&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
                &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$new_sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$new_rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="nv"&gt;$rest&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="nv"&gt;$rest&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$rest&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="c1"&gt;#* ],&lt;/span&gt;
                &lt;span class="p"&gt;];&lt;/span&gt;
                &lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="nv"&gt;@queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$new_used&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$new_sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$new_rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$new_sum&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$target_sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;# End of the list.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For testing, I create random lists of 15 or 20 or 25 numbers (choosing quite big numbers, so that they don't combine well, and there will be no solution).&lt;/p&gt;

&lt;p&gt;The first solution worked for around 4 minutes for a set of 15 matchsticks. I didn't try more then.&lt;/p&gt;

&lt;p&gt;My 'target sum' solution does that in less than 0.1 seconds!&lt;br&gt;
It takes less than 3 seconds for a set of 20, and less than 5 seconds for 25.&lt;/p&gt;

&lt;p&gt;Now that makes me happier...!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Thank you for the challenge!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Find the complete source code for both tasks, including tests and alternative solution implementations, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-296/challenge-296/matthias-muth#readme" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>pwc</category>
      <category>weeklychallenge</category>
      <category>challenge296</category>
    </item>
    <item>
      <title>Jump, but Don't Break the Game (PWC 295)</title>
      <dc:creator>Matthias Muth</dc:creator>
      <pubDate>Sun, 17 Nov 2024 22:28:51 +0000</pubDate>
      <link>https://dev.to/muthm/jump-but-dont-break-the-game-pwc-295-2i34</link>
      <guid>https://dev.to/muthm/jump-but-dont-break-the-game-pwc-295-2i34</guid>
      <description>&lt;p&gt;These are my solutions in Perl &lt;br&gt;
for &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-295" rel="noopener noreferrer"&gt;Challenge 295&lt;/a&gt;  Tasks 1 and 2 of &lt;a href="https://theweeklychallenge.org/" rel="noopener noreferrer"&gt;The Weekly Challenge - Perl and Raku&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Task 1: Word Break.&lt;/strong&gt;&lt;br&gt;
A simple regular expression, built from the word list, delivers the solution. Very short, very nice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task 2: Jump Game&lt;/strong&gt;&lt;br&gt;
Implementing an unspectacular 'breadth first search' (BFS) algorithm.&lt;/p&gt;
&lt;h2&gt;
  
  
  Task 1: Word Break
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given a string, $str, and list of words, &lt;a class="mentioned-user" href="https://dev.to/words"&gt;@words&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Write a script to return true or false whether the given string can be segmented into a space separated sequnce of one or more words from the given list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: $str = 'weeklychallenge', @words = ("challenge", "weekly")
Output: true
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: $str = "perlrakuperl", @words = ("raku", "perl")
Output: true
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: $str = "sonsanddaughters", @words = ("sons", "sand", "daughters")
Output: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;We need to recognize words from the input word list in the string, making sure that after each recognized word, another word from the list begins.&lt;/p&gt;

&lt;p&gt;That means we are checking whether the string is a &lt;em&gt;sequence of one or more words&lt;/em&gt; from the list.&lt;br&gt;
Wait a second...! Checking '&lt;em&gt;one or more&lt;/em&gt;' occurrences of something in a string?&lt;br&gt;
What could be easier than using a regular expression for that?&lt;br&gt;
The 'one or more' part directly translates to a &lt;code&gt;+&lt;/code&gt; quantifier.&lt;/p&gt;

&lt;p&gt;And the pattern? We form it as a list of alternatives, using the &lt;code&gt;'|'&lt;/code&gt; character do separate the choices.&lt;/p&gt;

&lt;p&gt;Then, we only have to match the string against our pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;word_break&lt;/span&gt;&lt;span class="p"&gt;( $str, $words ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;|&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nv"&gt;$words&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^($pattern)+$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was an easy one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 2: Jump Game
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an array of integers, @ints.&lt;/p&gt;

&lt;p&gt;Write a script to find the minimum number of jumps to reach the last element.&lt;br&gt;
$ints[$i] represents the maximum length of a forward jump from the index $i.&lt;br&gt;
In case last element is unreachable then return -1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (2, 3, 1, 1, 4)
Output: 2
Jump 1 step from index 0 then 3 steps from index 1 to the last element.
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (2, 3, 0, 4)
Output: 2
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt; &lt;br&gt;&lt;strong&gt;Example 3&lt;/strong&gt;&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: @ints = (2, 0, 0, 4)
Output: -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Now this one requires some 'real programming'(tm).&lt;/p&gt;

&lt;p&gt;First, let's get clear about the game mechanics. The description says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;$ints[$i] represents the maximum length of a forward jump from the index $i.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we take &lt;code&gt;$ints[$i] == 3&lt;/code&gt; as an example, that means that we can choose to jump to &lt;code&gt;$i+1&lt;/code&gt;, &lt;code&gt;$i+2&lt;/code&gt; or &lt;code&gt;$i+3&lt;/code&gt; in that move.&lt;br&gt;
For each of those, the next move continues with the number that we find there.&lt;/p&gt;

&lt;p&gt;Trying all possible combinations from the first entry in the list is like building a tree of possible paths. The root node is &lt;code&gt;$int[0]&lt;/code&gt;. From there, there is one outgoing branch for every possible jump from there.&lt;/p&gt;

&lt;p&gt;To find the 'shortest path' to the last entry, we need to find the shortest path in that tree that leads to a node with the index value of the last entry.&lt;/p&gt;

&lt;p&gt;Finding the shortest path in a tree is typically done using a 'breadth first search' (or 'BFS') algorithm. All of the nodes on the same level ('breadth') are checked before any nodes on higher levels. So if one fulfils the end condition (here: it's the index of the last entry in the list), it's garanteed that there are no shorter paths.&lt;/p&gt;

&lt;p&gt;A BFS algorithm is not difficult to set up:&lt;br&gt;
We use a queue for the nodes to check.&lt;br&gt;
For the queue entries, we use two-element anonymous arrays, containing the index value, and the length of the path that was needed to reach that node. That makes it easy to return the correct result once we find the shortest path.&lt;/p&gt;

&lt;p&gt;We initialize our queue with the index of the first number in the list (which is &lt;code&gt;0&lt;/code&gt;, of course), and the number of jumps needed to get there (&lt;code&gt;0&lt;/code&gt;, too!).&lt;br&gt;
This represents the starting point of our tree.&lt;/p&gt;

&lt;p&gt;Then we loop over the entries in the queue.&lt;br&gt;
For each entry, we check whether it meets the end condition, and return the path length if it does. Done.&lt;/p&gt;

&lt;p&gt;If we haven't reached the last entry yet, we add the next level of possible moves to the queue, making sure we don't add jumps that end beyond the end of the list.&lt;br&gt;
The path length for these new queue entries is one higher than the one that we have so far.&lt;/p&gt;

&lt;p&gt;If the queue runs empty, there is no possible path that reaches the last entry. We return the &lt;code&gt;-1&lt;/code&gt; as we should in that case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;jump_game&lt;/span&gt;&lt;span class="p"&gt;( @ints ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$n_jumps&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$n_jumps&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;@queue&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$n_jumps&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt; &lt;span class="nv"&gt;@queue&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;@*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$n_jumps&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$#ints&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="nv"&gt;@queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$n_jumps&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$#ints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nb"&gt;reverse&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This BFS does not need a 'visited' structure to avoid running into circles. As we only move forward in the list, we don't need to fear running into that problem at all.&lt;/p&gt;

&lt;p&gt;I have also created a solution using the &lt;code&gt;Algorithm::Functional::BFS&lt;/code&gt; module from CPAN. It hides all the mechanics of the BFS algorithm and uses a functional approach: there are code blocks handed in to the search function, for checking whether a node meets the the end criteria, and for getting the list of successor nodes for a node. These are the only two variable parts of the algorithm.&lt;/p&gt;

&lt;p&gt;In fact I found that the code is not significantly shorter when I use that module, because we need to supply the code blocks as parameters, and also set some parameters. So I am quite ok with having written it myself.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Thank you for the challenge!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Find the complete source code for both tasks, including tests and alternative solution implementations, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-295/challenge-295/matthias-muth#readme" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>pwc</category>
      <category>perlweeklychallenge</category>
      <category>challenge295</category>
    </item>
    <item>
      <title>Consecutive Sequences of Permutations, Anyone? (PWC 294)</title>
      <dc:creator>Matthias Muth</dc:creator>
      <pubDate>Sun, 10 Nov 2024 23:29:25 +0000</pubDate>
      <link>https://dev.to/muthm/consecutive-sequences-of-permutations-anyone-pwc-294-2dbf</link>
      <guid>https://dev.to/muthm/consecutive-sequences-of-permutations-anyone-pwc-294-2dbf</guid>
      <description>&lt;p&gt;&lt;strong&gt;Challenge 294 solutions in Perl by Matthias Muth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These are my &lt;a href="https://theweeklychallenge.org/blog/perl-weekly-challenge-294/#TASK1" rel="noopener noreferrer"&gt;Challenge 294 Task 1 and 2&lt;/a&gt; solutions in Perl&lt;br&gt;
for &lt;a href="https://theweeklychallenge.org/" rel="noopener noreferrer"&gt;The Weekly Challenge - Perl and Raku&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Task 1: Consecutive Sequences&lt;/strong&gt;&lt;br&gt;


&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 solution using a small data structure and a lookup hash to keep track of 'streaks' (consecutive sequences) and to merge them with new numbers as they are processed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task 2: Next Permutation&lt;/strong&gt;&lt;br&gt;
Working 'locally' to flip numbers to get the next permutation, without the need to create all permutations first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;:&lt;br&gt;
Find the complete source code for both tasks, including more tests, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-294/challenge-294/matthias-muth#readme" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Task 1: Consecutive Sequence
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an unsorted array of integers, @ints.&lt;br&gt;
Write a script to return the length of the longest consecutive elements sequence. Return -1 if none found. The algorithm must runs in O(n) time.&lt;/p&gt;

&lt;p&gt;Example 1&lt;br&gt;
Input: @ints = (10, 4, 20, 1, 3, 2)&lt;br&gt;
Output: 4&lt;br&gt;
The longest consecutive sequence (1, 2, 3, 4).&lt;br&gt;
The length of the sequence is 4.&lt;/p&gt;

&lt;p&gt;Example 2&lt;br&gt;
Input: @ints = (0, 6, 1, 8, 5, 2, 4, 3, 0, 7)&lt;br&gt;
Output: 9&lt;/p&gt;

&lt;p&gt;Example 3&lt;br&gt;
Input: @ints = (10, 30, 20)&lt;br&gt;
Output: -1&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Oh. Big Oh. 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n)  &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
!&lt;/p&gt;

&lt;p&gt;This restriction means that the simplest solution, sorting the array and then walking through the ordered numbers, is &lt;em&gt;not&lt;/em&gt; allowed. That's because &lt;code&gt;sort&lt;/code&gt; has an 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(nlog⁡n)O(n \log{} n) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mop"&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 time complexity.&lt;/p&gt;

&lt;p&gt;So what we &lt;em&gt;are&lt;/em&gt; allowed to do for 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is to walk through the array. As long as we don't use another loop within a loop, we can even walk through the array several times. This only means that the runtime spent for each number is slightly higher, but this still scales &lt;em&gt;linearly&lt;/em&gt; with rising 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;nn &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. Actually 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(2n)O(2n) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is the same as 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n)&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/p&gt;

&lt;p&gt;In fact I &lt;em&gt;do&lt;/em&gt; walk through the data twice! I use &lt;code&gt;uniq&lt;/code&gt; on the input data, as a first pass (Example 2 contains a &lt;code&gt;0&lt;/code&gt; twice!). I do this to make sure that double entries do not disturb the detection of sequences.&lt;/p&gt;

&lt;p&gt;Let's call a 'consecutive sequence' a 'streak' for short.&lt;br&gt;
We need to build up the 'streaks' as we encounter the numbers, one by one.&lt;br&gt;
The data structure I use for representing a streak is a simple hash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;    &lt;span class="nv"&gt;$streak&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;TO&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a new number is encountered, I try to merge that number with any streak that already exists at the number's immediate left or immediate right.&lt;/p&gt;

&lt;p&gt;For knowing whether those neighboring streaks already exists , I keep a lookup hash, &lt;code&gt;%streaks&lt;/code&gt;. For every streak I create, I put a reference to the streak's data structure into that lookup hash, one with its starting number as the key, and one with its ending number. Thus, to access the left and right neighboring streaks for any new number &lt;code&gt;$n&lt;/code&gt;, I only need to check &lt;code&gt;$streaks{ $n - 1 }&lt;/code&gt; and &lt;code&gt;$streaks{ $n + 1 }&lt;/code&gt;.. And once I have those, I know their 'other ends': the left streak's starting number, and the right streak's ending number. I then can create a new streak that covers them all, the left streak, the new number, and the right streak (if they exist, that is).&lt;/p&gt;

&lt;p&gt;What is left to do then is to update the lookup table. I delete any references to the left and right streaks that will not be needed anymore, and I store references to the merged streak in the lookup hash at its starting and ending numbers.&lt;/p&gt;

&lt;p&gt;For returning the length of the longest streak in the end, I check whether the new one is longer than what we already have, and update accordingly.&lt;/p&gt;

&lt;p&gt;I have left the comments inside the code to make it easier to follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="sx"&gt;qw( uniq )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;consecutive_sequence_using_hash&lt;/span&gt;&lt;span class="p"&gt;( @ints ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$max_streak_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%streaks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;uniq&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# Create a new streak from this number,&lt;/span&gt;
        &lt;span class="c1"&gt;# possibly merged with any existing adjacent streaks&lt;/span&gt;
        &lt;span class="c1"&gt;# to the left or to the right.&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$right&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$streaks&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nv"&gt;$streaks&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$left&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$left&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;FROM&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$right&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$right&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;TO&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$streak&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;TO&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="c1"&gt;# Update the lookup entries:&lt;/span&gt;
        &lt;span class="c1"&gt;# Remove any entries that are *inside* the merged streak,&lt;/span&gt;
        &lt;span class="c1"&gt;# and add or update entries at the streak borders.&lt;/span&gt;
        &lt;span class="nb"&gt;delete&lt;/span&gt; &lt;span class="nv"&gt;$streaks&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$left&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;TO&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;delete&lt;/span&gt; &lt;span class="nv"&gt;$streaks&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$right&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;FROM&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$streaks&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$streaks&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$streak&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;# Update the maximum length if this is a streak&lt;/span&gt;
        &lt;span class="c1"&gt;# (not just a single number) and it's longer than what we have.&lt;/span&gt;
        &lt;span class="nv"&gt;$max_streak_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$from&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$max_streak_length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$max_streak_length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No loops inside!&lt;br&gt;
I think this is proper 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n) &lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 solution.&lt;/p&gt;
&lt;h2&gt;
  
  
  Task 2: Next Permutation
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an array of integers, @ints.&lt;br&gt;
Write a script to find out the next permutation of the given array.&lt;br&gt;
The next permutation of an array of integers is the next lexicographically greater permutation of its integer.&lt;/p&gt;

&lt;p&gt;Example 1&lt;br&gt;
Input: @ints = (1, 2, 3)&lt;br&gt;
Output: (1, 3, 2)&lt;br&gt;
Permutations of (1, 2, 3) arranged lexicographically:&lt;br&gt;
(1, 2, 3)&lt;br&gt;
(1, 3, 2)&lt;br&gt;
(2, 1, 3)&lt;br&gt;
(2, 3, 1)&lt;br&gt;
(3, 1, 2)&lt;br&gt;
(3, 2, 1)&lt;/p&gt;

&lt;p&gt;Example 2&lt;br&gt;
Input: @ints = (2, 1, 3)&lt;br&gt;
Output: (2, 3, 1)&lt;/p&gt;

&lt;p&gt;Example 3&lt;br&gt;
Input: @ints = (3, 1, 2)&lt;br&gt;
Output: (3, 2, 1)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A simple, but compute-intensive solution would be to create &lt;em&gt;all&lt;/em&gt; permutations of the numbers involved, then sort them ('lexicographically'), then find the entry that corresponds to the permutation that is given, and then return the next one.&lt;br&gt;
Actually I don't like this approach too much, because in my experience, anything that has to do with permutations or combinations has a tendency to use a lot of time , or a lot of memory, or both, very fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's find a solution that works 'locally'!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to modify an existing permutation to the next higher one, we need to find the number with the lowest significance that can be increased.&lt;br&gt;
That means that we start at the right end (least significant), and find the first number that is lower than its right neighbor. All numbers at the right of that are ordered, highest first, so they can't be 'incremented'.&lt;/p&gt;

&lt;p&gt;What if we &lt;em&gt;didn't&lt;/em&gt; find any number that is lower than its right neighbor?&lt;br&gt;
In that case, all numbers are ordered, highest first. This must be the last permutation possible. Which means that the next permutation will restart from the beginning of the cycle of all permutations.&lt;br&gt;
In the first permutation, the numbers are ordered lowest first. To get there, we can just &lt;em&gt;reverse&lt;/em&gt; that highest permutation sequence of numbers, and we can return that as the result.&lt;/p&gt;

&lt;p&gt;If that's not the case, and we do have found a number that can be 'incremented', we need to find the next higher number to replace this number with.&lt;br&gt;
We only look in the right part of the permutation, because using any number from further left would change the order more than we want.&lt;br&gt;
We are looking for the lowest possible number that still is higher than our number.&lt;/p&gt;

&lt;p&gt;Once we have found that replacement number, we exchange the two numbers.&lt;br&gt;
We then have 'increased' our number by the next possible higher value of all permutations of the right part. At the same time, we have decreased the replacement number to the next possible lower number. So the ordering of the right part thus still is 'highest to lowest'. As we need the 'first' permutation of the right part, we can just reverse this.&lt;/p&gt;

&lt;p&gt;That's it! We have found the lowest possible increment.&lt;/p&gt;

&lt;p&gt;Again, I have left the comments in the code for easier following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;next_permutation&lt;/span&gt;&lt;span class="p"&gt;( @ints ) {&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;# Starting from the end, find the first number&lt;/span&gt;
    &lt;span class="c1"&gt;# that is lower than the one following it.&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$#ints&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;gt&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# Everything is in the loop condition.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# No lower number found?&lt;/span&gt;
    &lt;span class="c1"&gt;# Then we are at the end of the permutations.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;reverse&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;# Find the next highest value within the right part,&lt;/span&gt;
    &lt;span class="c1"&gt;# for using it to replace the current value.&lt;/span&gt;
    &lt;span class="c1"&gt;# (Remember that maybe not all values in the right part are higher!)&lt;/span&gt;
    &lt;span class="c1"&gt;# It has to be higher than the one to substitute, but the&lt;/span&gt;
    &lt;span class="c1"&gt;# lowest possible one.&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$index_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$replacement&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$index_2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$#ints&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$index_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$replacement&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="ow"&gt;lt&lt;/span&gt; &lt;span class="nv"&gt;$ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;lt&lt;/span&gt; &lt;span class="nv"&gt;$replacement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Swap the two numbers.&lt;/span&gt;
    &lt;span class="nv"&gt;@ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$index_2&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$index_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;# We know that the right side is sorted, highest first.&lt;/span&gt;
    &lt;span class="c1"&gt;# to have it sorted lowest first, we just need to reverse it.&lt;/span&gt;
    &lt;span class="nv"&gt;@ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$#ints&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nb"&gt;reverse&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nv"&gt;$#ints&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;@ints&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run this several times in a row, we will get a 'consecutive sequence of permutations'.&lt;br&gt;
How nice for the title of this blog, combining the two tasks!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Thank you for the challenge!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Find the complete source code for both tasks, including tests, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-294/challenge-294/matthias-muth#readme" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>pwc</category>
      <category>perlweeklychallenge</category>
      <category>challenge294</category>
    </item>
    <item>
      <title>Domino Frequencies and the Vectorized Boomerang (PWC 293)</title>
      <dc:creator>Matthias Muth</dc:creator>
      <pubDate>Thu, 31 Oct 2024 23:12:18 +0000</pubDate>
      <link>https://dev.to/muthm/domino-frequencies-and-the-vectorized-boomerang-4j5a</link>
      <guid>https://dev.to/muthm/domino-frequencies-and-the-vectorized-boomerang-4j5a</guid>
      <description>&lt;p&gt;&lt;strong&gt;Challenge 293 solutions in Perl by Matthias Muth&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Similar Dominos&lt;/strong&gt;:&lt;br&gt;
Two lines of code to compute frequencies of Domino value combinations&lt;br&gt;
and then to sum them up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Boomerang&lt;/strong&gt;:&lt;br&gt;
Thank you for helping me to get a refresher in vector geometry!&lt;br&gt;
It only needs two formulas and one comparison for checking whether the input points form a 'boomerang', using integer arithmetics only (no divisions, no square roots).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;:&lt;br&gt;
Find the complete source code for both tasks, including tests, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-293/challenge-293/matthias-muth#readme" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Task 1: Similar Dominos
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given a list of dominos, @dominos.&lt;br&gt;
Write a script to return the number of dominos that are similar to any other domino.&lt;br&gt;
$dominos[i] = [a, b] and $dominos[j] = [c, d] are same if either (a = c and b = d) or (a = d and b = c).&lt;/p&gt;

&lt;p&gt;Example 1&lt;br&gt;
Input: @dominos = ([1, 3], [3, 1], [2, 4], [6, 8])&lt;br&gt;
Output: 2&lt;br&gt;
Similar Dominos: $dominos[0], $dominos[1]&lt;/p&gt;

&lt;p&gt;Example 2&lt;br&gt;
Input: @dominos = ([1, 2], [2, 1], [1, 1], [1, 2], [2, 2])&lt;br&gt;
Output: 3&lt;br&gt;
Similar Dominos: $dominos[0], $dominos[1], $dominos[3]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My thinking process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For counting the number of &lt;em&gt;similar&lt;/em&gt; dominos, we can first count for each distinct value combination how often it exists, and then sum up the numbers of those that exist more than once.&lt;/li&gt;
&lt;li&gt;Counting how often each value combination exists is the same as getting their &lt;em&gt;frequencies&lt;/em&gt;. That's something we've done quite often before.
In Perl typically a hash is used, with the domino combination as the key, and the frequency as the value.
Today, I will let &lt;code&gt;List::MoreUtils&lt;/code&gt; do the job of creating the frequency hash.
Less typing ;-).&lt;/li&gt;
&lt;li&gt;To use the two numbers on a domino as a key, we have to combine them into a string.
Let's &lt;code&gt;join&lt;/code&gt; the two numbers with a separator (like &lt;code&gt;'-'&lt;/code&gt;) in between them.&lt;/li&gt;
&lt;li&gt;A combination and its inverse (like &lt;code&gt;[3, 1]&lt;/code&gt; and &lt;code&gt;[1, 3]&lt;/code&gt;) should be considered as being equal. They need to be mapped to the same key. To get that, it's easiest to just &lt;code&gt;sort&lt;/code&gt; the two numbers (even if there are only two of them) before turning them into a key string.
Both dominos &lt;code&gt;[3, 1]&lt;/code&gt; and &lt;code&gt;[1, 3]&lt;/code&gt; will then be counted using  &lt;code&gt;"1-3"&lt;/code&gt; as the key.&lt;/li&gt;
&lt;li&gt;The type of sort (numerical or lexical, ascending or descending) does not matter at all, it is only important that the result is the same if the input is in reversed order.
The default lexical sort will therefore do nicely.&lt;/li&gt;
&lt;li&gt;Once we have the frequencies, we add them up, but we exclude those having a frequency of 1. (The frequencies are in the &lt;code&gt;values&lt;/code&gt; of the frequency hash.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My solution then is this little program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;MoreUtils&lt;/span&gt; &lt;span class="sx"&gt;qw( frequency )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="sx"&gt;qw( sum )&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;similar_dominos&lt;/span&gt;&lt;span class="p"&gt;( $dominos ) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%frequencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;$dominos&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;values&lt;/span&gt; &lt;span class="nv"&gt;%frequencies&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;use v5.36;&lt;/code&gt; is short for getting subroutine signatures and automatic &lt;code&gt;strict&lt;/code&gt; and &lt;code&gt;warnings&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;I love how Perl makes this easy. &lt;/p&gt;

&lt;h2&gt;
  
  
  Task 2: Boomerang
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an array of points, (x, y).&lt;br&gt;
Write a script to find out if the given points are a boomerang.&lt;br&gt;
A boomerang is a set of three points that are all distinct and not in a straight line.&lt;/p&gt;

&lt;p&gt;Example 1&lt;br&gt;
Input: @points = ( [1, 1], [2, 3], [3,2] )&lt;br&gt;
Output: true&lt;/p&gt;

&lt;p&gt;Example 2&lt;br&gt;
Input: @points = ( [1, 1], [2, 2], [3, 3] )&lt;br&gt;
Output: false&lt;/p&gt;

&lt;p&gt;Example 3&lt;br&gt;
Input: @points = ( [1, 1], [1, 2], [2, 3] )&lt;br&gt;
Output: true&lt;/p&gt;

&lt;p&gt;Example 4&lt;br&gt;
Input: @points = ( [1, 1], [1, 2], [1, 3] )&lt;br&gt;&lt;br&gt;
Output: false&lt;/p&gt;

&lt;p&gt;Example 5&lt;br&gt;
Input: @points = ( [1, 1], [2, 1], [3, 1] )&lt;br&gt;
Output: false&lt;/p&gt;

&lt;p&gt;Example 6&lt;br&gt;
Input: @points = ( [0, 0], [2, 3], [4, 5] )&lt;br&gt;
Output: true&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We have the three input points&lt;br&gt;


&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;pi=(xiyi)∣i∈1…3\qquad \qquad
p_i = \begin{pmatrix}  x_i \\ y_i \end{pmatrix} |_{  i \in { 1 \dots 3 } }
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;p&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="minner"&gt;&lt;span class="mopen delimcenter"&gt;&lt;span class="delimsizing size3"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mtable"&gt;&lt;span class="col-align-c"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose delimcenter"&gt;&lt;span class="delimsizing size3"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;i&lt;/span&gt;&lt;span class="mrel mtight"&gt;∈&lt;/span&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;1&lt;/span&gt;&lt;span class="minner mtight"&gt;…&lt;/span&gt;&lt;span class="mord mtight"&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;br&gt;
My idea to solve this task is based on the two &lt;em&gt;vectors&lt;/em&gt; that we get&lt;br&gt;
when we connect these points:&lt;br&gt;

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;v=(x2−x1y2−y1)w=(x3−x2y3−y2)
\qquad \qquad
\mathbf{v} = \begin{pmatrix}  x_2 - x_1 \\ y_2 - y_1 \end{pmatrix} \qquad
\mathbf{w} = \begin{pmatrix}  x_3 - x_2 \\ y_3 - y_2 \end{pmatrix}
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathbf"&gt;v&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="minner"&gt;&lt;span class="mopen delimcenter"&gt;&lt;span class="delimsizing size3"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mtable"&gt;&lt;span class="col-align-c"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose delimcenter"&gt;&lt;span class="delimsizing size3"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathbf"&gt;w&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="minner"&gt;&lt;span class="mopen delimcenter"&gt;&lt;span class="delimsizing size3"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mtable"&gt;&lt;span class="col-align-c"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose delimcenter"&gt;&lt;span class="delimsizing size3"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/p&gt;

&lt;p&gt;For a 'boomerang', we then need to check whether the two vectors have the same direction.&lt;/p&gt;

&lt;p&gt;The reason why I'm using this 'vector' approach is that I hope to avoid any condition checking that would be necessary for the other possible approach: comparing the &lt;em&gt;slope&lt;/em&gt; of the line segments defined by the points. As the points can have the same 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;xx&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
-coordinate (like in Example 4), I would have to deal with possibly infinite slopes (vertical lines). And in any case with floating point numbers, which I always try to avoid if possible.&lt;br&gt;
Maybe my worries are exaggerated, but I also found it nice to get a little refresher in vector geometry!&lt;/p&gt;

&lt;p&gt;So going with the two vectors:&lt;br&gt;
I have re-learned (after around 50 years!) something about the &lt;em&gt;dot product&lt;/em&gt; (or &lt;em&gt;scalar product&lt;/em&gt;) of vectors.&lt;br&gt;
In the &lt;a href="https://en.wikipedia.org/wiki/Dot_product#Geometric_definition" rel="noopener noreferrer"&gt;Wikipedia article about the dot product&lt;/a&gt;, it says that if two vectors are &lt;em&gt;codirectional&lt;/em&gt;, their dot product is equal to the product of their magnitudes.&lt;br&gt;
That sounds complicated, but let's see what that means when we break it down.&lt;/p&gt;

&lt;p&gt;The 'dot product' is a scalar number, and for our two vectors&lt;br&gt;

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;v=(xvyv)w=(xwyw)
\qquad \qquad
\mathbf{v} = \begin{pmatrix} x_v \\ y_v \end{pmatrix} \qquad
\mathbf{w} = \begin{pmatrix} x_w \\ y_w \end{pmatrix}
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathbf"&gt;v&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="minner"&gt;&lt;span class="mopen delimcenter"&gt;&lt;span class="delimsizing size3"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mtable"&gt;&lt;span class="col-align-c"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose delimcenter"&gt;&lt;span class="delimsizing size3"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathbf"&gt;w&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="minner"&gt;&lt;span class="mopen delimcenter"&gt;&lt;span class="delimsizing size3"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mtable"&gt;&lt;span class="col-align-c"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose delimcenter"&gt;&lt;span class="delimsizing size3"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;br&gt;
it is simply computed like this:&lt;br&gt;

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;v⋅w=xvxw+yvyw
\qquad \qquad
\mathbf{v} \cdot \mathbf{w} = x_v x_w + y_v y_w
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathbf"&gt;v&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;⋅&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathbf"&gt;w&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/p&gt;

&lt;p&gt;The 'product of the magnitudes' of the two vectors is&lt;br&gt;

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;∥v∥ ∥w∥=xv2+yv2⋅xw2+yw2=(xv2+yv2) (xw2+yw2)
\qquad \qquad
    \| \mathbf{v} \| \, \| \mathbf{w} \|
        = \sqrt{ x_v^2 + y_v^2} \cdot \sqrt{x_w^2 + y_w^2}
        = \sqrt{ (x_v^2 + y_v^2) \, (x_w^2 + y_w^2)}
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∥&lt;/span&gt;&lt;span class="mord mathbf"&gt;v&lt;/span&gt;&lt;span class="mord"&gt;∥&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∥&lt;/span&gt;&lt;span class="mord mathbf"&gt;w&lt;/span&gt;&lt;span class="mord"&gt;∥&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord sqrt"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span class="svg-align"&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="hide-tail"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;⋅&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord sqrt"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span class="svg-align"&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="hide-tail"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord sqrt"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span class="svg-align"&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="hide-tail"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;br&gt;
The 'magnitude' of a vector is its length, and you recognize the Pythagorean theorem in the two-dimensional case here.&lt;/p&gt;

&lt;p&gt;For doing the 'boomerang check', we need to check whether those two are equal:&lt;br&gt;

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;xvxw+yvyw=(xv2+yv2) (xw2+yw2)
\qquad \qquad
    x_v x_w + y_v y_w
    = \sqrt{ (x_v^2 + y_v^2) \, (x_w^2 + y_w^2)}
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord sqrt"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span class="svg-align"&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="hide-tail"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/p&gt;

&lt;p&gt;To avoid floating point operations, and especially something as complicated as computing a square root, we use a trick and square both sides:&lt;br&gt;

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;(xvxw+yvyw)2=(xv2+yv2) (xw2+yw2)
\qquad \qquad
    ( x_v x_w + y_v y_w ) ^2
    = (x_v^2 + y_v^2) \, (x_w^2 + y_w^2)
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;x&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;br&gt;
Only integer arithmetics, not even a division in this one!&lt;/p&gt;

&lt;p&gt;Squaring both sides also has another positive (pun intended!) effect:&lt;br&gt;
If the two vectors have the same &lt;em&gt;direction&lt;/em&gt;, but a different &lt;em&gt;orientation&lt;/em&gt;&lt;br&gt;
(one is a &lt;em&gt;negative&lt;/em&gt; multiple of the other), their dot product is negative. Squaring both sides of the equation eliminates the negative sign, which is what we actually want.&lt;/p&gt;

&lt;p&gt;Now we have something that we can turn into code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.36&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;boomerang&lt;/span&gt;&lt;span class="p"&gt;( $points ) {&lt;/span&gt;
    &lt;span class="c1"&gt;# Create vectors connecting the points.&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$points&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$points&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="nv"&gt;$points&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$points&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$points&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$points&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="nv"&gt;$points&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$points&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;# Compute the dot product&lt;/span&gt;
    &lt;span class="c1"&gt;# and the *square* of the product of the magnitudes&lt;/span&gt;
    &lt;span class="c1"&gt;# (by not taking the square root).&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$dot_product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$mag_product_squared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$w&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;# Compare the two.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$dot_product&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nv"&gt;$mag_product_squared&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added some more tests for corner cases, like two of the three points being identical, or even all three of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ok 1 - Example 1: boomerang( [[1, 1], [2, 3], [3, 2]] ) is true
ok 2 - Example 2: boomerang( [[1, 1], [2, 2], [3, 3]] ) is false
ok 3 - Example 3: boomerang( [[1, 1], [1, 2], [2, 3]] ) is true
ok 4 - Example 4: boomerang( [[1, 1], [1, 2], [1, 3]] ) is false
ok 5 - Example 5: boomerang( [[1, 1], [2, 1], [3, 1]] ) is false
ok 6 - Example 6: boomerang( [[0, 0], [2, 3], [4, 5]] ) is true
ok 7 - Extra 1: boomerang( [[1, 1], [2, 1], [1, 1]] ) is false (points 1 and 3 identical)
ok 8 - Extra 2: boomerang( [[1, 1], [1, 1], [2, 1]] ) is false (points 1 and 2 identical)
ok 9 - Extra 3: boomerang( [[1, 1], [2, 1], [2, 1]] ) is false (points 2 and 3 identical)
ok 10 - Extra 4: boomerang( [[1, 1], [1, 1], [1, 1]] ) is false (all points identical)
1..10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Glad all the tests run successfully!&lt;/p&gt;

&lt;p&gt;Maybe next time dealing with vectors, I should try PDL!&lt;br&gt;
There's always something new to learn!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Thank you for the challenge!&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Find the complete source code for both tasks, including tests, on &lt;a href="https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-293/challenge-293/matthias-muth#readme" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>perlweeklychallenge</category>
      <category>pwc</category>
      <category>challenge293</category>
    </item>
  </channel>
</rss>
