cli-othello 1.0.2__tar.gz → 1.0.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cli-othello
3
- Version: 1.0.2
3
+ Version: 1.0.3
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cli-othello"
7
- version = "1.0.2"
7
+ version = "1.0.3"
8
8
  description = "Play Othello (Reversi) in your terminal against a 5-level AI"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -1,3 +1,3 @@
1
1
  """cli-othello: play Othello in your terminal."""
2
2
 
3
- __version__ = "1.0.2"
3
+ __version__ = "1.0.3"
@@ -9,15 +9,24 @@ from .board import BLACK, EMPTY, SIZE, WHITE, Board, opponent
9
9
 
10
10
  PLAYER_NAMES = {BLACK: "黒", WHITE: "白"}
11
11
 
12
- # Each cell is rendered as CELL_W columns x CELL_H rows so it reads as
13
- # roughly square in a terminal (chars are about twice as tall as wide).
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). All glyphs used inside the grid
15
+ # are plain ASCII: full-width characters (e.g. "●", "○") have ambiguous
16
+ # display width and end up misaligned in many terminals/fonts, so discs
17
+ # are shown as a colored background plus a half-width letter instead.
14
18
  CELL_W = 5
15
19
  CELL_H = 2
16
20
 
17
- DISC_BLACK = "●"
18
- DISC_WHITE = "○"
21
+ DISC_BLACK = "@"
22
+ DISC_WHITE = "O"
19
23
  HINT_MARK = "+"
20
24
 
25
+ # Box-drawing characters for the grid lines between cells.
26
+ _TL, _TR, _BL, _BR = "┌", "┐", "└", "┘"
27
+ _H, _V = "─", "│"
28
+ _T_DOWN, _T_UP, _T_RIGHT, _T_LEFT, _CROSS = "┬", "┴", "├", "┤", "┼"
29
+
21
30
  COLOR_BOARD = 1
22
31
  COLOR_BLACK = 2
23
32
  COLOR_WHITE = 3
@@ -60,7 +69,7 @@ def select_level(stdscr: "curses._CursesWindow") -> int:
60
69
  if max_y < required_rows or max_x < required_cols:
61
70
  _draw_too_small(stdscr)
62
71
  continue
63
- stdscr.addstr(1, 2, "♟ CLI OTHELLO", curses.color_pair(COLOR_HEADER) | curses.A_BOLD)
72
+ stdscr.addstr(1, 2, "CLI OTHELLO", curses.color_pair(COLOR_HEADER) | curses.A_BOLD)
64
73
  stdscr.addstr(3, 2, "対戦するAIの強さを選んでください", curses.A_BOLD)
65
74
  for i in range(MIN_LEVEL, MAX_LEVEL + 1):
66
75
  label = LEVEL_LABELS[i]
@@ -116,8 +125,11 @@ def _required_size() -> tuple[int, int]:
116
125
  """Return (rows, cols) needed to draw the board and panel, plus a
117
126
  1-line/1-column margin (curses can refuse writes to the very last
118
127
  row/column of the screen)."""
119
- rows = 3 + 1 + SIZE * CELL_H + 6 + 1
120
- cols = 4 + 3 + SIZE * CELL_W + 1
128
+ grid_rows = 1 + SIZE * (CELL_H + 1)
129
+ grid_cols = 1 + SIZE * (CELL_W + 1)
130
+ row_label_w = 3
131
+ rows = 3 + 1 + grid_rows + 6 + 1
132
+ cols = 4 + row_label_w + grid_cols + 1
121
133
  return rows, cols
122
134
 
123
135
 
@@ -153,7 +165,7 @@ def _draw_board(
153
165
  return False
154
166
 
155
167
  stdscr.erase()
156
- stdscr.addstr(top, 2, "♟ CLI OTHELLO", curses.color_pair(COLOR_HEADER) | curses.A_BOLD)
168
+ stdscr.addstr(top, 2, "CLI OTHELLO", curses.color_pair(COLOR_HEADER) | curses.A_BOLD)
157
169
  stdscr.addstr(
158
170
  top + 1,
159
171
  2,
@@ -164,29 +176,58 @@ def _draw_board(
164
176
  board_top = top + 3
165
177
  board_left = 4
166
178
  grid_attr = curses.color_pair(COLOR_GRID)
179
+ row_label_w = 3
167
180
 
168
- # Column labels (A-H), centered above each cell.
169
- header = " " * 3
181
+ # Column labels (A-H), centered above each cell (account for the
182
+ # leading grid line and the row-label gutter).
183
+ header = " " * row_label_w + " "
170
184
  for col in range(SIZE):
171
- header += "ABCDEFGH"[col].center(CELL_W)
185
+ header += "ABCDEFGH"[col].center(CELL_W) + " "
172
186
  stdscr.addstr(board_top, board_left, header, curses.A_BOLD)
173
187
 
174
- board_width = 3 + SIZE * CELL_W
188
+ grid_top = board_top + 1
189
+ grid_left = board_left + row_label_w
190
+ grid_cols = 1 + SIZE * (CELL_W + 1)
191
+ grid_rows = 1 + SIZE * (CELL_H + 1)
192
+ board_width = row_label_w + grid_cols
193
+
194
+ # Draw the grid lines (the lattice of cell borders) first.
195
+ for r in range(SIZE + 1):
196
+ y = grid_top + r * (CELL_H + 1)
197
+ if r == 0:
198
+ left, mid, right = _TL, _T_DOWN, _TR
199
+ elif r == SIZE:
200
+ left, mid, right = _BL, _T_UP, _BR
201
+ else:
202
+ left, mid, right = _T_RIGHT, _CROSS, _T_LEFT
203
+ line = left + (_H * CELL_W + mid) * SIZE
204
+ line = line[:-1] + right
205
+ stdscr.addstr(y, grid_left, line, grid_attr)
206
+ if r < SIZE:
207
+ for line_offset in range(1, CELL_H + 1):
208
+ y2 = y + line_offset
209
+ stdscr.addstr(y2, grid_left, _V, grid_attr)
210
+ stdscr.addstr(y2, grid_left + grid_cols - 1, _V, grid_attr)
211
+ for c in range(1, SIZE):
212
+ x = grid_left + c * (CELL_W + 1)
213
+ stdscr.addstr(y2, x, _V, grid_attr)
214
+
215
+ # Row labels (1-8), centered next to each cell.
175
216
  for row in range(SIZE):
176
- for line in range(CELL_H):
177
- y = board_top + 1 + row * CELL_H + line
178
- if line == CELL_H // 2:
179
- row_label = f"{row + 1:>2} "
180
- else:
181
- row_label = " "
182
- stdscr.addstr(y, board_left, row_label, curses.A_BOLD)
183
- for col in range(SIZE):
184
- cell = board.get(row, col)
185
- is_cursor = (row, col) == cursor
186
- is_hint = cell == EMPTY and (row, col) in legal
187
- x = board_left + 3 + col * CELL_W
188
-
189
- if line == CELL_H // 2:
217
+ y = grid_top + 1 + row * (CELL_H + 1) + (CELL_H - 1) // 2
218
+ stdscr.addstr(y, board_left, f"{row + 1:>2} ", curses.A_BOLD)
219
+
220
+ # Fill each cell's interior (background + disc/hint glyph).
221
+ for row in range(SIZE):
222
+ cell_top = grid_top + 1 + row * (CELL_H + 1)
223
+ for col in range(SIZE):
224
+ cell = board.get(row, col)
225
+ is_cursor = (row, col) == cursor
226
+ is_hint = cell == EMPTY and (row, col) in legal
227
+ x = grid_left + 1 + col * (CELL_W + 1)
228
+ for line in range(CELL_H):
229
+ y = cell_top + line
230
+ if line == (CELL_H - 1) // 2:
190
231
  attr, ch = _cell_center_attr(cell, is_cursor, is_hint)
191
232
  text = ch.center(CELL_W)
192
233
  else:
@@ -194,7 +235,7 @@ def _draw_board(
194
235
  text = " " * CELL_W
195
236
  stdscr.addstr(y, x, text, attr)
196
237
 
197
- board_bottom = board_top + 1 + SIZE * CELL_H
238
+ board_bottom = grid_top + grid_rows - 1
198
239
  panel_left = board_left
199
240
  panel_width = board_width
200
241
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cli-othello
3
- Version: 1.0.2
3
+ Version: 1.0.3
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
File without changes
File without changes