Straight Zeros
with Raku

by Arne Sommer

Straight Zeros with Raku

[357] Published 10. August 2025.

This is my response to The Weekly Challenge #333.

Challenge #333.1: Straight Line

You are given a list of co-ordinates.

Write a script to find out if the given points make a straight line.

Example 1:
Input: @list = ([2, 1], [2, 3], [2, 5])
Output: true
Example 2:
Input: @list = ([1, 4], [3, 4], [10, 4])
Output: true
Example 3:
Input: @list = ([0, 0], [1, 1], [2, 3])
Output: false
Example 4:
Input: @list = ([1, 1], [1, 1], [1, 1])
Output: true
Example 5:
Input: @list = ([1000000, 1000000], [2000000, 2000000],
                [3000000, 3000000])
Output: true

The five examples have three points, but the challenge text does not say that this is the case. So I have chosen to support an arbitrary number of points - with at least three.

File: straight-line
#! /usr/bin/env raku

unit sub MAIN (*@list where @list.elems > 2
                 && all(@list) ~~ /^\d+\,\d+$/,                 # [1]
               :v(:$verbose));

my ($Ax, $Ay) = @list.shift.split(",")>>.Int;                   # [2]
my ($Bx, $By) = @list.shift.split(",")>>.Int;                   # [3]

while @list                                                     # [4]
{
  my ($Cx, $Cy) = @list.shift.split(",")>>.Int;                 # [5]

  say ": Checking if ($Ax,$Ay), ($Bx,$By), ($Cx,$Cy) forms a triangle"
    if $verbose;
 
  if $Ax * ($By - $Cy) + $Bx * ($Cy - $Ay) + $Cx * ($Ay - $By)  # [6]
  {
    say ": trangle detected" if $verbose;
    say False;                                                  # [6a]
    exit;                                                       # [6b]
  }
}

say True;                                                       # [7]

[1] Ensure at least three points (or strings, rather).

[2] Get the first string, and extract the point coordinates Ax and Ay by splitting it on a comma. Then we coerce the two values to integers so that verbose mode looks better.

[3] Get the second string.

[4] As long as we have more points (no 3, 4 and so on) to process.

[5] Get the next string, and extract the third point for our comparison. We will get a new third point for each additional value in the input.

[6] Do we have a triangle, i.e. it has a non-zero area. If so, they are not on a straight line and we have faled. Say so and exit.

[7] Failure to fail means success. Say so.

I got the area formula from www.sciencing.com, but have dropped the final division by 2 as we are only checking for zero.

Running it:

$ ./straight-line "2,1" "2,3" "2,5"
True

$ ./straight-line "1,4" "3,4" "10,4"
True

$ ./straight-line "0,0" "1,1" "2,3"
False

$ ./straight-line "1,1" "1,1" "1,1"
True

$./straight-line "1000000,1000000" "2000000,2000000" "3000000,3000000"
True

Looking good.

With verbose mode:

$ ./straight-line -v "2,1" "2,3" "2,5"
: Checking if (2,1), (2,3), (2,5) forms a triangle
True

$ ./straight-line -v "1,4" "3,4" "10,4"
: Checking if (1,4), (3,4), (10,4) forms a triangle
True

$ ./straight-line -v "0,0" "1,1" "2,3"
: Checking if (0,0), (1,1), (2,3) forms a triangle
: trangle detected
False

$ ./straight-line -v "1,1" "1,1" "1,1"
: Checking if (1,1), (1,1), (1,1) forms a triangle
True

$./straight-line -v "1000000,1000000" "2000000,2000000" "3000000,3000000"
: Checking if (1000000,1000000), (2000000,2000000), (3000000,3000000) \
  forms a triangle
True

Some more, with more than three points:

$ ./straight-line -v "0,0" "1,1" "2,2" "3,3" "4,4" "5,5"
: Checking if (0,0), (1,1), (2,2) forms a triangle
: Checking if (0,0), (1,1), (3,3) forms a triangle
: Checking if (0,0), (1,1), (4,4) forms a triangle
: Checking if (0,0), (1,1), (5,5) forms a triangle
True

$ ./straight-line -v "0,0" "1,1" "2,2" "3,3" "4,4" "5,5" "60,6"
: Checking if (0,0), (1,1), (2,2) forms a triangle
: Checking if (0,0), (1,1), (3,3) forms a triangle
: Checking if (0,0), (1,1), (4,4) forms a triangle
: Checking if (0,0), (1,1), (5,5) forms a triangle
: Checking if (0,0), (1,1), (60,6) forms a triangle
: trangle detected
False

$ ./straight-line -v "0,0" "1,1" "2,2" "60,6" "3,3" "4,4" "5,5"
: Checking if (0,0), (1,1), (2,2) forms a triangle
: Checking if (0,0), (1,1), (60,6) forms a triangle
: trangle detected
False

Challenge #333.2: Duplicate Zeros

You are given an array of integers.

Write a script to duplicate each occurrence of zero, shifting the remaining elements to the right. The elements beyond the length of the original array are not written.

Example 1:
Input: @ints = (1, 0, 2, 3, 0, 4, 5, 0)
Output: (1, 0, 0, 2, 3, 0, 0, 4)

Each zero is duplicated.
Elements beyond the original length (like 5 and last 0) are discarded.
Example 2:
Input: @ints = (1, 2, 3)
Output: (1, 2, 3)

No zeros exist, so the array remains unchanged.
Example 3:
Input: @ints = (1, 2, 3, 0)
Output: (1, 2, 3, 0)
Example 4:
Input: @ints = (0, 0, 1, 2)
Output: (0, 0, 0, 0)
Example 5:
Input: @ints = (1, 2, 0, 3, 4)
Output: (1, 2, 0, 0, 3)
File: duplicate-zeroes
#! /usr/bin/env raku

unit sub MAIN (*@ints where @ints.elems > 0 && all(@ints) ~~ Int); # [1]

say @ints.map({ $_ ?? $_ !! (0,0) })[*;*][0 .. @ints.end];
# ## # 2 ######################### # 3 # # 4 ############

[1] Ensure at least one element, all of which must be integers.

[2] Use map to replace zeroes with (0,0) (a sublist with two zeroes), whilst non-zero values are left as is.

[3] The [*;*] construct flattens out the lists we added in [2], giving two zeroes instead of a (one) sublist containing two zeroes.

[4] This array slice takes the same number of elements as in the original array, from the start. The end call gives us the index of last item in the list. (You will get the same result with elems -1, but end is shorter.)

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

Running it:

$ ./duplicate-zeroes 1 0 2 3 0 4 5 0
(1 0 0 2 3 0 0 4)

$ ./duplicate-zeroes 1 2 3
(1 2 3)

$ ./duplicate-zeroes 1 2 3 0
(1 2 3 0)

3$ ./duplicate-zeroes 0 0 1 2
(0 0 0 0)

$ ./duplicate-zeroes 1 2 0 3 4
(1 2 0 0 3)

Looking good.

Verbose mode did not fit in the almost-one-liner format of the solution.

And that's it.