Home Posts Tags Post Search Tag Search

Post 45

Hacker Rank 19 - Is Convex?

Published on: 2025-06-29 Tags: elixir, Side Project, Hacker Rank
You are given the Cartesian coordinates of a set of points in a plane (in no particular order). Each of these points is a corner point of some Polygon, , which is not self-intersecting in nature. Can you determine whether or not is a concave polygon?

Sample Input
4
0 0
0 1  
1 1  
1 0

Sample Output
NO

Okay so for this one there was a few things that I wanted to do in order to find the right answer.

First I need to sort the points based of the centroid of the shape. To do that I needed to first find the centroid of the shape, this is a simple function that will add up all the x and y points and divide by the number of points. Once that is done we need to order the list based off the angel from the centroid of the shape.

    def sort_list(points) do
        number_of_points = length(points)
        [cx, cy] = 
            Enum.reduce(points, [0, 0], fn [x, y], [cx, cy] -> [x + cx, y + cy] end)
            |> (fn [x, y] -> [x / number_of_points, y / number_of_points] end).() 
            
        Enum.sort_by(points, fn [x, y] -> :math.atan2(y - cy, x - cx) end)
    end

Once this is done you now have the points in the correct order going around the center of the shape.

Next step is to take the cross-product of each set of 3 points on the shape. We do this because the cross product will tell us the the direction of the points from one to the next. 
    def find_orientaion(points) do
        full_loop = points ++ Enum.take(points, 2) # You need to add in the first 2 points to the end
        Enum.chunk_every(full_loop, 3, 1, :discard)
        |> Enum.map(&cross_product/1)
    end

    # Positive result -> A is counter-clockwise from B
    # Negative result -> A is clockwise from B
    defp cross_product([[x1, y1], [x2, y2], [x3, y3]]) do
        (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2)
    end

This will give us a list of every cross product of each point. 

Once you have this done you need to be sure that every cross-product is positive or negative. But keep in mind one thing a 0 for the cross-product means that the 3 points are in a straight line, this will mess with the logic to see if any 2 cross-products are either both positive or both negative. 
(cross1 * cross2 > 0) So we need to remove the 0's from the list.
    def is_convex(orientations) do
        non_zero = Enum.filter(orientations, &(&1 != 0))
        
        # If all are zero (degenerate polygon), treat as convex
        if non_zero == [], do: "NO", else: convex_loop(non_zero, hd(non_zero))
    end
      
    defp convex_loop([head | tail], check) do
    if head * check > 0,
        do: convex_loop(tail, check),
        else: "YES"
    end
      
    defp convex_loop([], _), do: "NO"

That is it... pretty simple if you know all the needed steps for the question.