"""simple docstring"""






# Lint as: python3
import dataclasses
import re
from dataclasses import dataclass
from functools import total_ordering
from typing import Optional, Union


__lowerCAmelCase    :       List[Any]					     =re.compile(R"""^(?P<major>\d+)""" R"""\.(?P<minor>\d+)""" R"""\.(?P<patch>\d+)$""")





@total_ordering
@dataclass
class  _A						:
      snake_case__			:   str
      snake_case__			:   Optional[str]							  =	None
      snake_case__			:   Optional[Union[str, int]]							  =	None
      snake_case__			:   Optional[Union[str, int]]							  =	None
      snake_case__			:   Optional[Union[str, int]]							  =	None

      def 				A__       (						self						):







            """simple docstring"""



            lowercase							,							lowercase							,							lowercase														=	_str_to_version_tuple(self.version_str						)

      def __repr__(						self						):







            """simple docstring"""



            return f'{self.tuple[0]}.{self.tuple[1]}.{self.tuple[2]}'

      @property
      def 				A__       (						self						):







            """simple docstring"""



            return self.major, self.minor, self.patch

      def 				A__       (						self		,       __lowerCAmelCase						):







            """simple docstring"""



            if isinstance(__lowerCAmelCase		,       __lowerCAmelCase						):
                  return Version(__lowerCAmelCase						)
            elif isinstance(__lowerCAmelCase		,       __lowerCAmelCase						):
                  return other
            raise TypeError(f'{other} (type {type(__lowerCAmelCase						)}) cannot be compared to version.'						)

      def __eq__(						self		,       __lowerCAmelCase						):







            """simple docstring"""



            try:
                  lowercase														=	self._validate_operand(__lowerCAmelCase						)
            except (TypeError, ValueError):
                  return False
            else:
                  return self.tuple == other.tuple

      def __lt__(						self		,       __lowerCAmelCase						):







            """simple docstring"""



            lowercase														=	self._validate_operand(__lowerCAmelCase						)
            return self.tuple < other.tuple

      def __hash__(						self						):







            """simple docstring"""



            return hash(_version_tuple_to_str(self.tuple						)						)

      @classmethod
      def 				A__       (						cls		,       __lowerCAmelCase						):







            """simple docstring"""



            lowercase														=	{f.name for f in dataclasses.fields(cls						)}
            return cls(**{k: v for k, v in dic.items() if k in field_names}						)







      def 				A__       (						self						):







            """simple docstring"""



            return self.version_str






def 			UpperCAmelCase__       (				lowerCAmelCase__     :Tuple		) ->    List[Any]:
      '''simple docstring'''


      lowercase														=	_VERSION_REG.match(lowerCAmelCase__		)
      if not res:
            raise ValueError(f'Invalid version \'{version_str}\'. Format should be x.y.z with {{x,y,z}} being digits.'		)
      return tuple(int(lowerCAmelCase__		) for v in [res.group("""major"""		), res.group("""minor"""		), res.group("""patch"""		)]		)






def 			UpperCAmelCase__       (				lowerCAmelCase__     :Optional[int]		) ->    Optional[Any]:
      '''simple docstring'''


      return ".".join(str(lowerCAmelCase__		) for v in version_tuple		)




"""simple docstring"""






from __future__ import annotations

from scipy.special import comb  # type: ignore





class  _A						:

      def __init__(						self		,       __lowerCAmelCase						):







            """simple docstring"""



            lowercase														=	list_of_points
            # Degree determines the flexibility of the curve.
            # Degree = 1 will produce a straight line.
            lowercase														=	len(__lowerCAmelCase						) - 1

      def 				A__       (						self		,       __lowerCAmelCase						):







            """simple docstring"""



            assert 0 <= t <= 1, "Time t must be between 0 and 1."
            lowercase														=	[]
            for i in range(len(self.list_of_points						)						):
                  # basis function for each i
                  output_values.append(
                      comb(self.degree		,       __lowerCAmelCase						) * ((1 - t) ** (self.degree - i)) * (t**i)						)
            # the basis must sum up to 1 for it to produce a valid Bezier curve.
            assert round(sum(__lowerCAmelCase						)		,       5						) == 1
            return output_values

      def 				A__       (						self		,       __lowerCAmelCase						):







            """simple docstring"""



            assert 0 <= t <= 1, "Time t must be between 0 and 1."

            lowercase														=	self.basis_function(__lowerCAmelCase						)
            lowercase														=	0.0
            lowercase														=	0.0
            for i in range(len(self.list_of_points						)						):
                  # For all points, sum up the product of i-th basis function and i-th point.
                  x += basis_function[i] * self.list_of_points[i][0]
                  y += basis_function[i] * self.list_of_points[i][1]
            return (x, y)







      def 				A__       (						self		,       __lowerCAmelCase = 0.0_1						):







            """simple docstring"""



            from matplotlib import pyplot as plt  # type: ignore

            lowercase														=	[]  # x coordinates of points to plot
            lowercase														=	[]  # y coordinates of points to plot

            lowercase														=	0.0
            while t <= 1:
                  lowercase														=	self.bezier_curve_function(__lowerCAmelCase						)
                  to_plot_x.append(value[0]						)
                  to_plot_y.append(value[1]						)
                  t += step_size

            lowercase														=	[i[0] for i in self.list_of_points]
            lowercase														=	[i[1] for i in self.list_of_points]

            plt.plot(
                __lowerCAmelCase		,       __lowerCAmelCase		,       color="""blue"""		,       label="""Curve of Degree """ + str(self.degree						)		,       )
            plt.scatter(__lowerCAmelCase		,       __lowerCAmelCase		,       color="""red"""		,       label="""Control Points"""						)
            plt.legend()
            plt.show()


if __name__ == "__main__":
       import doctest

       doctest.testmod()

       BezierCurve([(1, 2), (3, 5)]).plot_curve()  # degree 1
       BezierCurve([(0, 0), (5, 5), (5, 0)]).plot_curve()  # degree 2
       BezierCurve([(0, 0), (5, 5), (5, 0), (2.5, -2.5)]).plot_curve()  # degree 3



