absfuyu 3.1.1__py3-none-any.whl → 3.3.3__py3-none-any.whl

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.

Potentially problematic release.


This version of absfuyu might be problematic. Click here for more details.

Files changed (61) hide show
  1. absfuyu/__init__.py +3 -10
  2. absfuyu/__main__.py +5 -250
  3. absfuyu/cli/__init__.py +51 -0
  4. absfuyu/cli/color.py +24 -0
  5. absfuyu/cli/config_group.py +56 -0
  6. absfuyu/cli/do_group.py +76 -0
  7. absfuyu/cli/game_group.py +109 -0
  8. absfuyu/config/__init__.py +117 -100
  9. absfuyu/config/config.json +0 -7
  10. absfuyu/core.py +5 -66
  11. absfuyu/everything.py +7 -9
  12. absfuyu/extensions/beautiful.py +30 -23
  13. absfuyu/extensions/dev/__init__.py +11 -8
  14. absfuyu/extensions/dev/password_hash.py +4 -2
  15. absfuyu/extensions/dev/passwordlib.py +7 -5
  16. absfuyu/extensions/dev/project_starter.py +4 -2
  17. absfuyu/extensions/dev/shutdownizer.py +148 -0
  18. absfuyu/extensions/extra/__init__.py +1 -2
  19. absfuyu/extensions/extra/data_analysis.py +182 -107
  20. absfuyu/fun/WGS.py +50 -26
  21. absfuyu/fun/__init__.py +6 -7
  22. absfuyu/fun/tarot.py +1 -1
  23. absfuyu/game/__init__.py +75 -81
  24. absfuyu/game/game_stat.py +36 -0
  25. absfuyu/game/sudoku.py +41 -48
  26. absfuyu/game/tictactoe.py +303 -548
  27. absfuyu/game/wordle.py +56 -47
  28. absfuyu/general/__init__.py +17 -7
  29. absfuyu/general/content.py +16 -15
  30. absfuyu/general/data_extension.py +282 -90
  31. absfuyu/general/generator.py +67 -67
  32. absfuyu/general/human.py +74 -78
  33. absfuyu/logger.py +94 -68
  34. absfuyu/pkg_data/__init__.py +29 -25
  35. absfuyu/py.typed +0 -0
  36. absfuyu/sort.py +61 -47
  37. absfuyu/tools/__init__.py +0 -1
  38. absfuyu/tools/converter.py +80 -62
  39. absfuyu/tools/keygen.py +62 -67
  40. absfuyu/tools/obfuscator.py +57 -53
  41. absfuyu/tools/stats.py +24 -24
  42. absfuyu/tools/web.py +10 -9
  43. absfuyu/util/__init__.py +71 -33
  44. absfuyu/util/api.py +53 -43
  45. absfuyu/util/json_method.py +25 -27
  46. absfuyu/util/lunar.py +20 -24
  47. absfuyu/util/path.py +362 -241
  48. absfuyu/util/performance.py +217 -135
  49. absfuyu/util/pkl.py +8 -8
  50. absfuyu/util/zipped.py +17 -19
  51. absfuyu/version.py +160 -147
  52. absfuyu-3.3.3.dist-info/METADATA +124 -0
  53. absfuyu-3.3.3.dist-info/RECORD +59 -0
  54. {absfuyu-3.1.1.dist-info → absfuyu-3.3.3.dist-info}/WHEEL +1 -2
  55. {absfuyu-3.1.1.dist-info → absfuyu-3.3.3.dist-info}/entry_points.txt +1 -0
  56. {absfuyu-3.1.1.dist-info → absfuyu-3.3.3.dist-info/licenses}/LICENSE +1 -1
  57. absfuyu/extensions/dev/pkglib.py +0 -98
  58. absfuyu/game/tictactoe2.py +0 -318
  59. absfuyu-3.1.1.dist-info/METADATA +0 -215
  60. absfuyu-3.1.1.dist-info/RECORD +0 -55
  61. absfuyu-3.1.1.dist-info/top_level.txt +0 -1
absfuyu/fun/__init__.py CHANGED
@@ -3,16 +3,15 @@ Absfuyu: Fun
3
3
  ------------
4
4
  Some fun or weird stuff
5
5
 
6
- Version: 1.0.5
7
- Date updated: 27/11/2023 (dd/mm/yyyy)
6
+ Version: 1.0.6
7
+ Date updated: 05/04/2023 (dd/mm/yyyy)
8
8
  """
9
9
 
10
-
11
10
  # Library
12
11
  ###########################################################################
13
- from datetime import date
14
12
  import subprocess
15
13
  import sys
14
+ from datetime import date
16
15
 
17
16
  from absfuyu.logger import logger
18
17
  from absfuyu.util.api import APIRequest
@@ -55,7 +54,7 @@ def zodiac_sign(
55
54
  0 < month < 13,
56
55
  ]
57
56
  if not all(conditions):
58
- raise SystemExit("Value out of range")
57
+ raise ValueError("Value out of range")
59
58
 
60
59
  zodiac = {
61
60
  "Aquarius": any(
@@ -148,8 +147,8 @@ def im_bored() -> str:
148
147
  """
149
148
  try:
150
149
  api = APIRequest("https://www.boredapi.com/api/activity")
151
- return api.fetch_data_only().json()["activity"]
152
- except:
150
+ return api.fetch_data_only().json()["activity"] # type: ignore
151
+ except Exception:
153
152
  return "FAILED"
154
153
 
155
154
 
absfuyu/fun/tarot.py CHANGED
@@ -75,7 +75,7 @@ class Tarot:
75
75
 
76
76
  :rtype: list[TarotCard]
77
77
  """
78
- tarot_data: list = Pickler.load(self.data_location)
78
+ tarot_data: list = Pickler.load(self.data_location) # type: ignore
79
79
  logger.debug(f"{len(tarot_data)} tarot cards loaded")
80
80
  return [
81
81
  TarotCard(
absfuyu/game/__init__.py CHANGED
@@ -3,65 +3,66 @@ Absfuyu: Game
3
3
  -------------
4
4
  Contain some game that can be played on terminal
5
5
 
6
- Version: 1.0.2
7
- Date updated: 24/11/2023 (mm/dd/yyyy)
6
+ Version: 1.1.0
7
+ Date updated: 14/04/2024 (mm/dd/yyyy)
8
8
  """
9
9
 
10
-
11
- # Module Package
12
- ###########################################################################
13
10
  __all__ = [
14
- "game_escapeLoop", "game_RockPaperScissors",
11
+ "game_escapeLoop",
12
+ "game_RockPaperScissors",
15
13
  ]
16
14
 
17
15
 
18
- # Library
19
- ###########################################################################
20
- from random import choice as __randChoice
16
+ import random
17
+ import time
18
+
19
+ from .game_stat import GameStats
20
+
21
+ # Escape loop
22
+ _ESCAPE_LOOP_GAME_MSG = """\
23
+ Are you sure about this?
24
+ Don't leave me =((
25
+ I can't believe you did this to me!
26
+ Are you very much sure?
27
+ I'll be sad. Pick again please.
28
+ I still don't believe you.
29
+ Choose again.
30
+ You actually have to answer the correct keyword
31
+ I think you need to choose again.
32
+ Last chance!
33
+ Okay okay, i believe you ;)
34
+ Almost there.
35
+ I can do this all day
36
+ So close!
37
+ You can't escape from me.
38
+ How are you still here, just to suffer?
39
+ Never gonna give you up
40
+ Never gonna let you down
41
+ """
21
42
 
22
43
 
23
- # Default games
24
- ###########################################################################
25
44
  def game_escapeLoop() -> None:
26
45
  """Try to escape the infinite loop"""
27
-
46
+
28
47
  init = True
29
48
  welcome_messages = [
30
49
  "Congrats! You are now stuck inside an infinite loop.",
31
- "Do you want to escape this loop?"
50
+ "Do you want to escape this loop?",
32
51
  ]
33
52
 
34
- num1 = __randChoice([2,3,4,5,6,7,8,9,10,11,12])
35
- num2 = __randChoice([2,3,4,5,6,7,8,9,10,11,12])
53
+ num1 = random.choice(range(2, 13))
54
+ num2 = random.choice(range(2, 13))
36
55
  hidden_answer = str(num1 * num2)
37
56
 
38
- game_messages = [
39
- "Are you sure about this?",
40
- "Don't leave me =((",
41
- "I can't believe you did this to me!",
42
- "Are you very much sure?",
43
- "I'll be sad. Pick again please.",
44
- "I still don't believe you.",
45
- "Choose again.",
46
- "You actually have to answer the correct keyword",
47
- "I think you need to choose again.",
48
- "Last chance!",
49
- "Okay okay, i believe you ;)",
50
- "Almost there.",
51
- "I can do this all day",
52
- "So close!",
53
- "You can't escape from me.",
54
- "How are you still here, just to suffer?",
55
- "Never gonna give you up",
56
- "Never gonna let you down",
57
+ gm_msg = {x for x in _ESCAPE_LOOP_GAME_MSG.splitlines() if len(x) > 0}
58
+ game_messages = list(gm_msg) + [
57
59
  f"Hint 01: The keyword is: {num1}",
58
- f"Hint 02: *{num2}",
60
+ f"Hint 02: {num2}",
59
61
  ]
60
62
 
61
- congrats_messages = [
62
- "Congratulation! You've escaped."
63
- ]
64
-
63
+ congrats_messages = ["Congratulation! You've escaped."]
64
+
65
+ start_time = time.time()
65
66
  while True:
66
67
  # Welcome
67
68
  if init:
@@ -69,9 +70,9 @@ def game_escapeLoop() -> None:
69
70
  print(x)
70
71
  answer = str(input())
71
72
  init = False
72
-
73
+
73
74
  # Random text
74
- mess = __randChoice(game_messages)
75
+ mess = random.choice(game_messages)
75
76
  print(mess)
76
77
 
77
78
  # Condition check
@@ -79,24 +80,22 @@ def game_escapeLoop() -> None:
79
80
  if answer == hidden_answer:
80
81
  for x in congrats_messages:
81
82
  print(x)
83
+ stop_time = time.time()
82
84
  break
83
- pass
85
+ print(f"= Escaped in {stop_time-start_time:,.2f}s =")
84
86
 
85
87
 
86
- def game_RockPaperScissors(hard_mode=False):
88
+ # Rock Paper Scissors
89
+ def game_RockPaperScissors(hard_mode: bool = False) -> GameStats:
87
90
  """
88
91
  Rock Paper Scissors
89
-
92
+
90
93
  :param hard_mode: The bot only win or draw (Default: ``False``)
91
94
  :type hard_mode: bool
92
95
  """
93
-
94
- state_dict = {
95
- 0: "rock",
96
- 1: "paper",
97
- 2: "scissors"
98
- }
99
-
96
+
97
+ state_dict = {"0": "rock", "1": "paper", "2": "scissors"}
98
+
100
99
  init = True
101
100
 
102
101
  end_message = "end"
@@ -108,67 +107,62 @@ def game_RockPaperScissors(hard_mode=False):
108
107
 
109
108
  game_messages = [
110
109
  "Pick one option to begin:",
110
+ " ".join([f"{k}={v}" for k, v in state_dict.items()]),
111
111
  ]
112
112
 
113
- game_summary = {
114
- "Win": 0,
115
- "Draw": 0,
116
- "Lose": 0
117
- }
118
-
113
+ game_summary = GameStats()
114
+
119
115
  while True:
120
116
  # Welcome
121
117
  if init:
122
118
  for x in welcome_messages:
123
119
  print(x)
124
120
  init = False
125
-
121
+
126
122
  # Game start
127
123
  print("")
128
124
  for x in game_messages:
129
125
  print(x)
130
- print(state_dict)
131
-
126
+
132
127
  # Player's choice
133
- answer = input()
128
+ answer = input().strip().lower()
134
129
 
135
130
  # Condition check
136
131
  if answer == end_message:
137
132
  print(game_summary)
138
133
  break
139
-
140
- elif answer not in ["0","1","2"]:
134
+
135
+ elif answer not in ["0", "1", "2"]:
141
136
  print("Invalid option. Choose again!")
142
-
137
+
143
138
  else:
144
139
  # Calculation
145
- answer = int(answer)
146
140
  if hard_mode:
147
- if answer == 0:
148
- game_choice = __randChoice([0,1])
149
- if answer == 1:
150
- game_choice = __randChoice([1,2])
151
- if answer == 2:
152
- game_choice = __randChoice([0,2])
141
+ if answer == "0":
142
+ game_choice = random.choice(["0", "1"])
143
+ if answer == "1":
144
+ game_choice = random.choice(["1", "2"])
145
+ if answer == "2":
146
+ game_choice = random.choice(["0", "2"])
153
147
  else:
154
- game_choice = __randChoice([0,1,2])
148
+ game_choice = random.choice(["0", "1", "2"])
155
149
  print(f"You picked: {state_dict[answer]}")
156
150
  print(f"BOT picked: {state_dict[game_choice]}")
157
-
158
- if answer == 2 and game_choice == 0:
151
+
152
+ if answer == "2" and game_choice == "0":
159
153
  print("You Lose!")
160
- game_summary["Lose"] += 1
161
- elif answer == 0 and game_choice == 2:
154
+ game_summary.update_score("lose")
155
+ elif answer == "0" and game_choice == "2":
162
156
  print("You Win!")
163
- game_summary["Win"] += 1
157
+ game_summary.update_score("win")
164
158
  elif answer == game_choice:
165
159
  print("Draw Match!")
166
- game_summary["Draw"] += 1
160
+ game_summary.update_score("draw")
167
161
  elif answer > game_choice:
168
162
  print("You Win!")
169
- game_summary["Win"] += 1
163
+ game_summary.update_score("win")
170
164
  else:
171
165
  print("You Lose!")
172
- game_summary["Lose"] += 1
166
+ game_summary.update_score("lose")
173
167
 
174
- return game_summary
168
+ return game_summary
@@ -0,0 +1,36 @@
1
+ """
2
+ Game: Game Stat
3
+
4
+ Version: 1.0.0
5
+ Date updated: 14/04/2024 (dd/mm/yyyy)
6
+ """
7
+
8
+ __all__ = ["GameStats"]
9
+
10
+
11
+ from dataclasses import dataclass, field
12
+ from typing import Literal
13
+
14
+
15
+ @dataclass
16
+ class GameStats:
17
+ win: int = field(default=0)
18
+ draw: int = field(default=0)
19
+ lose: int = field(default=0)
20
+ win_rate: str = field(init=False)
21
+ _win_rate: float = field(init=False, repr=False)
22
+
23
+ def __post_init__(self) -> None:
24
+ self._update_win_rate()
25
+
26
+ def _update_win_rate(self) -> None:
27
+ try:
28
+ self._win_rate = self.win / (self.win + self.draw + self.lose)
29
+ self.win_rate = f"{self._win_rate*100:,.2f}%"
30
+ except ZeroDivisionError:
31
+ self._win_rate = 0
32
+ self.win_rate = "N/A"
33
+
34
+ def update_score(self, option: Literal["win", "draw", "lose"]) -> None:
35
+ self.__setattr__(option, self.__getattribute__(option) + 1)
36
+ self._update_win_rate()
absfuyu/game/sudoku.py CHANGED
@@ -12,21 +12,12 @@ Credit:
12
12
  - [Solve algo](https://www.techwithtim.net/tutorials/python-programming/sudoku-solver-backtracking/)
13
13
  """
14
14
 
15
-
16
- # Module level
17
- ###########################################################################
18
- __all__ = [
19
- "Sudoku"
20
- ]
15
+ __all__ = ["Sudoku"]
21
16
 
22
17
 
23
- # Library
24
- ###########################################################################
25
- from typing import List
18
+ from typing import List, Literal, Tuple
26
19
 
27
20
 
28
- # Class
29
- ###########################################################################
30
21
  class Sudoku:
31
22
  def __init__(self, sudoku_data: List[List[int]]) -> None:
32
23
  self.data = sudoku_data
@@ -34,21 +25,23 @@ class Sudoku:
34
25
  self._row_len = len(self.data)
35
26
  self._col_len = len(self.data[0])
36
27
  # self.solved = None
28
+
37
29
  def __str__(self) -> str:
38
30
  return f"{self.__class__.__name__}({self.export_to_string()})"
31
+
39
32
  def __repr__(self) -> str:
40
33
  return self.__str__()
41
-
42
- def export_to_string(self, *, style: str = "dot") -> str:
34
+
35
+ def export_to_string(self, *, style: Literal["dot", "zero"] = "dot") -> str:
43
36
  """
44
37
  Export Sudoku data to string form
45
38
 
46
39
  Parameters
47
40
  ----------
48
- style : str
41
+ style : Literal["dot", "zero"]
49
42
  - "zero": ``0`` is ``0``
50
43
  - "dot": ``0`` is ``.``
51
-
44
+
52
45
  Returns
53
46
  -------
54
47
  str
@@ -57,16 +50,16 @@ class Sudoku:
57
50
  style_option = ["zero", "dot"]
58
51
  if style.lower() not in style_option:
59
52
  style = "dot"
60
-
53
+
61
54
  out = "".join(str(self.data))
62
55
  remove = ["[", "]", " ", ","]
63
56
  for x in remove:
64
57
  out = out.replace(x, "")
65
-
58
+
66
59
  if style.startswith("zero"):
67
60
  return out
68
61
  elif style.startswith("dot"):
69
- out = out.replace("0",".")
62
+ out = out.replace("0", ".")
70
63
  return out
71
64
  else:
72
65
  return out
@@ -80,7 +73,7 @@ class Sudoku:
80
73
  ----------
81
74
  string_data : str
82
75
  String data
83
-
76
+
84
77
  Returns
85
78
  -------
86
79
  Sudoku
@@ -102,38 +95,39 @@ class Sudoku:
102
95
  """
103
96
  if len(string_data) == 81:
104
97
  # Convert
105
- sdk = str(string_data).replace(".","0")
106
-
98
+ sdk = str(string_data).replace(".", "0")
99
+
107
100
  # Divide into 9 equal parts
108
101
  temp = []
109
102
  while len(sdk) != 0:
110
103
  temp.append(sdk[:9])
111
104
  sdk = sdk[9:]
112
-
105
+
113
106
  # Turn into list[list[int]]
114
107
  out = []
115
108
  for value in temp:
116
109
  temp_list = [int(x) for x in value]
117
110
  out.append(temp_list)
118
-
111
+
119
112
  else:
120
113
  # Invalid length
121
114
  raise ValueError("Invalid length")
122
115
  return cls(out)
123
-
116
+
124
117
  @classmethod
125
118
  def hardest_sudoku(cls):
126
119
  """
127
- Create Hardest Sudoku instance
120
+ Create Hardest Sudoku instance
128
121
  ([Source](https://www.telegraph.co.uk/news/science/science-news/9359579/Worlds-hardest-sudoku-can-you-crack-it.html))
129
-
122
+
130
123
  Returns
131
124
  -------
132
125
  Sudoku
133
126
  ``Sudoku`` instance
134
127
  """
135
- return cls.from_string("8..........36......7..9.2...5...7.......457.....1...3...1....68..85...1..9....4..")
136
-
128
+ return cls.from_string(
129
+ "8..........36......7..9.2...5...7.......457.....1...3...1....68..85...1..9....4.."
130
+ )
137
131
 
138
132
  def to_board_form(self) -> str:
139
133
  """
@@ -144,7 +138,7 @@ class Sudoku:
144
138
  str
145
139
  Sudoku Board data that ready to print
146
140
 
147
-
141
+
148
142
  Example:
149
143
  --------
150
144
  >>> demo = Sudoku.hardest_sudoku()
@@ -167,22 +161,21 @@ class Sudoku:
167
161
  for row in range(self._row_len):
168
162
  if row % 3 == 0:
169
163
  if row == 0:
170
- out_string = out_string + u" \u250E" + u"\u2500"*29 + u"\u2512\n"
164
+ out_string = out_string + " \u250E" + "\u2500" * 29 + "\u2512\n"
171
165
  else:
172
- out_string = out_string + u" \u2520" + u"\u2500"*29 + u"\u2528\n"
166
+ out_string = out_string + " \u2520" + "\u2500" * 29 + "\u2528\n"
173
167
 
174
168
  for col in range(self._col_len):
175
169
  if col % 3 == 0:
176
- out_string += u" \u2503 "
170
+ out_string += " \u2503 "
177
171
 
178
172
  if col == 8:
179
- out_string = out_string + str(self.data[row][col]) + u" \u2503\n"
173
+ out_string = out_string + str(self.data[row][col]) + " \u2503\n"
180
174
  else:
181
175
  out_string = out_string + str(self.data[row][col]) + " "
182
176
 
183
- out_string = out_string + u" \u2516" + u"\u2500"*29 + u"\u251A"
177
+ out_string = out_string + " \u2516" + "\u2500" * 29 + "\u251A"
184
178
  return out_string
185
-
186
179
 
187
180
  # Solve
188
181
  def _find_empty(self):
@@ -200,15 +193,15 @@ class Sudoku:
200
193
  return (row, col)
201
194
  # Return None when there is no empty cell
202
195
  return None
203
-
204
- def _is_valid(self, number: int, position: tuple) -> bool:
196
+
197
+ def _is_valid(self, number: int, position: Tuple[int, int]) -> bool:
205
198
  """
206
199
  Check valid number value in row, column, box
207
200
  """
208
- row, col = position # unpack tuple
201
+ row, col = position # unpack tuple
209
202
 
210
203
  # Check row
211
- for i in range(self._col_len): # each item in row i; row i has `col_len` items
204
+ for i in range(self._col_len): # each item in row i; row i has `col_len` items
212
205
  if self.data[row][i] == number and col != i:
213
206
  return False
214
207
 
@@ -236,12 +229,12 @@ class Sudoku:
236
229
  # Find empty cell
237
230
  empty_pos = self._find_empty()
238
231
  if empty_pos is None:
239
- return True # solve_state (True: every cell filled)
232
+ return True # solve_state (True: every cell filled)
240
233
  else:
241
234
  # unpack position when exist empty cell
242
235
  row, col = empty_pos
243
236
 
244
- for num in range(1,10): # sudoku value (1-9)
237
+ for num in range(1, 10): # sudoku value (1-9)
245
238
  if self._is_valid(num, empty_pos):
246
239
  self.data[row][col] = num
247
240
 
@@ -253,17 +246,17 @@ class Sudoku:
253
246
 
254
247
  # End recursive
255
248
  return False
256
-
249
+
257
250
  def solve(self):
258
251
  """
259
252
  Solve the Sudoku
260
-
253
+
261
254
  Returns
262
255
  -------
263
256
  Sudoku
264
257
  ``Sudoku`` instance
265
-
266
-
258
+
259
+
267
260
  Example:
268
261
  --------
269
262
  >>> test = Sudoku.hardest_sudoku()
@@ -286,11 +279,11 @@ class Sudoku:
286
279
  self._solve()
287
280
  # self.solved = self.data
288
281
  # self.data = self._original
289
- return __class__(self.data)
290
-
282
+ return self.__class__(self.data)
283
+
291
284
 
292
285
  # Run
293
286
  ###########################################################################
294
287
  if __name__ == "__main__":
295
288
  test = Sudoku.hardest_sudoku()
296
- print(test.solve().to_board_form())
289
+ print(test.solve().to_board_form())