rushlib 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ GPL-3.0 License
2
+
3
+ Copyright (c) 2025 [Ndrzy]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
rushlib-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,26 @@
1
+ Metadata-Version: 2.4
2
+ Name: rushlib
3
+ Version: 0.1.0
4
+ Summary: python lib
5
+ Home-page: https://github.com/meatdumplings0019/rushlib
6
+ Author: ndrzy
7
+ Author-email: dandan0019@outlook.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires: colorama
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE.txt
15
+ Dynamic: author
16
+ Dynamic: author-email
17
+ Dynamic: classifier
18
+ Dynamic: description
19
+ Dynamic: description-content-type
20
+ Dynamic: home-page
21
+ Dynamic: license-file
22
+ Dynamic: requires
23
+ Dynamic: requires-python
24
+ Dynamic: summary
25
+
26
+ # RushLib
@@ -0,0 +1 @@
1
+ # RushLib
@@ -0,0 +1,6 @@
1
+ import rushlib.color
2
+ import rushlib.text
3
+ import rushlib.args
4
+ import rushlib.math
5
+ import rushlib.message
6
+ import rushlib.func
@@ -0,0 +1,12 @@
1
+ import argparse
2
+
3
+ from typing import Optional
4
+
5
+ def parse_args(tokens: list[str], parser: argparse.ArgumentParser) -> Optional[argparse.Namespace]:
6
+ try:
7
+ return parser.parse_args(tokens)
8
+ except SystemExit:
9
+ return None
10
+ except Exception as e:
11
+ print(f"参数解析错误: {str(e)}")
12
+ return None
@@ -0,0 +1,203 @@
1
+ from rushlib.color._console import *
2
+ from rushlib.color.util import *
3
+
4
+
5
+ class MColor:
6
+ CONSOLE_COLOR = ForeWhite()
7
+
8
+ def __init__(self, r: int = 255, g: int = 255, b: int = 255, a: int = 255):
9
+ """
10
+ 增强版的Color, 支持rgb转hex, 可以直接作为pygame的Color
11
+ :param r: R
12
+ :param g: G
13
+ :param b: B
14
+ :param a: A
15
+ """
16
+ self._r, self._g, self._b, self._a = self.vali_rgba(r, g, b, a)
17
+
18
+ @staticmethod
19
+ def from_hex(hex_str: str = "#FFFFFF"):
20
+ """
21
+ 将16进制颜色代码转为MColor
22
+ :param hex_str: 16进制string
23
+ :return: new MColor
24
+ """
25
+ r, g, b, a = hex_to_rgb(hex_str)
26
+ return MColor(r, g, b, a)
27
+
28
+ @staticmethod
29
+ def vali_rgba(r, g, b, a=255):
30
+ return vali_rgba(r, g, b, a)
31
+
32
+ @property
33
+ def r(self) -> int:
34
+ return self._r
35
+
36
+ @r.setter
37
+ def r(self, value: int) -> None:
38
+ if 0 < value <= 255:
39
+ self._r = value
40
+
41
+ self.r = 255
42
+
43
+ @property
44
+ def float_r(self) -> float:
45
+ return self.r / 255.0
46
+
47
+ @property
48
+ def g(self) -> int:
49
+ return self._g
50
+
51
+ @g.setter
52
+ def g(self, value: int) -> None:
53
+ if 0 < value <= 255:
54
+ self._g = value
55
+ return
56
+
57
+ self.g = 255
58
+
59
+ @property
60
+ def float_g(self) -> float:
61
+ return self.g / 255.0
62
+
63
+ @property
64
+ def b(self) -> int:
65
+ return self._b
66
+
67
+ @b.setter
68
+ def b(self, value: int) -> None:
69
+ if 0 < value <= 255:
70
+ self._b = value
71
+ return
72
+
73
+ self.b = 255
74
+
75
+ @property
76
+ def float_b(self) -> float:
77
+ return self.b / 255.0
78
+
79
+ @property
80
+ def a(self) -> int:
81
+ return self._a
82
+
83
+ @a.setter
84
+ def a(self, value: int) -> None:
85
+ if 0 < value <= 255:
86
+ self._a = value
87
+ return
88
+
89
+ self.a = 255
90
+
91
+ @property
92
+ def float_a(self) -> float:
93
+ return self.a / 255.0
94
+
95
+ @property
96
+ def rgb(self) -> tuple[int, int, int]:
97
+ return self.r, self.g, self.b
98
+
99
+ @property
100
+ def float_rgb(self) -> tuple[float, float, float]:
101
+ return self.float_r, self.float_g, self.float_b
102
+
103
+ @property
104
+ def rgba(self) -> tuple[int, int, int, int]:
105
+ return self.rgb[0], self.rgb[1], self.rgb[2], self.a
106
+
107
+ @property
108
+ def float_rgba(self) -> tuple[float, float, float, float]:
109
+ return self.float_rgb[0], self.float_rgb[1], self.float_rgb[2], self.float_a
110
+
111
+ @property
112
+ def hex(self) -> str:
113
+ return rgb_to_hex(self.r, self.g, self.b)
114
+
115
+ def __iter__(self):
116
+ yield self.r
117
+ yield self.g
118
+ yield self.b
119
+ yield self.a
120
+
121
+ def __len__(self):
122
+ return 4
123
+
124
+ def __getitem__(self, item):
125
+ prop = self.r, self.g, self.b, self.a
126
+
127
+ return prop[item]
128
+
129
+ def __add__(self, other):
130
+ if isinstance(other, MColor):
131
+ r, g, b, a = other
132
+ return MColor(self.r + r, self.g + g, self.b + b, self.a + a)
133
+
134
+ raise TypeError(other)
135
+
136
+ def __sub__(self, other):
137
+ if isinstance(other, MColor):
138
+ r, g, b, a = other
139
+ return MColor(self.r - r, self.g - g, self.b - b, self.a - a)
140
+
141
+ raise TypeError(other)
142
+
143
+ def __repr__(self):
144
+ return f"[MColor r={self.r} g={self.g} b={self.b} a={self.a}]"
145
+
146
+ def __str__(self):
147
+ return f'{self.CONSOLE_COLOR}'
148
+
149
+
150
+ class Black(MColor):
151
+ CONSOLE_COLOR = ForeBlack()
152
+
153
+ def __init__(self, a: int = 255):
154
+ super().__init__(0, 0, 0, a)
155
+
156
+
157
+ class Red(MColor):
158
+ CONSOLE_COLOR = ForeRed()
159
+
160
+ def __init__(self, a: int = 255):
161
+ super().__init__(255, 0, 0, a)
162
+
163
+
164
+ class Green(MColor):
165
+ CONSOLE_COLOR = ForeGreen()
166
+
167
+ def __init__(self, a: int = 255):
168
+ super().__init__(0, 255, 0, a)
169
+
170
+
171
+ class Yellow(MColor):
172
+ CONSOLE_COLOR = ForeYellow()
173
+
174
+ def __init__(self, a: int = 255):
175
+ super().__init__(255, 255, 0, a)
176
+
177
+
178
+ class Blue(MColor):
179
+ CONSOLE_COLOR = ForeBlue()
180
+
181
+ def __init__(self, a: int = 255):
182
+ super().__init__(0, 0, 255, a)
183
+
184
+
185
+ class Magenta(MColor):
186
+ CONSOLE_COLOR = ForeMagenta()
187
+
188
+ def __init__(self, a: int = 255):
189
+ super().__init__(255, 0, 255, a)
190
+
191
+
192
+ class Cyan(MColor):
193
+ CONSOLE_COLOR = ForeCyan()
194
+
195
+ def __init__(self, a: int = 255):
196
+ super().__init__(0, 255, 255, a)
197
+
198
+
199
+ class White(MColor):
200
+ CONSOLE_COLOR = ForeWhite()
201
+
202
+ def __init__(self, a: int = 255):
203
+ super().__init__(255, 255, 255, a)
@@ -0,0 +1,53 @@
1
+ from colorama import Fore
2
+
3
+
4
+ class ConsoleColor:
5
+ def __init__(self, fore):
6
+ self._fore = fore
7
+
8
+ @property
9
+ def fore(self):
10
+ return self._fore
11
+
12
+ def __str__(self):
13
+ return self.fore
14
+
15
+
16
+ class ForeBlack(ConsoleColor):
17
+ def __init__(self):
18
+ super().__init__(Fore.BLACK)
19
+
20
+
21
+ class ForeRed(ConsoleColor):
22
+ def __init__(self):
23
+ super().__init__(Fore.RED)
24
+
25
+
26
+ class ForeGreen(ConsoleColor):
27
+ def __init__(self):
28
+ super().__init__(Fore.GREEN)
29
+
30
+
31
+ class ForeYellow(ConsoleColor):
32
+ def __init__(self):
33
+ super().__init__(Fore.YELLOW)
34
+
35
+
36
+ class ForeBlue(ConsoleColor):
37
+ def __init__(self):
38
+ super().__init__(Fore.BLUE)
39
+
40
+
41
+ class ForeMagenta(ConsoleColor):
42
+ def __init__(self):
43
+ super().__init__(Fore.MAGENTA)
44
+
45
+
46
+ class ForeCyan(ConsoleColor):
47
+ def __init__(self):
48
+ super().__init__(Fore.CYAN)
49
+
50
+
51
+ class ForeWhite(ConsoleColor):
52
+ def __init__(self):
53
+ super().__init__(Fore.WHITE)
@@ -0,0 +1,40 @@
1
+ def vali_rgba(r, g, b, a=255):
2
+ return (
3
+ min(255, max(0, r)),
4
+ min(255, max(0, g)),
5
+ min(255, max(0, b)),
6
+ min(255, max(0, a))
7
+ )
8
+
9
+ def hex_to_rgb(hex_str: str) -> tuple[int, int, int, int]:
10
+ r, g, b, a = 0, 0, 0, 255
11
+
12
+ hex_str = hex_str.lstrip('#')
13
+
14
+ if len(hex_str) not in (3, 4, 6, 8):
15
+ raise ValueError("十六进制颜色代码必须是3, 4, 6或8个字符")
16
+
17
+ if len(hex_str) == 3:
18
+ hex_str = ''.join([c * 2 for c in hex_str])
19
+ elif len(hex_str) == 4:
20
+ hex_str = ''.join([c * 2 for c in hex_str])
21
+ alpha_hex = hex_str[6:8]
22
+ a = int(alpha_hex, 16)
23
+ hex_str = hex_str[0:6]
24
+
25
+ if len(hex_str) == 8:
26
+ alpha_hex = hex_str[6:8]
27
+ a = int(alpha_hex, 16)
28
+ hex_str = hex_str[0:6]
29
+
30
+ try:
31
+ r = int(hex_str[0:2], 16)
32
+ g = int(hex_str[2:4], 16)
33
+ b = int(hex_str[4:6], 16)
34
+ except ValueError:
35
+ raise ValueError("无效的十六进制颜色代码")
36
+
37
+ return r, g, b, a
38
+
39
+ def rgb_to_hex(r, g, b) -> str:
40
+ return '#%02x%02x%02x' % vali_rgba(r, g, b)[0:3]
@@ -0,0 +1,83 @@
1
+ import inspect
2
+ from inspect import Parameter
3
+ from functools import wraps
4
+ from typing import Callable, Any
5
+
6
+
7
+ def smart_call(func: Callable, *args: Any, **kwargs: Any) -> Any:
8
+ """
9
+ 智能调用函数,根据目标函数的参数签名自动匹配传入的参数
10
+
11
+ :param func: 要调用的目标函数
12
+ :param *args: 位置参数
13
+ :param **kwargs: 关键字参数
14
+
15
+ :return: 目标函数的执行结果
16
+ """
17
+ try:
18
+ # 获取函数签名
19
+ sig = inspect.signature(func)
20
+ except (ValueError, TypeError):
21
+ # 无法获取签名时直接尝试调用
22
+ return func(*args, **kwargs)
23
+
24
+ # 准备参数绑定
25
+ bound_args = {}
26
+ params = sig.parameters
27
+
28
+ # 处理位置参数
29
+ args_iter = iter(args)
30
+ for name, param in params.items():
31
+ if param.kind in (Parameter.POSITIONAL_ONLY,
32
+ Parameter.POSITIONAL_OR_KEYWORD,
33
+ Parameter.KEYWORD_ONLY):
34
+ # 尝试从位置参数获取值
35
+ if args_iter:
36
+ try:
37
+ bound_args[name] = next(args_iter)
38
+ continue
39
+ except StopIteration:
40
+ pass
41
+
42
+ # 如果位置参数用完,尝试从关键字参数获取
43
+ if name in kwargs:
44
+ bound_args[name] = kwargs[name]
45
+ elif param.default is not Parameter.empty:
46
+ # 使用默认值
47
+ bound_args[name] = param.default
48
+ else:
49
+ # 必需参数缺失
50
+ raise TypeError(f"Missing required argument: {name}")
51
+
52
+ elif param.kind == Parameter.VAR_POSITIONAL:
53
+ # 处理 *args 参数
54
+ bound_args[name] = tuple(args_iter)
55
+ args_iter = None # 标记位置参数已耗尽
56
+
57
+ # 处理剩余的关键字参数
58
+ for name, param in params.items():
59
+ if param.kind == Parameter.VAR_KEYWORD:
60
+ # 处理 **kwargs 参数
61
+ bound_args[name] = {
62
+ k: v for k, v in kwargs.items()
63
+ if k not in bound_args
64
+ }
65
+ break
66
+ elif name not in bound_args and param.kind == Parameter.KEYWORD_ONLY:
67
+ # 处理仅关键字参数
68
+ if name in kwargs:
69
+ bound_args[name] = kwargs[name]
70
+ elif param.default is not Parameter.empty:
71
+ bound_args[name] = param.default
72
+ else:
73
+ raise TypeError(f"Missing required keyword argument: {name}")
74
+
75
+ return func(**bound_args)
76
+
77
+
78
+ def adapt_args(func):
79
+ @wraps(func)
80
+ def wrapper(*args, **kwargs):
81
+ return smart_call(func, *args, **kwargs)
82
+
83
+ return wrapper
@@ -0,0 +1,309 @@
1
+ import math
2
+ from typing import Union
3
+
4
+ Number = Union[int, float]
5
+
6
+
7
+ class Vector2:
8
+ """二维向量类"""
9
+
10
+ __slots__ = ('x', 'y')
11
+
12
+ def __init__(self, x: Number = 0, y: Number = 0):
13
+ self.x = float(x)
14
+ self.y = float(y)
15
+
16
+ def __repr__(self) -> str:
17
+ return f"Vec2({self.x}, {self.y})"
18
+
19
+ def __str__(self) -> str:
20
+ return f"({self.x}, {self.y})"
21
+
22
+ def __eq__(self, other: object) -> bool:
23
+ if not isinstance(other, Vector2):
24
+ return False
25
+ return math.isclose(self.x, other.x) and math.isclose(self.y, other.y)
26
+
27
+ def __ne__(self, other: object) -> bool:
28
+ return not self.__eq__(other)
29
+
30
+ def __hash__(self) -> int:
31
+ return hash((self.x, self.y))
32
+
33
+ def __add__(self, other: 'Vector2') -> 'Vector2':
34
+ return Vector2(self.x + other.x, self.y + other.y)
35
+
36
+ def __sub__(self, other: 'Vector2') -> 'Vector2':
37
+ return Vector2(self.x - other.x, self.y - other.y)
38
+
39
+ def __mul__(self, scalar: Number) -> 'Vector2':
40
+ return Vector2(self.x * scalar, self.y * scalar)
41
+
42
+ def __rmul__(self, scalar: Number) -> 'Vector2':
43
+ return self.__mul__(scalar)
44
+
45
+ def __truediv__(self, scalar: Number) -> 'Vector2':
46
+ if abs(scalar) < 1e-10:
47
+ raise ZeroDivisionError("Division by near-zero scalar")
48
+ return Vector2(self.x / scalar, self.y / scalar)
49
+
50
+ def __neg__(self) -> 'Vector2':
51
+ return Vector2(-self.x, -self.y)
52
+
53
+ def __abs__(self) -> float:
54
+ return math.sqrt(self.x * self.x + self.y * self.y)
55
+
56
+ def dot(self, other: 'Vector2') -> float:
57
+ """点积"""
58
+ return self.x * other.x + self.y * other.y
59
+
60
+ def cross(self, other: 'Vector2') -> float:
61
+ """叉积(标量)"""
62
+ return self.x * other.y - self.y * other.x
63
+
64
+ def length(self) -> float:
65
+ """向量长度"""
66
+ return abs(self)
67
+
68
+ def length_squared(self) -> float:
69
+ """向量长度的平方"""
70
+ return self.x * self.x + self.y * self.y
71
+
72
+ def normalized(self) -> 'Vector2':
73
+ """单位向量"""
74
+ length = self.length()
75
+ if length < 1e-10:
76
+ return Vector2(0, 0)
77
+ return self / length
78
+
79
+ def normalize(self) -> None:
80
+ """将向量单位化(原地操作)"""
81
+ length = self.length()
82
+ if length < 1e-10:
83
+ self.x, self.y = 0, 0
84
+ else:
85
+ self.x /= length
86
+ self.y /= length
87
+
88
+ def distance_to(self, other: 'Vector2') -> float:
89
+ """到另一个向量的距离"""
90
+ return (self - other).length()
91
+
92
+ def angle(self) -> float:
93
+ """向量的角度(弧度)"""
94
+ return math.atan2(self.y, self.x)
95
+
96
+ def rotated(self, angle: float) -> 'Vector2':
97
+ """旋转指定弧度后的向量"""
98
+ cos_a = math.cos(angle)
99
+ sin_a = math.sin(angle)
100
+ return Vector2(
101
+ self.x * cos_a - self.y * sin_a,
102
+ self.x * sin_a + self.y * cos_a
103
+ )
104
+
105
+ def rotate(self, angle: float) -> None:
106
+ """旋转指定弧度(原地操作)"""
107
+ cos_a = math.cos(angle)
108
+ sin_a = math.sin(angle)
109
+ x = self.x * cos_a - self.y * sin_a
110
+ y = self.x * sin_a + self.y * cos_a
111
+ self.x, self.y = x, y
112
+
113
+ def lerp(self, other: 'Vector2', t: float) -> 'Vector2':
114
+ """线性插值"""
115
+ t = max(0.0, min(1.0, t)) # 限制t在[0,1]范围内
116
+ return Vector2(
117
+ self.x + (other.x - self.x) * t,
118
+ self.y + (other.y - self.y) * t
119
+ )
120
+
121
+ def copy(self) -> 'Vector2':
122
+ """返回向量的副本"""
123
+ return Vector2(self.x, self.y)
124
+
125
+ @classmethod
126
+ def from_angle(cls, angle: float, length: float = 1.0) -> 'Vector2':
127
+ """从角度和长度创建向量"""
128
+ return cls(math.cos(angle) * length, math.sin(angle) * length)
129
+
130
+ @classmethod
131
+ def zero(cls) -> 'Vector2':
132
+ """零向量"""
133
+ return cls(0, 0)
134
+
135
+ @classmethod
136
+ def one(cls) -> 'Vector2':
137
+ """全1向量"""
138
+ return cls(1, 1)
139
+
140
+ @classmethod
141
+ def up(cls) -> 'Vector2':
142
+ """上向量"""
143
+ return cls(0, 1)
144
+
145
+ @classmethod
146
+ def down(cls) -> 'Vector2':
147
+ """下向量"""
148
+ return cls(0, -1)
149
+
150
+ @classmethod
151
+ def left(cls) -> 'Vector2':
152
+ """左向量"""
153
+ return cls(-1, 0)
154
+
155
+ @classmethod
156
+ def right(cls) -> 'Vector2':
157
+ """右向量"""
158
+ return cls(1, 0)
159
+
160
+
161
+ class Vector3:
162
+ """三维向量类"""
163
+
164
+ __slots__ = ('x', 'y', 'z')
165
+
166
+ def __init__(self, x: Number = 0, y: Number = 0, z: Number = 0):
167
+ self.x = float(x)
168
+ self.y = float(y)
169
+ self.z = float(z)
170
+
171
+ def __repr__(self) -> str:
172
+ return f"Vec3({self.x}, {self.y}, {self.z})"
173
+
174
+ def __str__(self) -> str:
175
+ return f"({self.x}, {self.y}, {self.z})"
176
+
177
+ def __eq__(self, other: object) -> bool:
178
+ if not isinstance(other, Vector3):
179
+ return False
180
+ return (math.isclose(self.x, other.x) and
181
+ math.isclose(self.y, other.y) and
182
+ math.isclose(self.z, other.z))
183
+
184
+ def __ne__(self, other: object) -> bool:
185
+ return not self.__eq__(other)
186
+
187
+ def __hash__(self) -> int:
188
+ return hash((self.x, self.y, self.z))
189
+
190
+ def __add__(self, other: 'Vector3') -> 'Vector3':
191
+ return Vector3(self.x + other.x, self.y + other.y, self.z + other.z)
192
+
193
+ def __sub__(self, other: 'Vector3') -> 'Vector3':
194
+ return Vector3(self.x - other.x, self.y - other.y, self.z - other.z)
195
+
196
+ def __mul__(self, scalar: Number) -> 'Vector3':
197
+ return Vector3(self.x * scalar, self.y * scalar, self.z * scalar)
198
+
199
+ def __rmul__(self, scalar: Number) -> 'Vector3':
200
+ return self.__mul__(scalar)
201
+
202
+ def __truediv__(self, scalar: Number) -> 'Vector3':
203
+ if abs(scalar) < 1e-10:
204
+ raise ZeroDivisionError("Division by near-zero scalar")
205
+ return Vector3(self.x / scalar, self.y / scalar, self.z / scalar)
206
+
207
+ def __neg__(self) -> 'Vector3':
208
+ return Vector3(-self.x, -self.y, -self.z)
209
+
210
+ def __abs__(self) -> float:
211
+ return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
212
+
213
+ def dot(self, other: 'Vector3') -> float:
214
+ """点积"""
215
+ return self.x * other.x + self.y * other.y + self.z * other.z
216
+
217
+ def cross(self, other: 'Vector3') -> 'Vector3':
218
+ """叉积(向量)"""
219
+ return Vector3(
220
+ self.y * other.z - self.z * other.y,
221
+ self.z * other.x - self.x * other.z,
222
+ self.x * other.y - self.y * other.x
223
+ )
224
+
225
+ def length(self) -> float:
226
+ """向量长度"""
227
+ return abs(self)
228
+
229
+ def length_squared(self) -> float:
230
+ """向量长度的平方"""
231
+ return self.x * self.x + self.y * self.y + self.z * self.z
232
+
233
+ def normalized(self) -> 'Vector3':
234
+ """单位向量"""
235
+ length = self.length()
236
+ if length < 1e-10:
237
+ return Vector3(0, 0, 0)
238
+ return self / length
239
+
240
+ def normalize(self) -> None:
241
+ """将向量单位化(原地操作)"""
242
+ length = self.length()
243
+ if length < 1e-10:
244
+ self.x, self.y, self.z = 0, 0, 0
245
+ else:
246
+ self.x /= length
247
+ self.y /= length
248
+ self.z /= length
249
+
250
+ def distance_to(self, other: 'Vector3') -> float:
251
+ """到另一个向量的距离"""
252
+ return (self - other).length()
253
+
254
+ def lerp(self, other: 'Vector3', t: float) -> 'Vector3':
255
+ """线性插值"""
256
+ t = max(0.0, min(1.0, t)) # 限制t在[0,1]范围内
257
+ return Vector3(
258
+ self.x + (other.x - self.x) * t,
259
+ self.y + (other.y - self.y) * t,
260
+ self.z + (other.z - self.z) * t
261
+ )
262
+
263
+ def copy(self) -> 'Vector3':
264
+ """返回向量的副本"""
265
+ return Vector3(self.x, self.y, self.z)
266
+
267
+ @classmethod
268
+ def zero(cls) -> 'Vector3':
269
+ """零向量"""
270
+ return cls(0, 0, 0)
271
+
272
+ @classmethod
273
+ def one(cls) -> 'Vector3':
274
+ """全1向量"""
275
+ return cls(1, 1, 1)
276
+
277
+ @classmethod
278
+ def up(cls) -> 'Vector3':
279
+ """上向量"""
280
+ return cls(0, 1, 0)
281
+
282
+ @classmethod
283
+ def down(cls) -> 'Vector3':
284
+ """下向量"""
285
+ return cls(0, -1, 0)
286
+
287
+ @classmethod
288
+ def left(cls) -> 'Vector3':
289
+ """左向量"""
290
+ return cls(-1, 0, 0)
291
+
292
+ @classmethod
293
+ def right(cls) -> 'Vector3':
294
+ """右向量"""
295
+ return cls(1, 0, 0)
296
+
297
+ @classmethod
298
+ def forward(cls) -> 'Vector3':
299
+ """前向量"""
300
+ return cls(0, 0, 1)
301
+
302
+ @classmethod
303
+ def back(cls) -> 'Vector3':
304
+ """后向量"""
305
+ return cls(0, 0, -1)
306
+
307
+
308
+ vec2 = Vector2
309
+ vec3 = Vector3
@@ -0,0 +1,22 @@
1
+ from typing import TypeVar, Generic
2
+
3
+ from rushlib.text import Error
4
+
5
+ T = TypeVar('T')
6
+
7
+ class Message(Generic[T]):
8
+ def __init__(self, var: T, msg: Exception | str | Error = None):
9
+ self.var: T = var
10
+
11
+ if isinstance(msg, Error):
12
+ tmp = msg
13
+ elif isinstance(msg, (self, Exception)):
14
+ tmp = Error(msg)
15
+ else:
16
+ raise TypeError(msg)
17
+
18
+ self.msg: Error = tmp
19
+
20
+ def __iter__(self):
21
+ yield self.var
22
+ yield self.msg
@@ -0,0 +1,64 @@
1
+ from colorama import Style
2
+
3
+ from rushlib.color import MColor, White, Red, Yellow
4
+
5
+
6
+ class Text:
7
+ def __init__(self, text="", color: MColor = White()):
8
+ self._text = text
9
+ self._color = color
10
+
11
+ def sub_string(self, start: int, end: int) -> str:
12
+ return self.text[start:end]
13
+
14
+ @property
15
+ def text(self):
16
+ return self._text
17
+
18
+ @text.setter
19
+ def text(self, text):
20
+ self._text = text
21
+
22
+ @property
23
+ def color(self):
24
+ return self._color
25
+
26
+ @color.setter
27
+ def color(self, color):
28
+ self._color = color
29
+
30
+ def __add__(self, other):
31
+ if isinstance(other, Text):
32
+ return Text(self.text + other.text, self.color)
33
+
34
+ if isinstance(other, str):
35
+ return Text(self.text + other, self.color)
36
+
37
+ raise TypeError(other)
38
+
39
+ def __len__(self):
40
+ return len(self.text)
41
+
42
+ def __getitem__(self, item):
43
+ return self.text[item]
44
+
45
+ def __iter__(self):
46
+ return self.text.__iter__()
47
+
48
+ def __str__(self):
49
+ return f'{self.color}{self.text}{Style.RESET_ALL}'
50
+
51
+
52
+ class Error(Text):
53
+ def __init__(self, text):
54
+ super().__init__(text, Red())
55
+
56
+
57
+ class Info(Text):
58
+ def __init__(self, text):
59
+ super().__init__(text, White())
60
+
61
+
62
+ class Warn(Text):
63
+ def __init__(self, text):
64
+ super().__init__(text, Yellow())
@@ -0,0 +1,26 @@
1
+ Metadata-Version: 2.4
2
+ Name: rushlib
3
+ Version: 0.1.0
4
+ Summary: python lib
5
+ Home-page: https://github.com/meatdumplings0019/rushlib
6
+ Author: ndrzy
7
+ Author-email: dandan0019@outlook.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires: colorama
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE.txt
15
+ Dynamic: author
16
+ Dynamic: author-email
17
+ Dynamic: classifier
18
+ Dynamic: description
19
+ Dynamic: description-content-type
20
+ Dynamic: home-page
21
+ Dynamic: license-file
22
+ Dynamic: requires
23
+ Dynamic: requires-python
24
+ Dynamic: summary
25
+
26
+ # RushLib
@@ -0,0 +1,16 @@
1
+ LICENSE.txt
2
+ README.md
3
+ setup.py
4
+ rushlib/__init__.py
5
+ rushlib/args.py
6
+ rushlib/func.py
7
+ rushlib/math.py
8
+ rushlib/message.py
9
+ rushlib/text.py
10
+ rushlib.egg-info/PKG-INFO
11
+ rushlib.egg-info/SOURCES.txt
12
+ rushlib.egg-info/dependency_links.txt
13
+ rushlib.egg-info/top_level.txt
14
+ rushlib/color/__init__.py
15
+ rushlib/color/util.py
16
+ rushlib/color/_console/__init__.py
@@ -0,0 +1 @@
1
+ rushlib
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
rushlib-0.1.0/setup.py ADDED
@@ -0,0 +1,26 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ with open("README.md", "r", encoding="utf8") as fh:
4
+ long_description = fh.read()
5
+
6
+ setup(
7
+ name='rushlib',
8
+ version='0.1.0',
9
+ packages=find_packages(),
10
+ requires=[
11
+ 'colorama'
12
+ ],
13
+ description='python lib',
14
+ author='ndrzy',
15
+ author_email='dandan0019@outlook.com',
16
+ python_requires='>=3.10',
17
+ long_description=long_description,
18
+ long_description_content_type="text/markdown",
19
+ url="https://github.com/meatdumplings0019/rushlib",
20
+
21
+ classifiers=[
22
+ "Programming Language :: Python :: 3",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Operating System :: OS Independent",
25
+ ]
26
+ )