"""simple docstring"""







from __future__ import annotations

from collections.abc import Iterable



class 			_lowerCamelCase      :







				def __init__(			self     :							Tuple      ,       lowerCamelCase_     :							List[Any]      ,       lowerCamelCase_     :							Optional[Any]    ):

					"""simple docstring"""






					_lowercase					,   _lowercase			:     List[Any]      					=				float(lowerCamelCase_    ), float(lowerCamelCase_    )







				def __eq__(			self     :							int      ,       lowerCamelCase_     :							Optional[int]    ):

					"""simple docstring"""






					return self.x == other.x and self.y == other.y







				def __ne__(			self     :							Any      ,       lowerCamelCase_     :							List[str]    ):

					"""simple docstring"""






					return not self == other







				def __gt__(			self     :							Dict      ,       lowerCamelCase_     :							str    ):

					"""simple docstring"""






					if self.x > other.x:
						return True
					elif self.x == other.x:
						return self.y > other.y
					return False







				def __lt__(			self     :							int      ,       lowerCamelCase_     :							List[str]    ):

					"""simple docstring"""






					return not self > other







				def __ge__(			self     :							Optional[int]      ,       lowerCamelCase_     :							Union[str, Any]    ):

					"""simple docstring"""






					if self.x > other.x:
						return True
					elif self.x == other.x:
						return self.y >= other.y
					return False







				def __le__(			self     :							Optional[Any]      ,       lowerCamelCase_     :							Union[str, Any]    ):

					"""simple docstring"""






					if self.x < other.x:
						return True
					elif self.x == other.x:
						return self.y <= other.y
					return False







				def __repr__(			self     :							str    ):

					"""simple docstring"""






					return F'''({self.x}, {self.y})'''







				def __hash__(			self     :							List[Any]    ):

					"""simple docstring"""






					return hash(self.x    )



def   __lowerCAmelCase(		__UpperCAmelCase  ,):






	"""simple docstring"""





	_lowercase			:     list[Point]      					=				[]
	if list_of_tuples:
		for p in list_of_tuples:
			if isinstance(__UpperCAmelCase  ,__UpperCAmelCase      ):
				points.append(__UpperCAmelCase      )
			else:
				try:
					points.append(Point(p[0]  ,p[1]      )      )
				except (IndexError, TypeError):
					print(
					    F'''Ignoring deformed point {p}. All points'''
					    ' must have at least 2 coordinates.'      )
	return points


def   __lowerCAmelCase(		__UpperCAmelCase      ):






	"""simple docstring"""





	if not hasattr(__UpperCAmelCase  ,'__iter__'      ):
		_lowercase			:     List[str]      					=				F'''Expecting an iterable object but got an non-iterable type {points}'''
		raise ValueError(__UpperCAmelCase      )

	if not points:
		_lowercase			:     Any      					=				F'''Expecting a list of points but got {points}'''
		raise ValueError(__UpperCAmelCase      )

	return _construct_points(__UpperCAmelCase      )


def   __lowerCAmelCase(		__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase      ):






	"""simple docstring"""





	_lowercase			:     Any      					=				(a.x * b.y + b.x * c.y + c.x * a.y) - (a.y * b.x + b.y * c.x + c.y * a.x)
	return det


def   __lowerCAmelCase(		__UpperCAmelCase      ):






	"""simple docstring"""





	_lowercase			:     Tuple      					=				sorted(_validate_input(__UpperCAmelCase      )      )
	_lowercase			:     Tuple      					=				len(__UpperCAmelCase      )
	_lowercase			:     str      					=				set()

	for i in range(n - 1      ):
		for j in range(i + 1  ,__UpperCAmelCase      ):
			_lowercase			:     Any      					=				False
			_lowercase			:     str      					=				True
			for k in range(__UpperCAmelCase      ):
				if k != i and k != j:
					_lowercase			:     int      					=				_det(points[i]  ,points[j]  ,points[k]      )

					if det_k > 0:
						_lowercase			:     str      					=				True
					elif det_k < 0:
						_lowercase			:     str      					=				True
					else:
						# point[i], point[j], point[k] all lie on a straight line
						# if point[k] is to the left of point[i] or it's to the
						# right of point[j], then point[i], point[j] cannot be
						# part of the convex hull of A
						if points[k] < points[i] or points[k] > points[j]:
							_lowercase			:     List[str]      					=				False
							break

				if points_left_of_ij and points_right_of_ij:
					_lowercase			:     Tuple      					=				False
					break

			if ij_part_of_convex_hull:
				convex_set.update([points[i], points[j]]      )

	return sorted(__UpperCAmelCase      )


def   __lowerCAmelCase(		__UpperCAmelCase      ):






	"""simple docstring"""





	_lowercase			:     str      					=				sorted(_validate_input(__UpperCAmelCase      )      )
	_lowercase			:     List[str]      					=				len(__UpperCAmelCase      )

	# divide all the points into an upper hull and a lower hull
	# the left most point and the right most point are definitely
	# members of the convex hull by definition.
	# use these two anchors to divide all the points into two hulls,
	# an upper hull and a lower hull.

	# all points to the left (above) the line joining the extreme points belong to the
	# upper hull
	# all points to the right (below) the line joining the extreme points below to the
	# lower hull
	# ignore all points on the line joining the extreme points since they cannot be
	# part of the convex hull

	_lowercase			:     Any      					=				points[0]
	_lowercase			:     Union[str, Any]      					=				points[n - 1]

	_lowercase			:     Tuple      					=				{left_most_point, right_most_point}
	_lowercase			:     str      					=				[]
	_lowercase			:     int      					=				[]

	for i in range(1  ,n - 1      ):
		_lowercase			:     str      					=				_det(__UpperCAmelCase  ,__UpperCAmelCase  ,points[i]      )

		if det > 0:
			upper_hull.append(points[i]      )
		elif det < 0:
			lower_hull.append(points[i]      )

	_construct_hull(__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase      )
	_construct_hull(__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase      )

	return sorted(__UpperCAmelCase      )


def   __lowerCAmelCase(		__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase      ):






	"""simple docstring"""





	if points:
		_lowercase			:     str      					=				None
		_lowercase			:     Optional[Any]      					=				float('-inf'      )
		_lowercase			:     Optional[Any]      					=				[]

		for p in points:
			_lowercase			:     Union[str, Any]      					=				_det(__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase      )

			if det > 0:
				candidate_points.append(__UpperCAmelCase      )

				if det > extreme_point_distance:
					_lowercase			:     Optional[int]      					=				det
					_lowercase			:     int      					=				p

		if extreme_point:
			_construct_hull(__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase      )
			convex_set.add(__UpperCAmelCase      )
			_construct_hull(__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase  ,__UpperCAmelCase      )


def   __lowerCAmelCase(		__UpperCAmelCase      ):






	"""simple docstring"""





	_lowercase			:     Optional[int]      					=				sorted(_validate_input(__UpperCAmelCase      )      )
	_lowercase			:     List[Any]      					=				len(__UpperCAmelCase      )

	_lowercase			:     Union[str, Any]      					=				points[:2]
	for i in range(2  ,__UpperCAmelCase      ):
		_lowercase			:     Dict      					=				_det(convex_hull[1]  ,convex_hull[0]  ,points[i]      )
		if det > 0:
			convex_hull.insert(0  ,points[i]      )
			break
		elif det < 0:
			convex_hull.append(points[i]      )
			break
		else:
			_lowercase			:     str      					=				points[i]
	i += 1

	for j in range(__UpperCAmelCase  ,__UpperCAmelCase      ):
		if (
		    _det(convex_hull[0]  ,convex_hull[-1]  ,points[j]      ) > 0
		    and _det(convex_hull[-1]  ,convex_hull[0]  ,points[1]      ) < 0
		):
			# The point lies within the convex hull
			continue

		convex_hull.insert(0  ,points[j]      )
		convex_hull.append(points[j]      )
		while _det(convex_hull[0]  ,convex_hull[1]  ,convex_hull[2]      ) >= 0:
			del convex_hull[1]
		while _det(convex_hull[-1]  ,convex_hull[-2]  ,convex_hull[-3]      ) <= 0:
			del convex_hull[-2]

    # `convex_hull` is contains the convex hull in circular order
	return sorted(convex_hull[1:] if len(__UpperCAmelCase      ) > 3 else convex_hull      )


def   __lowerCAmelCase(		):






	"""simple docstring"""





	_lowercase			:     Tuple      					=				[
	    (0, 3),
	    (2, 2),
	    (1, 1),
	    (2, 1),
	    (3, 0),
	    (0, 0),
	    (3, 3),
	    (2, -1),
	    (2, -4),
	    (1, -3),
	]
	# the convex set of points is
	# [(0, 0), (0, 3), (1, -3), (2, -4), (3, 0), (3, 3)]
	_lowercase			:     Any      					=				convex_hull_bf(__UpperCAmelCase      )

	_lowercase			:     Optional[Any]      					=				convex_hull_recursive(__UpperCAmelCase      )
	assert results_bf == results_recursive

	_lowercase			:     List[Any]      					=				convex_hull_melkman(__UpperCAmelCase      )
	assert results_bf == results_melkman

	print(__UpperCAmelCase      )


if __name__ == "__main__":
						main()




"""simple docstring"""







from __future__ import annotations

import re


def   __lowerCAmelCase(		__UpperCAmelCase      ):






	"""simple docstring"""





	def alphanum_key(__UpperCAmelCase      ):
		return [int(__UpperCAmelCase      ) if s.isdigit() else s.lower() for s in re.split('([0-9]+)'  ,__UpperCAmelCase      )]

	return sorted(__UpperCAmelCase  ,key=__UpperCAmelCase      )


if __name__ == "__main__":
						import doctest

						doctest.testmod()



