Peter’s blog ✴ Week 123 ✴ 26 July 2021

THE WEEKLY CHALLENGE
Ugly and square

The Perl Camel

Task 2

Square points

You are given coordinates of four points: (x1, y1), (x2, y2), (x3, y3) and (x4, y4).

Write a script to find out if the given four points form a square.

Examples


Input: x1 = 10, y1 = 20
       x2 = 20, y2 = 20
       x3 = 20, y3 = 10
       x4 = 10, y4 = 10
Output: 1 as the given coordinates form a square.

Input: x1 = 12, y1 = 24
       x2 = 16, y2 = 10
       x3 = 20, y3 = 12
       x4 = 18, y4 = 16
Output: 0 as the given coordinates don't form a square.

Analysis

The points form a square if:

  • all four sides are equal length, and
  • both diagonals are sqrt(2) times the length of the sides.

It is not necessary that the sides of the square parallel the x and y axes - see my fourth example.

I am sorry that the 'Try it' feature is currently working very slowly or not at all owing to some issue with my web hosting provider.

Try it 

Try running the script with any input:



example: (1, 2), (2, 2), (2, 1), (1, 1)

Script


#!/usr/bin/perl

# Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use v5.26;    # The Weekly Challenge - 2021-07-26
use utf8;     # Week 123 - task 2 - Square points
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';
use Encode;

square_points(0, 0, 0, 2, 2, 2, 2, 0); # true
square_points(0, 0, 0, 2, 2, 2, 2, 3); # false
square_points(-2, 0, 0, 2, 2, 0, 0, -2); # true
square_points(-1, -1, 1, -1, 3, 1, 1, 1); # false
square_points(87, 34, 9, -44, 3, 61, 0, 77); # false

sub square_points {
    
    my (@p, $out, $side);
    
    # initialise
    @p = @_;
    
    # get length of side
    $side = dist($p[0], $p[1], $p[2], $p[3]);

    # other 3 sides the same and diagonals = sqrt(2) * side
    $out = (abs(dist($p[2], $p[3], $p[4], $p[5]) - $side) < 1e-5
        && abs(dist($p[4], $p[5], $p[6], $p[7]) - $side) < 1e-5
        && abs(dist($p[6], $p[7], $p[0], $p[1]) - $side) < 1e-5
        && abs(dist($p[0], $p[1], $p[4], $p[5]) - ($side * sqrt(2)) < 1e-5)
        && abs(dist($p[2], $p[3], $p[6], $p[7]) - ($side * sqrt(2)) < 1e-5))
        ? 1 : 0;
    
    say qq[\nInput:  ] . 
        sprintf('(%d, %d), (%d, %d), (%d, %d), (%d, %d)', @p);
    say qq[Output: $out];
}

# distance between 2 points
sub dist {
    my @p = @_;
    return sqrt(($p[0] - $p[2]) ** 2 + ($p[1] - $p[3]) ** 2);
}

16 lines of code
Completed after the closing date and not submitted to GitHub

Output from script



Input:  (0, 0), (0, 2), (2, 2), (2, 0)
Output: 1

Input:  (0, 0), (0, 2), (2, 2), (2, 3)
Output: 0

Input:  (-2, 0), (0, 2), (2, 0), (0, -2)
Output: 1

Input:  (-1, -1), (1, -1), (3, 1), (1, 1)
Output: 0

Input:  (87, 34), (9, -44), (3, 61), (0, 77)
Output: 0

Input:  (0, 0), (1, 0), (0, 0), (1, 0)
Output: 0

 

Any content of this website which has been created by Peter Campbell Smith is in the public domain