cli-othello 1.0.2__tar.gz → 1.0.4__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.
- cli_othello-1.0.4/LICENSE +7 -0
- {cli_othello-1.0.2 → cli_othello-1.0.4}/PKG-INFO +17 -3
- {cli_othello-1.0.2 → cli_othello-1.0.4}/README.md +14 -2
- {cli_othello-1.0.2 → cli_othello-1.0.4}/pyproject.toml +1 -1
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello/__init__.py +1 -1
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello/ui.py +90 -35
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello.egg-info/PKG-INFO +17 -3
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello.egg-info/SOURCES.txt +1 -0
- {cli_othello-1.0.2 → cli_othello-1.0.4}/setup.cfg +0 -0
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello/ai.py +0 -0
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello/board.py +0 -0
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello/cli.py +0 -0
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello.egg-info/dependency_links.txt +0 -0
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello.egg-info/entry_points.txt +0 -0
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello.egg-info/requires.txt +0 -0
- {cli_othello-1.0.2 → cli_othello-1.0.4}/src/cli_othello.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
MITライセンス
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lapius7bot Technology Co.
|
|
4
|
+
|
|
5
|
+
本パッケージおよび関連するドキュメントファイル(以下「本パッケージ」)のコピーを取得したすべての人に対し、本パッケージを無制限に利用する権利を無償で付与します。これには、使用、複製、改変、統合、公開、配布、サブライセンス、および/または販売する権利が含まれますが、これらに限定されません。ただし、以下の条件を遵守することを条件とします。
|
|
6
|
+
上記の著作権表示および本許可通知は、本パッケージのすべてのコピーまたはその大部分に記載する必要があります。
|
|
7
|
+
本パッケージは「現状のまま」使用、その他の取り扱いに起因または関連して生じる請求、損害、その他の責任について、契約違反、不法行為、その他の理由にかかわらず、一切の責任を負いません。提供されるものであり、明示的または黙示的を問わず、商品性、特定目的への適合性、非侵害性に関する保証を含むいかなる保証も行いません。いかなる場合においても、著作者または著作権者は、本パッケージまたはその
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-othello
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Play Othello (Reversi) in your terminal against a 5-level AI
|
|
5
5
|
Author-email: Lapius7 <20071209ryo@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -8,7 +8,9 @@ Project-URL: Homepage, https://github.com/Lapius7/cli-othello
|
|
|
8
8
|
Project-URL: Repository, https://github.com/Lapius7/cli-othello
|
|
9
9
|
Requires-Python: >=3.9
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
11
12
|
Requires-Dist: windows-curses; platform_system == "Windows"
|
|
13
|
+
Dynamic: license-file
|
|
12
14
|
|
|
13
15
|
# cli-othello
|
|
14
16
|
|
|
@@ -17,10 +19,22 @@ Requires-Dist: windows-curses; platform_system == "Windows"
|
|
|
17
19
|
|
|
18
20
|
## インストール
|
|
19
21
|
|
|
22
|
+
### npm(推奨)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm i -g @lapius/cli-othello
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`othello` コマンドが入ります(Node.js 18 以上と Python 3.9 以上が必要)。
|
|
29
|
+
|
|
30
|
+
### pip
|
|
31
|
+
|
|
20
32
|
```bash
|
|
21
33
|
pip install cli-othello
|
|
22
34
|
```
|
|
23
35
|
|
|
36
|
+
Windows では curses を使うために `windows-curses` が必要です。pip で入れた場合は自動で入ります。npm で入れた場合は `py -m pip install windows-curses` で入れてください。
|
|
37
|
+
|
|
24
38
|
## 使い方
|
|
25
39
|
|
|
26
40
|
```bash
|
|
@@ -58,8 +72,8 @@ othello --level 3
|
|
|
58
72
|
|
|
59
73
|
## 必要環境
|
|
60
74
|
|
|
61
|
-
- Python 3.9
|
|
62
|
-
-
|
|
75
|
+
- Python 3.9以上(npm で入れる場合は Node.js 18 以上も)
|
|
76
|
+
- 端末は 57列 x 36行 以上
|
|
63
77
|
|
|
64
78
|
## ライセンス
|
|
65
79
|
|
|
@@ -5,10 +5,22 @@
|
|
|
5
5
|
|
|
6
6
|
## インストール
|
|
7
7
|
|
|
8
|
+
### npm(推奨)
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm i -g @lapius/cli-othello
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`othello` コマンドが入ります(Node.js 18 以上と Python 3.9 以上が必要)。
|
|
15
|
+
|
|
16
|
+
### pip
|
|
17
|
+
|
|
8
18
|
```bash
|
|
9
19
|
pip install cli-othello
|
|
10
20
|
```
|
|
11
21
|
|
|
22
|
+
Windows では curses を使うために `windows-curses` が必要です。pip で入れた場合は自動で入ります。npm で入れた場合は `py -m pip install windows-curses` で入れてください。
|
|
23
|
+
|
|
12
24
|
## 使い方
|
|
13
25
|
|
|
14
26
|
```bash
|
|
@@ -46,8 +58,8 @@ othello --level 3
|
|
|
46
58
|
|
|
47
59
|
## 必要環境
|
|
48
60
|
|
|
49
|
-
- Python 3.9
|
|
50
|
-
-
|
|
61
|
+
- Python 3.9以上(npm で入れる場合は Node.js 18 以上も)
|
|
62
|
+
- 端末は 57列 x 36行 以上
|
|
51
63
|
|
|
52
64
|
## ライセンス
|
|
53
65
|
|
|
@@ -9,15 +9,37 @@ from .board import BLACK, EMPTY, SIZE, WHITE, Board, opponent
|
|
|
9
9
|
|
|
10
10
|
PLAYER_NAMES = {BLACK: "黒", WHITE: "白"}
|
|
11
11
|
|
|
12
|
-
# Each cell is
|
|
13
|
-
#
|
|
12
|
+
# Each cell's interior is CELL_W columns x CELL_H rows, not counting the
|
|
13
|
+
# grid lines drawn around it, so it reads as roughly square in a terminal
|
|
14
|
+
# (chars are about twice as tall as wide).
|
|
14
15
|
CELL_W = 5
|
|
15
16
|
CELL_H = 2
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
# Round glyphs such as "⬤"/"◯" have ambiguous display width: some
|
|
19
|
+
# terminal/font combinations render them as 1 column, others as 2, and
|
|
20
|
+
# this can't be reliably detected from Python (confirmed: wcwidth's
|
|
21
|
+
# reported width didn't match actual rendering in testing). Discs are
|
|
22
|
+
# therefore drawn as a half-width letter on a solid background instead,
|
|
23
|
+
# which always lines up with the surrounding grid.
|
|
24
|
+
DISC_BLACK = "@"
|
|
25
|
+
DISC_WHITE = "O"
|
|
26
|
+
DISC_WIDTH = 1
|
|
19
27
|
HINT_MARK = "+"
|
|
20
28
|
|
|
29
|
+
|
|
30
|
+
def _center_display(glyph: str, glyph_width: int, total_width: int) -> str:
|
|
31
|
+
"""Center `glyph` (which occupies `glyph_width` display columns) inside
|
|
32
|
+
a field of `total_width` columns, using plain spaces for padding."""
|
|
33
|
+
pad = total_width - glyph_width
|
|
34
|
+
left = pad // 2
|
|
35
|
+
right = pad - left
|
|
36
|
+
return " " * left + glyph + " " * right
|
|
37
|
+
|
|
38
|
+
# Box-drawing characters for the grid lines between cells.
|
|
39
|
+
_TL, _TR, _BL, _BR = "┌", "┐", "└", "┘"
|
|
40
|
+
_H, _V = "─", "│"
|
|
41
|
+
_T_DOWN, _T_UP, _T_RIGHT, _T_LEFT, _CROSS = "┬", "┴", "├", "┤", "┼"
|
|
42
|
+
|
|
21
43
|
COLOR_BOARD = 1
|
|
22
44
|
COLOR_BLACK = 2
|
|
23
45
|
COLOR_WHITE = 3
|
|
@@ -60,7 +82,7 @@ def select_level(stdscr: "curses._CursesWindow") -> int:
|
|
|
60
82
|
if max_y < required_rows or max_x < required_cols:
|
|
61
83
|
_draw_too_small(stdscr)
|
|
62
84
|
continue
|
|
63
|
-
stdscr.addstr(1, 2, "
|
|
85
|
+
stdscr.addstr(1, 2, "CLI OTHELLO", curses.color_pair(COLOR_HEADER) | curses.A_BOLD)
|
|
64
86
|
stdscr.addstr(3, 2, "対戦するAIの強さを選んでください", curses.A_BOLD)
|
|
65
87
|
for i in range(MIN_LEVEL, MAX_LEVEL + 1):
|
|
66
88
|
label = LEVEL_LABELS[i]
|
|
@@ -99,25 +121,29 @@ def _cell_fill_attr(cell: int, is_cursor: bool) -> int:
|
|
|
99
121
|
return curses.color_pair(COLOR_BOARD)
|
|
100
122
|
|
|
101
123
|
|
|
102
|
-
def _cell_center_attr(cell: int, is_cursor: bool, is_hint: bool) -> tuple[int, str]:
|
|
103
|
-
"""Return (attribute, character) for the center row of
|
|
124
|
+
def _cell_center_attr(cell: int, is_cursor: bool, is_hint: bool) -> tuple[int, str, int]:
|
|
125
|
+
"""Return (attribute, character, display_width) for the center row of
|
|
126
|
+
a cell."""
|
|
104
127
|
fill = _cell_fill_attr(cell, is_cursor)
|
|
105
128
|
if cell == BLACK:
|
|
106
|
-
return fill, DISC_BLACK
|
|
129
|
+
return fill, DISC_BLACK, DISC_WIDTH
|
|
107
130
|
if cell == WHITE:
|
|
108
|
-
return fill, DISC_WHITE
|
|
131
|
+
return fill, DISC_WHITE, DISC_WIDTH
|
|
109
132
|
if is_hint:
|
|
110
133
|
attr = curses.color_pair(COLOR_CURSOR_EMPTY if is_cursor else COLOR_HINT) | curses.A_BOLD
|
|
111
|
-
return attr, HINT_MARK
|
|
112
|
-
return fill, " "
|
|
134
|
+
return attr, HINT_MARK, 1
|
|
135
|
+
return fill, " ", 0
|
|
113
136
|
|
|
114
137
|
|
|
115
138
|
def _required_size() -> tuple[int, int]:
|
|
116
139
|
"""Return (rows, cols) needed to draw the board and panel, plus a
|
|
117
140
|
1-line/1-column margin (curses can refuse writes to the very last
|
|
118
141
|
row/column of the screen)."""
|
|
119
|
-
|
|
120
|
-
|
|
142
|
+
grid_rows = 1 + SIZE * (CELL_H + 1)
|
|
143
|
+
grid_cols = 1 + SIZE * (CELL_W + 1)
|
|
144
|
+
row_label_w = 3
|
|
145
|
+
rows = 3 + 1 + grid_rows + 6 + 1
|
|
146
|
+
cols = 4 + row_label_w + grid_cols + 1
|
|
121
147
|
return rows, cols
|
|
122
148
|
|
|
123
149
|
|
|
@@ -153,7 +179,7 @@ def _draw_board(
|
|
|
153
179
|
return False
|
|
154
180
|
|
|
155
181
|
stdscr.erase()
|
|
156
|
-
stdscr.addstr(top, 2, "
|
|
182
|
+
stdscr.addstr(top, 2, "CLI OTHELLO", curses.color_pair(COLOR_HEADER) | curses.A_BOLD)
|
|
157
183
|
stdscr.addstr(
|
|
158
184
|
top + 1,
|
|
159
185
|
2,
|
|
@@ -164,37 +190,66 @@ def _draw_board(
|
|
|
164
190
|
board_top = top + 3
|
|
165
191
|
board_left = 4
|
|
166
192
|
grid_attr = curses.color_pair(COLOR_GRID)
|
|
193
|
+
row_label_w = 3
|
|
167
194
|
|
|
168
|
-
# Column labels (A-H), centered above each cell
|
|
169
|
-
|
|
195
|
+
# Column labels (A-H), centered above each cell (account for the
|
|
196
|
+
# leading grid line and the row-label gutter).
|
|
197
|
+
header = " " * row_label_w + " "
|
|
170
198
|
for col in range(SIZE):
|
|
171
|
-
header += "ABCDEFGH"[col].center(CELL_W)
|
|
199
|
+
header += "ABCDEFGH"[col].center(CELL_W) + " "
|
|
172
200
|
stdscr.addstr(board_top, board_left, header, curses.A_BOLD)
|
|
173
201
|
|
|
174
|
-
|
|
202
|
+
grid_top = board_top + 1
|
|
203
|
+
grid_left = board_left + row_label_w
|
|
204
|
+
grid_cols = 1 + SIZE * (CELL_W + 1)
|
|
205
|
+
grid_rows = 1 + SIZE * (CELL_H + 1)
|
|
206
|
+
board_width = row_label_w + grid_cols
|
|
207
|
+
|
|
208
|
+
# Draw the grid lines (the lattice of cell borders) first.
|
|
209
|
+
for r in range(SIZE + 1):
|
|
210
|
+
y = grid_top + r * (CELL_H + 1)
|
|
211
|
+
if r == 0:
|
|
212
|
+
left, mid, right = _TL, _T_DOWN, _TR
|
|
213
|
+
elif r == SIZE:
|
|
214
|
+
left, mid, right = _BL, _T_UP, _BR
|
|
215
|
+
else:
|
|
216
|
+
left, mid, right = _T_RIGHT, _CROSS, _T_LEFT
|
|
217
|
+
line = left + (_H * CELL_W + mid) * SIZE
|
|
218
|
+
line = line[:-1] + right
|
|
219
|
+
stdscr.addstr(y, grid_left, line, grid_attr)
|
|
220
|
+
if r < SIZE:
|
|
221
|
+
for line_offset in range(1, CELL_H + 1):
|
|
222
|
+
y2 = y + line_offset
|
|
223
|
+
stdscr.addstr(y2, grid_left, _V, grid_attr)
|
|
224
|
+
stdscr.addstr(y2, grid_left + grid_cols - 1, _V, grid_attr)
|
|
225
|
+
for c in range(1, SIZE):
|
|
226
|
+
x = grid_left + c * (CELL_W + 1)
|
|
227
|
+
stdscr.addstr(y2, x, _V, grid_attr)
|
|
228
|
+
|
|
229
|
+
# Row labels (1-8), centered next to each cell.
|
|
175
230
|
for row in range(SIZE):
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if line == CELL_H // 2:
|
|
190
|
-
attr, ch = _cell_center_attr(cell, is_cursor, is_hint)
|
|
191
|
-
text = ch
|
|
231
|
+
y = grid_top + 1 + row * (CELL_H + 1) + (CELL_H - 1) // 2
|
|
232
|
+
stdscr.addstr(y, board_left, f"{row + 1:>2} ", curses.A_BOLD)
|
|
233
|
+
|
|
234
|
+
# Fill each cell's interior (background + disc/hint glyph).
|
|
235
|
+
for row in range(SIZE):
|
|
236
|
+
cell_top = grid_top + 1 + row * (CELL_H + 1)
|
|
237
|
+
for col in range(SIZE):
|
|
238
|
+
cell = board.get(row, col)
|
|
239
|
+
is_cursor = (row, col) == cursor
|
|
240
|
+
is_hint = cell == EMPTY and (row, col) in legal
|
|
241
|
+
x = grid_left + 1 + col * (CELL_W + 1)
|
|
242
|
+
for line in range(CELL_H):
|
|
243
|
+
y = cell_top + line
|
|
244
|
+
if line == (CELL_H - 1) // 2:
|
|
245
|
+
attr, ch, width = _cell_center_attr(cell, is_cursor, is_hint)
|
|
246
|
+
text = _center_display(ch, width, CELL_W)
|
|
192
247
|
else:
|
|
193
248
|
attr = _cell_fill_attr(cell, is_cursor)
|
|
194
249
|
text = " " * CELL_W
|
|
195
250
|
stdscr.addstr(y, x, text, attr)
|
|
196
251
|
|
|
197
|
-
board_bottom =
|
|
252
|
+
board_bottom = grid_top + grid_rows - 1
|
|
198
253
|
panel_left = board_left
|
|
199
254
|
panel_width = board_width
|
|
200
255
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cli-othello
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Play Othello (Reversi) in your terminal against a 5-level AI
|
|
5
5
|
Author-email: Lapius7 <20071209ryo@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -8,7 +8,9 @@ Project-URL: Homepage, https://github.com/Lapius7/cli-othello
|
|
|
8
8
|
Project-URL: Repository, https://github.com/Lapius7/cli-othello
|
|
9
9
|
Requires-Python: >=3.9
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
11
12
|
Requires-Dist: windows-curses; platform_system == "Windows"
|
|
13
|
+
Dynamic: license-file
|
|
12
14
|
|
|
13
15
|
# cli-othello
|
|
14
16
|
|
|
@@ -17,10 +19,22 @@ Requires-Dist: windows-curses; platform_system == "Windows"
|
|
|
17
19
|
|
|
18
20
|
## インストール
|
|
19
21
|
|
|
22
|
+
### npm(推奨)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm i -g @lapius/cli-othello
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`othello` コマンドが入ります(Node.js 18 以上と Python 3.9 以上が必要)。
|
|
29
|
+
|
|
30
|
+
### pip
|
|
31
|
+
|
|
20
32
|
```bash
|
|
21
33
|
pip install cli-othello
|
|
22
34
|
```
|
|
23
35
|
|
|
36
|
+
Windows では curses を使うために `windows-curses` が必要です。pip で入れた場合は自動で入ります。npm で入れた場合は `py -m pip install windows-curses` で入れてください。
|
|
37
|
+
|
|
24
38
|
## 使い方
|
|
25
39
|
|
|
26
40
|
```bash
|
|
@@ -58,8 +72,8 @@ othello --level 3
|
|
|
58
72
|
|
|
59
73
|
## 必要環境
|
|
60
74
|
|
|
61
|
-
- Python 3.9
|
|
62
|
-
-
|
|
75
|
+
- Python 3.9以上(npm で入れる場合は Node.js 18 以上も)
|
|
76
|
+
- 端末は 57列 x 36行 以上
|
|
63
77
|
|
|
64
78
|
## ライセンス
|
|
65
79
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|