absfuyu 2.8.1__py3-none-any.whl → 3.1.0__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.
- absfuyu/__init__.py +13 -10
- absfuyu/__main__.py +55 -38
- absfuyu/config/config.json +3 -3
- absfuyu/core.py +39 -25
- absfuyu/everything.py +4 -5
- absfuyu/extensions/__init__.py +3 -2
- absfuyu/extensions/dev/__init__.py +162 -19
- absfuyu/extensions/dev/password_hash.py +11 -10
- absfuyu/extensions/dev/passwordlib.py +256 -0
- absfuyu/extensions/dev/pkglib.py +53 -57
- absfuyu/extensions/dev/project_starter.py +58 -0
- absfuyu/extensions/dev/shutdownizer.py +8 -0
- absfuyu/extensions/extra/data_analysis.py +687 -119
- absfuyu/fun/__init__.py +88 -118
- absfuyu/fun/tarot.py +32 -34
- absfuyu/game/tictactoe2.py +90 -78
- absfuyu/{collections → general}/__init__.py +14 -12
- absfuyu/{collections → general}/content.py +105 -87
- absfuyu/{collections → general}/data_extension.py +652 -172
- absfuyu/{collections → general}/generator.py +65 -4
- absfuyu/{collections → general}/human.py +28 -3
- absfuyu/pkg_data/__init__.py +14 -36
- absfuyu/pkg_data/chemistry.pkl +0 -0
- absfuyu/pkg_data/tarot.pkl +0 -0
- absfuyu/tools/converter.py +58 -31
- absfuyu/tools/obfuscator.py +4 -4
- absfuyu/tools/stats.py +4 -4
- absfuyu/tools/web.py +2 -2
- absfuyu/util/lunar.py +144 -123
- absfuyu/util/path.py +22 -3
- absfuyu/util/performance.py +101 -14
- absfuyu/version.py +93 -84
- {absfuyu-2.8.1.dist-info → absfuyu-3.1.0.dist-info}/METADATA +63 -33
- absfuyu-3.1.0.dist-info/RECORD +55 -0
- {absfuyu-2.8.1.dist-info → absfuyu-3.1.0.dist-info}/WHEEL +1 -1
- absfuyu-3.1.0.dist-info/entry_points.txt +2 -0
- absfuyu/pkg_data/chemistry.json +0 -6268
- absfuyu/pkg_data/tarot.json +0 -2593
- absfuyu-2.8.1.dist-info/RECORD +0 -52
- absfuyu-2.8.1.dist-info/entry_points.txt +0 -2
- {absfuyu-2.8.1.dist-info → absfuyu-3.1.0.dist-info}/LICENSE +0 -0
- {absfuyu-2.8.1.dist-info → absfuyu-3.1.0.dist-info}/top_level.txt +0 -0
absfuyu/game/tictactoe2.py
CHANGED
|
@@ -2,24 +2,22 @@
|
|
|
2
2
|
Game: Tic Tac Toe
|
|
3
3
|
-----------------
|
|
4
4
|
|
|
5
|
-
Version: 2.0.
|
|
6
|
-
Date updated:
|
|
5
|
+
Version: 2.0.2
|
|
6
|
+
Date updated: 04/12/2023 (mm/dd/yyyy)
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
11
11
|
###########################################################################
|
|
12
|
-
__all__ = [
|
|
13
|
-
"TicTacToe", "GameMode"
|
|
14
|
-
]
|
|
12
|
+
__all__ = ["TicTacToe", "GameMode"]
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
# Library
|
|
18
16
|
###########################################################################
|
|
19
|
-
from collections import namedtuple
|
|
17
|
+
# from collections import namedtuple
|
|
20
18
|
import random
|
|
21
19
|
import time
|
|
22
|
-
from typing import Dict, List, Union
|
|
20
|
+
from typing import Dict, List, NamedTuple, Union
|
|
23
21
|
|
|
24
22
|
from absfuyu.core import CLITextColor
|
|
25
23
|
|
|
@@ -27,7 +25,12 @@ from absfuyu.core import CLITextColor
|
|
|
27
25
|
# Class
|
|
28
26
|
###########################################################################
|
|
29
27
|
BoardGame = List[List[str]]
|
|
30
|
-
Pos = namedtuple("Pos", ["row", "col"])
|
|
28
|
+
# Pos = namedtuple("Pos", ["row", "col"]) # Position
|
|
29
|
+
class Pos(NamedTuple):
|
|
30
|
+
"""Position"""
|
|
31
|
+
row: int
|
|
32
|
+
col: int
|
|
33
|
+
|
|
31
34
|
|
|
32
35
|
class GameMode:
|
|
33
36
|
ONE_V_ONE = "1v1"
|
|
@@ -37,18 +40,18 @@ class GameMode:
|
|
|
37
40
|
|
|
38
41
|
class TicTacToe:
|
|
39
42
|
"""Tic Tac Toe game"""
|
|
43
|
+
|
|
40
44
|
def __init__(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
) -> None:
|
|
45
|
+
self,
|
|
46
|
+
game_size: int = 3,
|
|
47
|
+
*,
|
|
48
|
+
x: str = "X",
|
|
49
|
+
o: str = "O",
|
|
50
|
+
blank: str = " ",
|
|
51
|
+
position_split_symbol: str = ",",
|
|
52
|
+
end_break_word: str = "END",
|
|
53
|
+
welcome_message: bool = True,
|
|
54
|
+
) -> None:
|
|
52
55
|
"""
|
|
53
56
|
:param game_size: Board size (Default: 3x3)
|
|
54
57
|
:param x: X symbol
|
|
@@ -76,56 +79,57 @@ class TicTacToe:
|
|
|
76
79
|
|
|
77
80
|
def __str__(self) -> str:
|
|
78
81
|
return f"{self.__class__.__name__}(game_size={self.row_size})"
|
|
82
|
+
|
|
79
83
|
def __repr__(self) -> str:
|
|
80
84
|
return self.__str__()
|
|
81
|
-
|
|
85
|
+
|
|
82
86
|
# Game
|
|
83
87
|
def _gen_board(self) -> BoardGame:
|
|
84
88
|
"""
|
|
85
89
|
Generate board game
|
|
86
90
|
"""
|
|
87
91
|
board = [
|
|
88
|
-
[self.BLANK for _ in range(self.row_size)]
|
|
89
|
-
for _ in range(self.col_size)
|
|
92
|
+
[self.BLANK for _ in range(self.row_size)] for _ in range(self.col_size)
|
|
90
93
|
]
|
|
91
94
|
return board
|
|
92
|
-
|
|
95
|
+
|
|
93
96
|
def _check_state(self) -> Dict[str, Union[str, int]]:
|
|
94
97
|
"""
|
|
95
98
|
Check game winning state
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
dict[str, str | int]
|
|
103
|
+
``X`` | ``O`` | ``BLANK``
|
|
100
104
|
"""
|
|
101
105
|
|
|
102
106
|
# Check rows
|
|
103
107
|
for row in range(self.row_size):
|
|
104
108
|
if len(set(self.board[row])) == 1:
|
|
105
109
|
key = list(set(self.board[row]))[0]
|
|
106
|
-
return {"key": key, "location": "row", "pos": row}
|
|
110
|
+
return {"key": key, "location": "row", "pos": row} # modified
|
|
107
111
|
|
|
108
112
|
# Check cols
|
|
109
113
|
for col in range(self.col_size):
|
|
110
114
|
temp = [self.board[row][col] for row in range(self.row_size)]
|
|
111
115
|
if len(set(temp)) == 1:
|
|
112
116
|
key = list(set(temp))[0]
|
|
113
|
-
return {"key": key, "location": "col", "pos": col}
|
|
114
|
-
|
|
117
|
+
return {"key": key, "location": "col", "pos": col} # modified
|
|
118
|
+
|
|
115
119
|
# Check diagonal
|
|
116
120
|
diag1 = [self.board[i][i] for i in range(len(self.board))]
|
|
117
121
|
if len(set(diag1)) == 1:
|
|
118
122
|
key = list(set(diag1))[0]
|
|
119
|
-
return {"key": key, "location": "diag", "pos": 1}
|
|
120
|
-
|
|
121
|
-
diag2 = [self.board[i][len(self.board)-i-1] for i in range(len(self.board))]
|
|
123
|
+
return {"key": key, "location": "diag", "pos": 1} # modified
|
|
124
|
+
|
|
125
|
+
diag2 = [self.board[i][len(self.board) - i - 1] for i in range(len(self.board))]
|
|
122
126
|
if len(set(diag2)) == 1:
|
|
123
127
|
key = list(set(diag2))[0]
|
|
124
|
-
return {"key": key, "location": "diag", "pos": 2}
|
|
125
|
-
|
|
128
|
+
return {"key": key, "location": "diag", "pos": 2} # modified
|
|
129
|
+
|
|
126
130
|
# Else
|
|
127
131
|
return {"key": self.BLANK}
|
|
128
|
-
|
|
132
|
+
|
|
129
133
|
@staticmethod
|
|
130
134
|
def _print_board(board: BoardGame) -> None:
|
|
131
135
|
"""
|
|
@@ -138,7 +142,7 @@ class TicTacToe:
|
|
|
138
142
|
for col in range(ncol):
|
|
139
143
|
print(f"| {board[row][col]} ", end="")
|
|
140
144
|
print(f"|\n{'+---'*length}+")
|
|
141
|
-
|
|
145
|
+
|
|
142
146
|
def _win_hightlight(self) -> BoardGame:
|
|
143
147
|
"""
|
|
144
148
|
Hight light the win by removing other placed key
|
|
@@ -165,44 +169,44 @@ class TicTacToe:
|
|
|
165
169
|
board[i][i] = detail["key"]
|
|
166
170
|
else:
|
|
167
171
|
for i in range(len(board)):
|
|
168
|
-
board[i][len(board)-i-1] = detail["key"]
|
|
169
|
-
|
|
172
|
+
board[i][len(board) - i - 1] = detail["key"]
|
|
173
|
+
|
|
170
174
|
# Output
|
|
171
175
|
return board
|
|
172
|
-
|
|
176
|
+
|
|
173
177
|
def _is_blank(self, pos: Pos) -> bool:
|
|
174
178
|
"""Check if current pos is filled"""
|
|
175
179
|
return self.board[pos.row][pos.col] == self.BLANK
|
|
176
180
|
|
|
177
181
|
@staticmethod
|
|
178
|
-
def _convert_bot_output(pos: Pos):
|
|
182
|
+
def _convert_bot_output(pos: Pos) -> Pos:
|
|
179
183
|
"""
|
|
180
184
|
Turn to real pos by:
|
|
181
|
-
|
|
182
|
-
-
|
|
185
|
+
|
|
186
|
+
- +1 to ``row`` and ``col``
|
|
187
|
+
- convert into ``str``
|
|
183
188
|
"""
|
|
184
189
|
return Pos(pos.row + 1, pos.col + 1)
|
|
185
|
-
|
|
186
|
-
def _generate_random_move(self):
|
|
190
|
+
|
|
191
|
+
def _generate_random_move(self) -> Pos:
|
|
187
192
|
"""
|
|
188
193
|
Generate a random move from board game
|
|
189
194
|
"""
|
|
190
195
|
while True:
|
|
191
196
|
output = Pos(
|
|
192
|
-
random.randint(0, len(self.board)-1),
|
|
193
|
-
random.randint(0, len(self.board)-1)
|
|
197
|
+
random.randint(0, len(self.board) - 1),
|
|
198
|
+
random.randint(0, len(self.board) - 1),
|
|
194
199
|
)
|
|
195
200
|
if self._is_blank(output):
|
|
196
201
|
break
|
|
197
202
|
return self._convert_bot_output(output)
|
|
198
203
|
|
|
199
|
-
|
|
200
204
|
def play(
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
self,
|
|
206
|
+
game_mode: str = GameMode.ONE_V_BOT,
|
|
207
|
+
*,
|
|
208
|
+
bot_time: float = 0,
|
|
209
|
+
) -> None:
|
|
206
210
|
"""
|
|
207
211
|
Play a game of Tic Tac Toe
|
|
208
212
|
|
|
@@ -210,7 +214,7 @@ class TicTacToe:
|
|
|
210
214
|
----------
|
|
211
215
|
game_mode : str
|
|
212
216
|
Game mode
|
|
213
|
-
|
|
217
|
+
|
|
214
218
|
bot_time : float
|
|
215
219
|
Time sleep between each bot move (Default: ``0``)
|
|
216
220
|
"""
|
|
@@ -223,63 +227,71 @@ class TicTacToe:
|
|
|
223
227
|
|
|
224
228
|
# Welcome message
|
|
225
229
|
if self.welcome_message:
|
|
226
|
-
print(
|
|
230
|
+
print(
|
|
231
|
+
f"""\
|
|
227
232
|
{CLITextColor.GREEN}Welcome to Tic Tac Toe!
|
|
228
233
|
|
|
229
234
|
{CLITextColor.YELLOW}Rules: Match lines vertically, horizontally or diagonally
|
|
230
235
|
{CLITextColor.YELLOW}{self.X} goes first, then {self.O}
|
|
231
|
-
{CLITextColor.RED}Type '{self.END_BREAK}' to end the game{CLITextColor.RESET}"""
|
|
232
|
-
|
|
236
|
+
{CLITextColor.RED}Type '{self.END_BREAK}' to end the game{CLITextColor.RESET}"""
|
|
237
|
+
)
|
|
238
|
+
|
|
233
239
|
# Check gamemode
|
|
234
240
|
_game_mode = [
|
|
235
|
-
"1v1",
|
|
236
|
-
"1v0",
|
|
237
|
-
"0v0"
|
|
241
|
+
"1v1", # Player vs player
|
|
242
|
+
"1v0", # Player vs BOT
|
|
243
|
+
"0v0", # BOT vs BOT
|
|
238
244
|
]
|
|
239
245
|
if game_mode not in _game_mode:
|
|
240
|
-
game_mode = _game_mode[1]
|
|
246
|
+
game_mode = _game_mode[1] # Force vs BOT
|
|
241
247
|
if game_mode.startswith(GameMode.ONE_V_BOT):
|
|
242
248
|
BOT = True
|
|
243
249
|
if game_mode.startswith(GameMode.BOT_V_BOT):
|
|
244
250
|
BOT = True
|
|
245
251
|
BOT2 = True
|
|
246
|
-
|
|
252
|
+
|
|
247
253
|
# Game
|
|
248
254
|
self._print_board(self.board)
|
|
249
255
|
|
|
250
256
|
place_pos = None
|
|
251
257
|
while state == self.BLANK and filled < self.row_size**2:
|
|
252
258
|
print(f"{CLITextColor.BLUE}{current_player}'s turn:{CLITextColor.RESET}")
|
|
253
|
-
|
|
254
|
-
try:
|
|
259
|
+
|
|
260
|
+
try: # Error handling
|
|
255
261
|
if (BOT and current_player == self.O) or BOT2:
|
|
256
262
|
move = self._generate_random_move()
|
|
257
263
|
str_move = f"{move.row}{self.POS_SPLIT}{move.col}"
|
|
258
264
|
move = str_move
|
|
259
265
|
else:
|
|
260
|
-
move = input(
|
|
266
|
+
move = input(
|
|
267
|
+
f"Place {CLITextColor.BLUE}{current_player}{CLITextColor.RESET} at {CLITextColor.BLUE}<row{self.POS_SPLIT}col>:{CLITextColor.RESET} "
|
|
268
|
+
)
|
|
261
269
|
|
|
262
|
-
if move.upper() == self.END_BREAK:
|
|
270
|
+
if move.upper() == self.END_BREAK: # Failsafe
|
|
263
271
|
print(f"{CLITextColor.RED}Game ended{CLITextColor.RESET}")
|
|
264
272
|
break
|
|
265
|
-
|
|
273
|
+
|
|
266
274
|
move = move.split(self.POS_SPLIT)
|
|
267
275
|
row = int(move[0])
|
|
268
276
|
col = int(move[1])
|
|
269
|
-
place_pos = Pos(row-1, col-1)
|
|
277
|
+
place_pos = Pos(row - 1, col - 1)
|
|
270
278
|
|
|
271
279
|
if self._is_blank(place_pos):
|
|
272
280
|
self.board[place_pos.row][place_pos.col] = current_player
|
|
273
281
|
filled += 1
|
|
274
|
-
|
|
275
|
-
else:
|
|
276
|
-
print(
|
|
282
|
+
|
|
283
|
+
else: # User and BOT error
|
|
284
|
+
print(
|
|
285
|
+
f"{CLITextColor.RED}Invalid move, please try again{CLITextColor.RESET}"
|
|
286
|
+
)
|
|
277
287
|
continue
|
|
278
|
-
|
|
279
|
-
except:
|
|
280
|
-
print(
|
|
288
|
+
|
|
289
|
+
except: # User error
|
|
290
|
+
print(
|
|
291
|
+
f"{CLITextColor.RED}Invalid move, please try again{CLITextColor.RESET}"
|
|
292
|
+
)
|
|
281
293
|
continue
|
|
282
|
-
|
|
294
|
+
|
|
283
295
|
state = self._check_state()["key"]
|
|
284
296
|
self._print_board(self.board)
|
|
285
297
|
|
|
@@ -288,9 +300,9 @@ class TicTacToe:
|
|
|
288
300
|
self._print_board(self._win_hightlight())
|
|
289
301
|
|
|
290
302
|
# Change turn
|
|
291
|
-
if BOT2:
|
|
303
|
+
if BOT2: # BOT delay
|
|
292
304
|
time.sleep(bot_time)
|
|
293
|
-
|
|
305
|
+
|
|
294
306
|
if current_player == self.X:
|
|
295
307
|
current_player = self.O
|
|
296
308
|
else:
|
|
@@ -303,4 +315,4 @@ class TicTacToe:
|
|
|
303
315
|
# Run
|
|
304
316
|
###########################################################################
|
|
305
317
|
if __name__ == "__main__":
|
|
306
|
-
pass
|
|
318
|
+
pass
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Absfuyu:
|
|
3
|
-
|
|
2
|
+
Absfuyu: General
|
|
3
|
+
----------------
|
|
4
4
|
Collection of useful classes
|
|
5
5
|
|
|
6
|
-
Version: 1.1.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 1.1.3
|
|
7
|
+
Date updated: 26/11/2023 (dd/mm/yyyy)
|
|
8
8
|
|
|
9
9
|
Features:
|
|
10
10
|
---------
|
|
@@ -16,9 +16,7 @@ Features:
|
|
|
16
16
|
|
|
17
17
|
# Libary
|
|
18
18
|
###########################################################################
|
|
19
|
-
from absfuyu.
|
|
20
|
-
content, data_extension, generator, human
|
|
21
|
-
)
|
|
19
|
+
from absfuyu.general import content, data_extension, generator, human
|
|
22
20
|
|
|
23
21
|
|
|
24
22
|
# Class
|
|
@@ -29,27 +27,28 @@ class Dummy:
|
|
|
29
27
|
|
|
30
28
|
Update attribute through dict
|
|
31
29
|
"""
|
|
30
|
+
|
|
32
31
|
def __init__(self, data: dict = None) -> None:
|
|
33
32
|
try:
|
|
34
33
|
self.__dict__.update(data)
|
|
35
34
|
except:
|
|
36
35
|
pass
|
|
37
|
-
|
|
36
|
+
|
|
38
37
|
def __str__(self) -> str:
|
|
39
38
|
class_name = self.__class__.__name__
|
|
40
39
|
return f"{class_name}({self.__dict__})"
|
|
41
40
|
|
|
42
41
|
def __repr__(self) -> str:
|
|
43
42
|
return self.__str__()
|
|
44
|
-
|
|
43
|
+
|
|
45
44
|
def dir_(self):
|
|
46
45
|
"""List ``property``"""
|
|
47
46
|
return [x for x in self.__dir__() if not x.startswith("_")]
|
|
48
|
-
|
|
47
|
+
|
|
49
48
|
def update(self, data: dict) -> None:
|
|
50
49
|
"""
|
|
51
50
|
Update with dict data
|
|
52
|
-
|
|
51
|
+
|
|
53
52
|
:param data: Dict data
|
|
54
53
|
:type data: dict
|
|
55
54
|
"""
|
|
@@ -58,10 +57,13 @@ class Dummy:
|
|
|
58
57
|
|
|
59
58
|
class ClassBase:
|
|
60
59
|
"""Class base for other class"""
|
|
60
|
+
|
|
61
61
|
def __init__(self) -> None:
|
|
62
62
|
pass
|
|
63
|
+
|
|
63
64
|
def __str__(self) -> str:
|
|
64
65
|
return f"{self.__class__.__name__}({self._get_key_and_val_for_print()})"
|
|
66
|
+
|
|
65
67
|
def __repr__(self) -> str:
|
|
66
68
|
return self.__str__()
|
|
67
69
|
|
|
@@ -81,4 +83,4 @@ class ClassBase:
|
|
|
81
83
|
# Run
|
|
82
84
|
###########################################################################
|
|
83
85
|
if __name__ == "__main__":
|
|
84
|
-
pass
|
|
86
|
+
pass
|