perl logo Perl logo (Thanks to Olaf Alders)

The weekly challenge 333 - Task 1: Straight Line

  1 #!/usr/bin/env perl
  2 # https://theweeklychallenge.org/blog/perl-weekly-challenge-333/#TASK1
  3 #
  4 # Task 1: Straight Line
  5 # =====================
  6 #
  7 # You are given a list of co-ordinates.
  8 #
  9 # Write a script to find out if the given points make a straight line.
 10 #
 11 ## Example 1
 12 ##
 13 ## Input: @list = ([2, 1], [2, 3], [2, 5])
 14 ## Output: true
 15 #
 16 #
 17 ## Example 2
 18 ##
 19 ## Input: @list = ([1, 4], [3, 4], [10, 4])
 20 ## Output: true
 21 #
 22 #
 23 ## Example 3
 24 ##
 25 ## Input: @list = ([0, 0], [1, 1], [2, 3])
 26 ## Output: false
 27 #
 28 #
 29 ## Example 4
 30 ##
 31 ## Input: @list = ([1, 1], [1, 1], [1, 1])
 32 ## Output: true
 33 #
 34 #
 35 ## Example 5
 36 ##
 37 ## Input: @list = ([1000000, 1000000], [2000000, 2000000], [3000000, 3000000])
 38 ## Output: true
 39 #
 40 ############################################################
 41 ##
 42 ## discussion
 43 ##
 44 ############################################################
 45 #
 46 # Basically we need to calculate the slope of the potential straight line
 47 # from the first two points in the list. Then we need to calculate the slope
 48 # from the first point to each other point in the list and compare that to
 49 # the first slope. If it's always the same all points are on a straight line.
 50 # If it isn't then we found a point that isn't on the same straight line as
 51 # the first two points so we can return "false".
 52 # The rest is special case handling: If a point is the same as the first point
 53 # in the list it's on every straight line that crosses this point, so we are
 54 # fine. And if the x values are the same but the y values aren't then we are
 55 # on a vertical line so we can't calculate the slope due to division by zero.
 56 # While at it, we also do special handling for the case of a horizontal line
 57 # even though that wouldn't be necessary as the slope would just be 0.
 58 
 59 use v5.36;
 60 
 61 straight_line([2, 1], [2, 3], [2, 5]);
 62 straight_line([1, 4], [3, 4], [10, 4]);
 63 straight_line([0, 0], [1, 1], [2, 3]);
 64 straight_line([1, 1], [1, 1], [1, 1]);
 65 straight_line([1000000, 1000000], [2000000, 2000000], [3000000, 3000000]);
 66 
 67 sub straight_line(@list) {
 68     say "Input: (" . join(", ", map { "[$_->[0], $_->[1]]" } @list) . ")";
 69     my $direction = "";
 70     my $start = shift @list;
 71     my $slope;
 72     foreach my $point (@list) {
 73         if($point->[0] == $start->[0] and $point->[1] == $start->[1]) {
 74             # the same point again - it's always on the same line
 75             next;
 76         }
 77         if(defined($slope)) {
 78             if($slope eq "v" and $point->[0] == $start->[0]) {
 79                 # x value is the same for a vertical slope
 80                 next;
 81             }
 82             if($slope eq "h" and $point->[1] == $start->[1]) {
 83                 # y value is the same for a horizontal slope
 84                 next;
 85             }
 86             if($slope == ($point->[1] - $start->[1])/($point->[0] - $start->[0]) ) {
 87                 # slope to this point is the same as before, so we're on the same straight line
 88                 next;
 89             }
 90             return say "Output: false";
 91         } else {
 92             if($point->[0] == $start->[0]) {
 93                 $slope = "v";
 94             } elsif($point->[1] == $start->[1]) {
 95                 $slope = "h";
 96             } else {
 97                 $slope = ($point->[1] - $start->[1])/($point->[0] - $start->[0]);
 98             }
 99         }
100     }
101     say "Output: true";
102 }
103