wocli 0.2.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.
- wocli/__init__.py +3 -0
- wocli/commands/__init__.py +1 -0
- wocli/commands/badapple.py +51 -0
- wocli/commands/battery.py +124 -0
- wocli/commands/cow.py +58 -0
- wocli/commands/dead.py +41 -0
- wocli/commands/dino.py +229 -0
- wocli/commands/glitch.py +52 -0
- wocli/commands/goodbye.py +40 -0
- wocli/commands/gpa.py +84 -0
- wocli/commands/hash_cmd.py +41 -0
- wocli/commands/ip.py +127 -0
- wocli/commands/lolcat.py +31 -0
- wocli/commands/luck.py +38 -0
- wocli/commands/matrix.py +77 -0
- wocli/commands/path_cmd.py +37 -0
- wocli/commands/port.py +101 -0
- wocli/commands/progress.py +68 -0
- wocli/commands/qr_cmd.py +50 -0
- wocli/commands/regex_cmd.py +39 -0
- wocli/commands/sys_cmd.py +157 -0
- wocli/commands/time_cmd.py +57 -0
- wocli/commands/tree.py +60 -0
- wocli/commands/typing_cmd.py +69 -0
- wocli/commands/wifi_cmd.py +117 -0
- wocli/main.py +129 -0
- wocli-0.2.0.dist-info/METADATA +16 -0
- wocli-0.2.0.dist-info/RECORD +32 -0
- wocli-0.2.0.dist-info/WHEEL +5 -0
- wocli-0.2.0.dist-info/entry_points.txt +2 -0
- wocli-0.2.0.dist-info/licenses/LICENSE +21 -0
- wocli-0.2.0.dist-info/top_level.txt +1 -0
wocli/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""wocli command modules."""
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""wocli badapple - 播放 Bad Apple!! ASCII 动画"""
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
C_WHITE = "\033[97m"
|
|
7
|
+
C_RESET = "\033[0m"
|
|
8
|
+
|
|
9
|
+
FRAME_FILE = os.path.join(os.path.dirname(__file__), "frames.txt")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def load_frames():
|
|
13
|
+
"""加载帧序列,返回帧列表"""
|
|
14
|
+
if not os.path.exists(FRAME_FILE):
|
|
15
|
+
print("\n frames.txt 未找到,请确保下载了 Bad Apple ASCII 帧序列并放到 commands/ 目录。")
|
|
16
|
+
print(" 下载地址: https://raw.githubusercontent.com/kevinjycui/bad-apple/main/frames.txt\n")
|
|
17
|
+
return None
|
|
18
|
+
with open(FRAME_FILE, "r", encoding="utf-8") as f:
|
|
19
|
+
data = f.read()
|
|
20
|
+
# 帧之间用 SPLIT 分隔,每一帧是一段文本
|
|
21
|
+
frames = data.split("\nSPLIT\n")
|
|
22
|
+
return frames
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def run():
|
|
26
|
+
print("\n [ Bad Apple!! ]")
|
|
27
|
+
print(" 正在加载帧序列...")
|
|
28
|
+
frames = load_frames()
|
|
29
|
+
if not frames:
|
|
30
|
+
return
|
|
31
|
+
print(f" 共 {len(frames)} 帧,按 Enter 开始播放...")
|
|
32
|
+
input()
|
|
33
|
+
|
|
34
|
+
# 隐藏光标
|
|
35
|
+
sys.stdout.write("\033[?25l")
|
|
36
|
+
sys.stdout.flush()
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
for frame in frames:
|
|
40
|
+
# 将光标移到终端左上角(不清屏,直接覆盖)
|
|
41
|
+
sys.stdout.write("\033[H")
|
|
42
|
+
sys.stdout.write(C_WHITE + frame + C_RESET)
|
|
43
|
+
sys.stdout.flush()
|
|
44
|
+
time.sleep(1 / 30) # 30fps,可根据机器性能调整
|
|
45
|
+
except KeyboardInterrupt:
|
|
46
|
+
pass
|
|
47
|
+
finally:
|
|
48
|
+
sys.stdout.write("\033[?25h") # 恢复光标
|
|
49
|
+
sys.stdout.write(C_RESET)
|
|
50
|
+
sys.stdout.flush()
|
|
51
|
+
print("\n 播放完毕。")
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""wocli battery - 电池信息与健康度打分"""
|
|
2
|
+
import subprocess
|
|
3
|
+
import platform
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_battery_macos():
|
|
8
|
+
try:
|
|
9
|
+
result = subprocess.run(["pmset", "-g", "batt"], capture_output=True, text=True)
|
|
10
|
+
output = result.stdout
|
|
11
|
+
# 电量
|
|
12
|
+
pct_match = re.search(r"(\d{1,3})%", output)
|
|
13
|
+
percent = int(pct_match.group(1)) if pct_match else -1
|
|
14
|
+
# 充电状态
|
|
15
|
+
status = "未知"
|
|
16
|
+
if "charging" in output:
|
|
17
|
+
status = "充电中"
|
|
18
|
+
elif "discharging" in output:
|
|
19
|
+
status = "使用中"
|
|
20
|
+
elif "charged" in output:
|
|
21
|
+
status = "已充满"
|
|
22
|
+
# 健康度和循环次数
|
|
23
|
+
try:
|
|
24
|
+
health = subprocess.run(
|
|
25
|
+
["system_profiler", "SPPowerDataType"],
|
|
26
|
+
capture_output=True, text=True
|
|
27
|
+
)
|
|
28
|
+
cycles_match = re.search(r"Cycle Count:\s*(\d+)", health.stdout)
|
|
29
|
+
cycles = int(cycles_match.group(1)) if cycles_match else -1
|
|
30
|
+
max_match = re.search(r"Maximum Capacity:\s*(\d+)%", health.stdout)
|
|
31
|
+
max_cap = int(max_match.group(1)) if max_match else 100
|
|
32
|
+
except:
|
|
33
|
+
cycles = -1
|
|
34
|
+
max_cap = 100
|
|
35
|
+
return percent, status, cycles, max_cap
|
|
36
|
+
except:
|
|
37
|
+
return -1, "未知", -1, 100
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_battery_windows():
|
|
41
|
+
try:
|
|
42
|
+
result = subprocess.run(
|
|
43
|
+
["wmic", "path", "Win32_Battery", "get", "EstimatedChargeRemaining,EstimatedRunTime,BatteryStatus"],
|
|
44
|
+
capture_output=True, text=True
|
|
45
|
+
)
|
|
46
|
+
lines = [l.strip() for l in result.stdout.split("\n") if l.strip()]
|
|
47
|
+
if len(lines) < 2:
|
|
48
|
+
return -1, "未知", -1, 100
|
|
49
|
+
parts = lines[1].split()
|
|
50
|
+
percent = int(parts[0]) if parts else -1
|
|
51
|
+
status_map = {"1": "使用中", "2": "充电中", "3": "已充满"}
|
|
52
|
+
status = status_map.get(parts[1], "未知") if len(parts) > 1 else "未知"
|
|
53
|
+
return percent, status, -1, 100
|
|
54
|
+
except:
|
|
55
|
+
return -1, "未知", -1, 100
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_battery_linux():
|
|
59
|
+
try:
|
|
60
|
+
with open("/sys/class/power_supply/BAT0/capacity", "r") as f:
|
|
61
|
+
percent = int(f.read().strip())
|
|
62
|
+
with open("/sys/class/power_supply/BAT0/status", "r") as f:
|
|
63
|
+
raw = f.read().strip()
|
|
64
|
+
status_map = {"Discharging": "使用中", "Charging": "充电中", "Full": "已充满"}
|
|
65
|
+
status = status_map.get(raw, raw)
|
|
66
|
+
return percent, status, -1, 100
|
|
67
|
+
except:
|
|
68
|
+
return -1, "未知", -1, 100
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def score_battery(percent, cycles, max_cap):
|
|
72
|
+
if percent < 0:
|
|
73
|
+
return 0, "无数据"
|
|
74
|
+
charge_score = percent
|
|
75
|
+
if cycles > 0:
|
|
76
|
+
cycle_score = max(0, 100 - cycles * 0.1)
|
|
77
|
+
else:
|
|
78
|
+
cycle_score = 100
|
|
79
|
+
health_score = max_cap
|
|
80
|
+
total = charge_score * 0.3 + cycle_score * 0.3 + health_score * 0.4
|
|
81
|
+
total = min(100, total)
|
|
82
|
+
|
|
83
|
+
if total >= 95:
|
|
84
|
+
grade = "S级 · 古希腊掌管电池的神"
|
|
85
|
+
elif total >= 85:
|
|
86
|
+
grade = "A级 · 还能战三年"
|
|
87
|
+
elif total >= 70:
|
|
88
|
+
grade = "B级 · 电池有点虚了"
|
|
89
|
+
elif total >= 50:
|
|
90
|
+
grade = "C级 · 已经离不开充电器"
|
|
91
|
+
else:
|
|
92
|
+
grade = "D级 · 电池这么老,零百加速只要三十分钟吧"
|
|
93
|
+
|
|
94
|
+
return round(total, 2), grade
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def run():
|
|
98
|
+
system = platform.system()
|
|
99
|
+
if system == "Darwin":
|
|
100
|
+
percent, status, cycles, max_cap = get_battery_macos()
|
|
101
|
+
elif system == "Windows":
|
|
102
|
+
percent, status, cycles, max_cap = get_battery_windows()
|
|
103
|
+
else:
|
|
104
|
+
percent, status, cycles, max_cap = get_battery_linux()
|
|
105
|
+
|
|
106
|
+
if percent < 0:
|
|
107
|
+
print("\n 无法获取电池信息。\n")
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
score_val, grade = score_battery(percent, cycles, max_cap)
|
|
111
|
+
bar_len = 20
|
|
112
|
+
filled = int(bar_len * percent / 100)
|
|
113
|
+
bar = "=" * filled + "-" * (bar_len - filled)
|
|
114
|
+
|
|
115
|
+
print()
|
|
116
|
+
print(f" 当前电量:[{bar}] {percent}%")
|
|
117
|
+
print(f" 充电状态:{status}")
|
|
118
|
+
if cycles >= 0:
|
|
119
|
+
print(f" 循环次数:{cycles} 次")
|
|
120
|
+
if max_cap < 100:
|
|
121
|
+
print(f" 最大容量:{max_cap}%")
|
|
122
|
+
print(f" 健康评分:{score_val:.2f} / 100.00")
|
|
123
|
+
print(f" 评级:{grade}")
|
|
124
|
+
print()
|
wocli/commands/cow.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""wocli cow - ASCII牛说你说的话."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
COW = r"""
|
|
7
|
+
\ ^__^
|
|
8
|
+
\ (oo)\_______
|
|
9
|
+
(__)\ )\/\
|
|
10
|
+
||----w |
|
|
11
|
+
|| ||
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def make_bubble(text):
|
|
16
|
+
"""生成对话气泡."""
|
|
17
|
+
lines = []
|
|
18
|
+
words = text.split()
|
|
19
|
+
line = ""
|
|
20
|
+
for word in words:
|
|
21
|
+
if len(line) + len(word) + 1 <= 36:
|
|
22
|
+
line += (" " + word) if line else word
|
|
23
|
+
else:
|
|
24
|
+
lines.append(line)
|
|
25
|
+
line = word
|
|
26
|
+
if line:
|
|
27
|
+
lines.append(line)
|
|
28
|
+
|
|
29
|
+
max_len = max(len(l) for l in lines) if lines else 0
|
|
30
|
+
top = " " + "_" * (max_len + 2)
|
|
31
|
+
bottom = " " + "-" * (max_len + 2)
|
|
32
|
+
|
|
33
|
+
bubble = [top]
|
|
34
|
+
if len(lines) == 1:
|
|
35
|
+
bubble.append(f" < {lines[0]} >")
|
|
36
|
+
else:
|
|
37
|
+
for i, l in enumerate(lines):
|
|
38
|
+
if i == 0:
|
|
39
|
+
bubble.append(f" / {l:<{max_len}} \\")
|
|
40
|
+
elif i == len(lines) - 1:
|
|
41
|
+
bubble.append(f" \\ {l:<{max_len}} /")
|
|
42
|
+
else:
|
|
43
|
+
bubble.append(f" | {l:<{max_len}} |")
|
|
44
|
+
bubble.append(bottom)
|
|
45
|
+
return "\n".join(bubble)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def run():
|
|
49
|
+
"""运行 cow 命令."""
|
|
50
|
+
if len(sys.argv) > 1:
|
|
51
|
+
text = " ".join(sys.argv[1:])
|
|
52
|
+
else:
|
|
53
|
+
text = "哞————(无意味)"
|
|
54
|
+
|
|
55
|
+
print()
|
|
56
|
+
print(make_bubble(text))
|
|
57
|
+
print(COW)
|
|
58
|
+
print()
|
wocli/commands/dead.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""wocli dead - 伪装终端死机"""
|
|
2
|
+
import sys
|
|
3
|
+
import time
|
|
4
|
+
import random
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def run():
|
|
8
|
+
print()
|
|
9
|
+
print(" !! WARNING: Kernel panic detected !!")
|
|
10
|
+
time.sleep(1)
|
|
11
|
+
|
|
12
|
+
# 花屏
|
|
13
|
+
chars = "!@#$%^&*()_+-=[]{}|;:',.<>?/~`"
|
|
14
|
+
colors = [31, 32, 33, 34, 35, 36, 91, 92, 93, 94, 95, 96]
|
|
15
|
+
for _ in range(20):
|
|
16
|
+
line = " " + "".join(random.choice(chars) for _ in range(60))
|
|
17
|
+
color = random.choice(colors)
|
|
18
|
+
sys.stdout.write(f"\033[{color}m{line}\033[0m\n")
|
|
19
|
+
sys.stdout.flush()
|
|
20
|
+
time.sleep(0.05)
|
|
21
|
+
|
|
22
|
+
time.sleep(0.5)
|
|
23
|
+
|
|
24
|
+
# 蓝屏
|
|
25
|
+
sys.stdout.write("\033[44m\033[37m")
|
|
26
|
+
sys.stdout.write("\033[2J\033[H")
|
|
27
|
+
print()
|
|
28
|
+
print(" *** SYSTEM ERROR ***")
|
|
29
|
+
print()
|
|
30
|
+
print(" A fatal exception has occurred at 0xDEADBEEF")
|
|
31
|
+
print(" The system has been halted.")
|
|
32
|
+
print()
|
|
33
|
+
print(" Attempting to recover...")
|
|
34
|
+
sys.stdout.flush()
|
|
35
|
+
|
|
36
|
+
time.sleep(3)
|
|
37
|
+
|
|
38
|
+
# 恢复
|
|
39
|
+
sys.stdout.write("\033[0m\033[2J\033[H")
|
|
40
|
+
sys.stdout.write(" Just kidding. Your terminal is fine.\n\n")
|
|
41
|
+
sys.stdout.flush()
|
wocli/commands/dino.py
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import sys, os, time, random, platform, signal
|
|
2
|
+
|
|
3
|
+
W, H = 70, 20
|
|
4
|
+
GROUND = H - 3
|
|
5
|
+
X0 = 10
|
|
6
|
+
C_ORANGE = "\033[38;5;214m"
|
|
7
|
+
C_GREEN = "\033[32m"
|
|
8
|
+
C_WHITE = "\033[97m"
|
|
9
|
+
C_RESET = "\033[0m"
|
|
10
|
+
|
|
11
|
+
CLAUDE_A = [" ▗ ▗ ", " ▘▘ ", " ▝▝ "]
|
|
12
|
+
CLAUDE_B = [" ▖ ▖ ", " ▝▝ ", " ▘▘ "]
|
|
13
|
+
|
|
14
|
+
# ---------- 跨平台终端控制 ----------
|
|
15
|
+
if platform.system() == "Windows":
|
|
16
|
+
import msvcrt
|
|
17
|
+
def setup_terminal(): pass
|
|
18
|
+
def restore_terminal(): pass
|
|
19
|
+
def get_key():
|
|
20
|
+
if msvcrt.kbhit():
|
|
21
|
+
ch = msvcrt.getch()
|
|
22
|
+
if ch == b'\xe0': return ''
|
|
23
|
+
try:
|
|
24
|
+
return ch.decode('utf-8', errors='ignore')
|
|
25
|
+
except:
|
|
26
|
+
return ''
|
|
27
|
+
return ''
|
|
28
|
+
else:
|
|
29
|
+
import termios, tty, fcntl
|
|
30
|
+
_old_term = None
|
|
31
|
+
_old_flags = None
|
|
32
|
+
_fd = sys.stdin.fileno()
|
|
33
|
+
|
|
34
|
+
def setup_terminal():
|
|
35
|
+
global _old_term, _old_flags
|
|
36
|
+
_old_term = termios.tcgetattr(_fd)
|
|
37
|
+
_old_flags = fcntl.fcntl(_fd, fcntl.F_GETFL)
|
|
38
|
+
tty.setraw(_fd)
|
|
39
|
+
fcntl.fcntl(_fd, fcntl.F_SETFL, _old_flags | os.O_NONBLOCK)
|
|
40
|
+
|
|
41
|
+
def restore_terminal():
|
|
42
|
+
if _old_term is not None:
|
|
43
|
+
termios.tcsetattr(_fd, termios.TCSADRAIN, _old_term)
|
|
44
|
+
if _old_flags is not None:
|
|
45
|
+
fcntl.fcntl(_fd, fcntl.F_SETFL, _old_flags)
|
|
46
|
+
|
|
47
|
+
def get_key():
|
|
48
|
+
try:
|
|
49
|
+
data = os.read(_fd, 1).decode('utf-8', errors='ignore')
|
|
50
|
+
return data
|
|
51
|
+
except BlockingIOError:
|
|
52
|
+
return ''
|
|
53
|
+
|
|
54
|
+
class Game:
|
|
55
|
+
def __init__(self):
|
|
56
|
+
self.score = 0
|
|
57
|
+
self.high = self._load_high()
|
|
58
|
+
self.ground_y = GROUND - len(CLAUDE_A)
|
|
59
|
+
self.y = float(self.ground_y)
|
|
60
|
+
self.vy = 0.0
|
|
61
|
+
self.objs = []
|
|
62
|
+
self.speed = 0.8
|
|
63
|
+
self.frame = 0
|
|
64
|
+
self.over = False
|
|
65
|
+
self._hide_cursor()
|
|
66
|
+
signal.signal(signal.SIGINT, self._stop)
|
|
67
|
+
signal.signal(signal.SIGTERM, self._stop)
|
|
68
|
+
|
|
69
|
+
def _stop(self, *args):
|
|
70
|
+
self.over = True
|
|
71
|
+
|
|
72
|
+
def _hide_cursor(self):
|
|
73
|
+
sys.stdout.write("\033[?25l")
|
|
74
|
+
sys.stdout.flush()
|
|
75
|
+
|
|
76
|
+
def _show_cursor(self):
|
|
77
|
+
sys.stdout.write("\033[?25h")
|
|
78
|
+
sys.stdout.flush()
|
|
79
|
+
|
|
80
|
+
def _load_high(self):
|
|
81
|
+
p = os.path.expanduser("~/.wocli_dino")
|
|
82
|
+
try:
|
|
83
|
+
with open(p) as f:
|
|
84
|
+
return int(f.read())
|
|
85
|
+
except:
|
|
86
|
+
return 0
|
|
87
|
+
|
|
88
|
+
def _save_high(self):
|
|
89
|
+
if self.score > self.high:
|
|
90
|
+
self.high = self.score
|
|
91
|
+
p = os.path.expanduser("~/.wocli_dino")
|
|
92
|
+
try:
|
|
93
|
+
with open(p, "w") as f:
|
|
94
|
+
f.write(str(self.score))
|
|
95
|
+
except:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
def jump(self):
|
|
99
|
+
if self.vy == 0 and self.y >= self.ground_y:
|
|
100
|
+
self.vy = -2.2
|
|
101
|
+
|
|
102
|
+
def update(self):
|
|
103
|
+
if self.over:
|
|
104
|
+
return
|
|
105
|
+
self.frame += 1
|
|
106
|
+
self.score += 1
|
|
107
|
+
if self.score % 600 == 0:
|
|
108
|
+
self.speed = min(2.0, self.speed * 1.05)
|
|
109
|
+
|
|
110
|
+
self.vy += 0.2
|
|
111
|
+
self.y += self.vy
|
|
112
|
+
if self.y >= self.ground_y:
|
|
113
|
+
self.y = self.ground_y
|
|
114
|
+
self.vy = 0
|
|
115
|
+
|
|
116
|
+
# 移除超出屏幕的障碍
|
|
117
|
+
self.objs = [o for o in self.objs if o[0] > -15]
|
|
118
|
+
for o in self.objs:
|
|
119
|
+
o[0] -= self.speed
|
|
120
|
+
|
|
121
|
+
# 生成障碍
|
|
122
|
+
if len(self.objs) < 3 and random.random() < 0.02:
|
|
123
|
+
last_x = max([o[0] for o in self.objs]) if self.objs else W
|
|
124
|
+
if last_x < W - 20:
|
|
125
|
+
if random.random() < 0.65:
|
|
126
|
+
h = random.randint(3, 4)
|
|
127
|
+
w = random.randint(5, 7)
|
|
128
|
+
cactus = []
|
|
129
|
+
for i in range(h):
|
|
130
|
+
line = ""
|
|
131
|
+
for j in range(w):
|
|
132
|
+
if i == 0 and j == w // 2: line += "┃"
|
|
133
|
+
elif i > 0 and (j == 0 or j == w - 1): line += "│"
|
|
134
|
+
elif i == h - 1: line += "━"
|
|
135
|
+
else: line += " " if random.random() < 0.7 else "╻"
|
|
136
|
+
cactus.append(line)
|
|
137
|
+
self.objs.append([W, w, h, GROUND - h, cactus, C_GREEN])
|
|
138
|
+
else:
|
|
139
|
+
bird_y = GROUND - random.randint(4, 7)
|
|
140
|
+
bird = [" ^^ ", " <^^> "]
|
|
141
|
+
self.objs.append([W, 6, 2, bird_y, bird, C_WHITE])
|
|
142
|
+
|
|
143
|
+
# 碰撞检测
|
|
144
|
+
claude_h = len(CLAUDE_A)
|
|
145
|
+
claude_w = max(len(r) for r in CLAUDE_A)
|
|
146
|
+
cx0, cy0 = X0, int(self.y)
|
|
147
|
+
for ox, ow, oh, oy, _, _ in self.objs:
|
|
148
|
+
if (cx0 + claude_w > ox and cx0 < ox + ow and
|
|
149
|
+
cy0 + claude_h > oy and cy0 < oy + oh):
|
|
150
|
+
self.over = True
|
|
151
|
+
self._save_high()
|
|
152
|
+
break
|
|
153
|
+
|
|
154
|
+
def render(self):
|
|
155
|
+
sys.stdout.write("\033[2J\033[H")
|
|
156
|
+
buf = [[" "] * W for _ in range(H)]
|
|
157
|
+
for x in range(W):
|
|
158
|
+
buf[GROUND][x] = "─"
|
|
159
|
+
|
|
160
|
+
frame_char = CLAUDE_A if (self.frame // 3) % 2 == 0 else CLAUDE_B
|
|
161
|
+
for dy, row in enumerate(frame_char):
|
|
162
|
+
y = int(self.y) + dy
|
|
163
|
+
if 0 <= y < H:
|
|
164
|
+
for dx, ch in enumerate(row):
|
|
165
|
+
x = X0 + dx
|
|
166
|
+
if 0 <= x < W and ch != " ":
|
|
167
|
+
buf[y][x] = f"{C_ORANGE}{ch}{C_RESET}"
|
|
168
|
+
|
|
169
|
+
for ox, ow, oh, oy, shape, col in self.objs:
|
|
170
|
+
for sy, row in enumerate(shape):
|
|
171
|
+
y = oy + sy
|
|
172
|
+
if 0 <= y < H:
|
|
173
|
+
for sx, ch in enumerate(row):
|
|
174
|
+
x = ox + sx
|
|
175
|
+
if 0 <= x < W and ch != " ":
|
|
176
|
+
buf[y][x] = f"{col}{ch}{C_RESET}"
|
|
177
|
+
|
|
178
|
+
for row in buf:
|
|
179
|
+
print(" " + "".join(row))
|
|
180
|
+
|
|
181
|
+
score_str = f"Score: {self.score:05d} High: {self.high:05d}"
|
|
182
|
+
hint = "Space:Jump Q:Quit" if not self.over else "GAME OVER R:Restart Q:Quit"
|
|
183
|
+
print(f" {C_ORANGE}{score_str}{C_RESET} {hint}")
|
|
184
|
+
|
|
185
|
+
def input_handle(self):
|
|
186
|
+
k = get_key()
|
|
187
|
+
while k:
|
|
188
|
+
if k == ' ':
|
|
189
|
+
self.jump()
|
|
190
|
+
elif k == 'q':
|
|
191
|
+
self.over = True
|
|
192
|
+
elif k == 'r' and self.over:
|
|
193
|
+
self._save_high()
|
|
194
|
+
self.__init__()
|
|
195
|
+
k = get_key()
|
|
196
|
+
|
|
197
|
+
def run(self):
|
|
198
|
+
try:
|
|
199
|
+
while not self.over:
|
|
200
|
+
self.input_handle()
|
|
201
|
+
self.update()
|
|
202
|
+
self.render()
|
|
203
|
+
time.sleep(0.04)
|
|
204
|
+
self.render()
|
|
205
|
+
time.sleep(1.5)
|
|
206
|
+
finally:
|
|
207
|
+
self._show_cursor()
|
|
208
|
+
self._save_high()
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def main():
|
|
212
|
+
print(f"\n {C_ORANGE}╭─ Claude Run ──────────────────────────────╮{C_RESET}")
|
|
213
|
+
print(f" {C_ORANGE}│{C_RESET} 橙色小人跑酷,按任意键开始 {C_ORANGE}│{C_RESET}")
|
|
214
|
+
print(f" {C_ORANGE}╰──────────────────────────────────────────╯{C_RESET}")
|
|
215
|
+
|
|
216
|
+
setup_terminal()
|
|
217
|
+
try:
|
|
218
|
+
# 等待任意键
|
|
219
|
+
while True:
|
|
220
|
+
if get_key():
|
|
221
|
+
break
|
|
222
|
+
time.sleep(0.05)
|
|
223
|
+
g = Game()
|
|
224
|
+
g.run()
|
|
225
|
+
finally:
|
|
226
|
+
restore_terminal()
|
|
227
|
+
|
|
228
|
+
if __name__ == "__main__":
|
|
229
|
+
main()
|
wocli/commands/glitch.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""wocli glitch - 文字故障风效果."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import random
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def glitch_case(text):
|
|
8
|
+
return "".join(
|
|
9
|
+
c.upper() if random.random() > 0.5 else c.lower()
|
|
10
|
+
for c in text
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def glitch_leet(text):
|
|
15
|
+
mapping = {
|
|
16
|
+
"a": "4", "A": "4",
|
|
17
|
+
"e": "3", "E": "3",
|
|
18
|
+
"i": "1", "I": "1",
|
|
19
|
+
"o": "0", "O": "0",
|
|
20
|
+
"s": "5", "S": "5",
|
|
21
|
+
"t": "7", "T": "7",
|
|
22
|
+
"l": "1", "L": "1",
|
|
23
|
+
}
|
|
24
|
+
return "".join(mapping.get(c, c) for c in text)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def glitch_zalgo(text):
|
|
28
|
+
up = "".join(random.choice("''^`") for _ in range(len(text)))
|
|
29
|
+
down = "".join(random.choice(",.;:") for _ in range(len(text)))
|
|
30
|
+
return up + "\n" + text + "\n" + down
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def glitch_morse(text):
|
|
34
|
+
return " ".join(
|
|
35
|
+
"".join(random.choice([".", "-"]) for _ in range(random.randint(1, 4)))
|
|
36
|
+
for _ in text.split()
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def run():
|
|
41
|
+
"""运行 glitch 命令."""
|
|
42
|
+
if len(sys.argv) > 1:
|
|
43
|
+
text = " ".join(sys.argv[1:])
|
|
44
|
+
else:
|
|
45
|
+
text = "Hello World"
|
|
46
|
+
|
|
47
|
+
print()
|
|
48
|
+
print(f" Original : {text}")
|
|
49
|
+
print(f" Glitch 1 : {glitch_case(text)}")
|
|
50
|
+
print(f" Glitch 2 : {glitch_leet(text)}")
|
|
51
|
+
print(f" Glitch 3 : {glitch_zalgo(text)}")
|
|
52
|
+
print()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""wocli goodbye - 花式退出动画."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import time
|
|
5
|
+
import random
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
MESSAGES = [
|
|
9
|
+
"明天又是充满 bug 的一天(目移)",
|
|
10
|
+
"记得 commit 和 push 哦",
|
|
11
|
+
"没人觉得 rust 很香吗",
|
|
12
|
+
"就当是为了我,对他使用force-push吧",
|
|
13
|
+
"Goodbye world!",
|
|
14
|
+
"本次编码结束,bug 数 +1。",
|
|
15
|
+
"代码能跑就行...",
|
|
16
|
+
"感谢使用awa",
|
|
17
|
+
"Ctrl+C 的人生不需要解释",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def run():
|
|
22
|
+
"""运行 goodbye 命令."""
|
|
23
|
+
msg = random.choice(MESSAGES)
|
|
24
|
+
|
|
25
|
+
print()
|
|
26
|
+
print(" System will shut down in 3 seconds...")
|
|
27
|
+
time.sleep(1)
|
|
28
|
+
|
|
29
|
+
width = 30
|
|
30
|
+
for i in range(width + 1):
|
|
31
|
+
bar = "=" * i + ">" + " " * (width - i)
|
|
32
|
+
pct = int(i / width * 100)
|
|
33
|
+
sys.stdout.write(f"\r [{bar}] {pct}%")
|
|
34
|
+
sys.stdout.flush()
|
|
35
|
+
time.sleep(0.08)
|
|
36
|
+
|
|
37
|
+
print()
|
|
38
|
+
print(f" {msg}")
|
|
39
|
+
print(" Bye!")
|
|
40
|
+
print()
|
wocli/commands/gpa.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""wocli gpa - 加权GPA计算器,带毒舌点评."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def grade_to_point(grade):
|
|
5
|
+
"""百分制转绩点(4.0制)."""
|
|
6
|
+
if grade >= 90:
|
|
7
|
+
return 4.0
|
|
8
|
+
elif grade >= 85:
|
|
9
|
+
return 3.7
|
|
10
|
+
elif grade >= 82:
|
|
11
|
+
return 3.3
|
|
12
|
+
elif grade >= 78:
|
|
13
|
+
return 3.0
|
|
14
|
+
elif grade >= 75:
|
|
15
|
+
return 2.7
|
|
16
|
+
elif grade >= 72:
|
|
17
|
+
return 2.3
|
|
18
|
+
elif grade >= 68:
|
|
19
|
+
return 2.0
|
|
20
|
+
elif grade >= 64:
|
|
21
|
+
return 1.5
|
|
22
|
+
elif grade >= 60:
|
|
23
|
+
return 1.0
|
|
24
|
+
else:
|
|
25
|
+
return 0.0
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def comment(gpa):
|
|
29
|
+
"""根据GPA给出毒舌点评."""
|
|
30
|
+
if gpa >= 3.8:
|
|
31
|
+
return "你住在图书馆里。图书馆现在是你家。"
|
|
32
|
+
elif gpa >= 3.5:
|
|
33
|
+
return "再熬一点。提高一分干掉千人。"
|
|
34
|
+
elif gpa >= 3.0:
|
|
35
|
+
return "3分万岁。不难看就行。"
|
|
36
|
+
elif gpa >= 2.5:
|
|
37
|
+
return "正在卷GPA,亿万大学生必须加把劲。"
|
|
38
|
+
elif gpa >= 2.0:
|
|
39
|
+
return "两分够用了。Passing is passing。"
|
|
40
|
+
elif gpa >= 1.0:
|
|
41
|
+
return "至少老师记住你了,怎么记住的你别管。"
|
|
42
|
+
else:
|
|
43
|
+
return "回家吧孩子回家吧,你比较适合做一头猪。"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def run():
|
|
47
|
+
"""运行 gpa 命令."""
|
|
48
|
+
print()
|
|
49
|
+
print(" [ GPA 计算器 ]")
|
|
50
|
+
print(" " + "-" * 40)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
n = int(input(" 课程数量: "))
|
|
54
|
+
except (ValueError, EOFError):
|
|
55
|
+
print("\n 输入无效。\n")
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
total_points = 0
|
|
59
|
+
total_credits = 0
|
|
60
|
+
|
|
61
|
+
for i in range(1, n + 1):
|
|
62
|
+
try:
|
|
63
|
+
credit = float(input(f" 课程{i} - 学分: "))
|
|
64
|
+
grade = float(input(f" 课程{i} - 成绩(0-100): "))
|
|
65
|
+
except (ValueError, EOFError):
|
|
66
|
+
print("\n 输入无效。\n")
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
point = grade_to_point(grade)
|
|
70
|
+
total_points += point * credit
|
|
71
|
+
total_credits += credit
|
|
72
|
+
|
|
73
|
+
if total_credits == 0:
|
|
74
|
+
print("\n 总学分不能为零。\n")
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
gpa = total_points / total_credits
|
|
78
|
+
|
|
79
|
+
print()
|
|
80
|
+
print(f" 加权 GPA:{gpa:.2f} / 4.0")
|
|
81
|
+
print(f" 总学分:{total_credits:.0f}")
|
|
82
|
+
print()
|
|
83
|
+
print(f" {comment(gpa)}")
|
|
84
|
+
print()
|