1+ from __future__ import annotations
2+
13import tkinter as tk
4+ import operator
5+ from math import log2
6+ from typing import NamedTuple , Callable , TypeVar , List
27from enum import Flag
38from dataclasses import dataclass
9+ from functools import partialmethod
10+
11+
12+ class Coord (NamedTuple ):
13+ """
14+ Helper class for managing coordinate values.
15+
16+ Coord overloads many of the numeric operators by mapping
17+ it to the x and y values individually.
18+
19+ param:
20+ x: int -- X position.
21+ y: int -- Y position.
22+
23+ example::
24+
25+ ```
26+ c1 = c2 = Coord(1, 1)
27+ c1 + c2
28+ >>> Coord(2, 2)
29+ # For convenience, integers are accepted as well
30+ c1 = Coord(1, 1)
31+ c1 + 1 # 1 is cast to Coord(1, 1)
32+ >>> Coord(2, 2)
33+ ```
34+
35+ note:
36+
37+ True divide `round`s in order to remain compatible with tkinter
38+ coordinate values (`int`).
39+ """
40+
41+ x : int
42+ y : int
43+
44+ Operand = TypeVar ('Operand' , 'Coord' , int )
45+
46+ def __apply (self , op : Callable , other : Coord .Operand ) -> Coord :
47+ if isinstance (other , int ):
48+ other = Coord (other , other )
49+
50+ x = op (self .x , other .x )
51+ y = op (self .y , other .y )
52+ return Coord (x , y )
53+
54+ def midpoint (self , other : Coord ) -> Coord :
55+ """
56+ The Coord that is equal distance from `self` and `other`.
57+
58+ param:
59+ other: Coord -- The point to consider.
60+
61+ return:
62+ Coord -- The resulting coordinate.
63+ """
64+ return (self + other ) / 2
65+
66+ def distance (self , other : Coord ) -> int :
67+ """
68+ The Manhattan distance between `self` and `other`.
69+
70+ param:
71+ other: Coord -- THe point to consider.
472
5- from .coord import Coord
73+ return:
74+ int -- A numeric representation of the distance between two points.
75+ """
76+ dist = map (abs , other - self )
77+ return sum (dist )
78+
79+ def __truediv__ (self , other ):
80+ result = self .__apply (operator .truediv , other )
81+ return Coord (* map (round , result ))
82+
83+ __add__ = partialmethod (__apply , operator .add )
84+ __sub__ = partialmethod (__apply , operator .sub )
85+ __mul__ = partialmethod (__apply , operator .mul )
86+ __mod__ = partialmethod (__apply , operator .mod )
87+ __pow__ = partialmethod (__apply , operator .pow )
88+ __floordiv__ = partialmethod (__apply , operator .floordiv )
689
790
891class Direction (Flag ):
92+ """
93+ Defines base directions.
94+
95+
96+ """
997 LEFT = Coord (- 1 , 0 )
1098 RIGHT = Coord (1 , 0 )
1199 UP = Coord (0 , 1 )
12100 DOWN = Coord (0 , - 1 )
13101
102+ def __mul__ (self , other : int ) -> Coord :
103+ return self .value * other
104+
105+ def __add__ (self , other : Direction ) -> Coord :
106+ return self .value + other .value
107+
14108
15109class Window (tk .Canvas ):
16110
@@ -33,10 +127,6 @@ class Motion:
33127 frames = 30
34128
35129
36-
37-
38-
39-
40130class Animate :
41131
42132 def __init__ (self , obj : tk .Widget ):
@@ -45,5 +135,41 @@ def __init__(self, obj: tk.Widget):
45135 def set_event (self , event : tk .EventType ):
46136 self .bind (event , self .run )
47137
48- def add (self , )
138+ # def add(self, )
139+
140+
141+ def vector (start : Coord , end : Coord , step : int = 60 ) -> List [Coord ]:
142+ """
143+ Creates a list of all the Coords on a straight line from `start` to `end`.
144+
145+ param:
146+ start: Coord -- The starting point.
147+ end: Coord -- The ending point.
148+ step: int (optional) -- The desired number of points to include. Defaults to 60.
149+ Actual resulting length may vary.
150+
151+ return:
152+ List[Coord] -- All points that fall on the line from start to end.
153+
154+ example::
155+
156+ ```
157+ start = Coord(0, 0)
158+ end = Coord(5, 0)
159+ vector(start, end, 5)
160+ >>> [Coord(x=0, y=0), Coord(x=1, y=0), Coord(x=2, y=0), Coord(x=4, y=0)]
161+ ```
162+
163+ note:
49164
165+ The current implementation recursively finds midpoints to build the line.
166+ This means the resulting length may vary, due to its eager nature.
167+ """
168+ mid = start .midpoint (end )
169+ instep = round (step / 2 )
170+ if instep :
171+ back = vector (start , mid , step = instep )
172+ front = vector (mid , end , step = instep )
173+ return back + front
174+ else :
175+ return [start ]
0 commit comments