``package algorithmsinanutshellimport algorithmdesignmanualbook.printimport utils.PrintUtilsimport utils.assertArraysSameimport java.util.*private fun <T> Stack<T>.fromTopNext() = this[this.lastIndex - 1]/** * Find Convex Hull - a polygon that surrounds all points * * [link](https://www.cs.auckland.ac.nz/software/AlgAnim/convex_hull.html) */class ConvexHullScanUsingGrahamScan(private val points: Array<Point>) {    private val result = Stack<Point>()    init {        require(points.size >= 3)        // Left most point is at 0th index        points.sortBy { it.x }        points.forEach(::println)    }    /**     * When LTR, exclude 2nd point     *     * When RTL, dont exclude     *     *        ________x     *     *      x     *     *    /     *     * x     *     * Include all if ß12 = ß23     * x----- x ------x     *     */    private fun excludeP2FromConvexHull(p1: Point, p2: Point, p3: Point): Boolean {        val orientation = OrientationOf3Points(p1, p2, p3)        return when (orientation.getOrientation()) {            Orientation.CW -> true            Orientation.ACW -> false            Orientation.COLINEAR -> false        }    }    fun execute(): Stack<Point> {        // Add first three points        result.add(points[0])        result.add(points[1])        result.add(points[2])        for (i in 3..points.lastIndex) {            val p3 = points[i]            // Last two from stack            var p2 = result.lastElement()            var p1 = result.fromTopNext()            while (excludeP2FromConvexHull(p1, p2, p3)) {                // pop the last element from stack and update p2 & p1. p3 remains the same                result.pop()                p2 = result.lastElement()                p1 = result.fromTopNext()            }            result.push(p3)        }        result.add(points[0])        println("Stack Content:")        result.forEach(::println)        return result    }}fun main() {    val exec = ConvexHullScanUsingGrahamScan(        arrayOf(            0 fromTo 3,            2 fromTo 3,            1 fromTo 1,            2 fromTo 1,            3 fromTo 0,            0 fromTo 0,            3 fromTo 3,        )    )    assertArraysSame(        expected = arrayOf(0 fromTo 3, 0 fromTo 0, 3 fromTo 0, 3 fromTo 3, 0 fromTo 3),        actual = exec.execute().toArray()    )}``