cli-othello 1.0.1__tar.gz → 1.0.2__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.1
3
+ Version: 1.0.2
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.1"
7
+ version = "1.0.2"
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.1"
3
+ __version__ = "1.0.2"
@@ -52,8 +52,14 @@ def select_level(stdscr: "curses._CursesWindow") -> int:
52
52
  """Let the user pick an AI difficulty level (1-5) with arrow keys."""
53
53
  level = 3
54
54
  curses.curs_set(0)
55
+ required_rows = 5 + MAX_LEVEL + 3
56
+ required_cols = 36
55
57
  while True:
56
58
  stdscr.erase()
59
+ max_y, max_x = stdscr.getmaxyx()
60
+ if max_y < required_rows or max_x < required_cols:
61
+ _draw_too_small(stdscr)
62
+ continue
57
63
  stdscr.addstr(1, 2, "♟ CLI OTHELLO", curses.color_pair(COLOR_HEADER) | curses.A_BOLD)
58
64
  stdscr.addstr(3, 2, "対戦するAIの強さを選んでください", curses.A_BOLD)
59
65
  for i in range(MIN_LEVEL, MAX_LEVEL + 1):
@@ -106,6 +112,28 @@ def _cell_center_attr(cell: int, is_cursor: bool, is_hint: bool) -> tuple[int, s
106
112
  return fill, " "
107
113
 
108
114
 
115
+ def _required_size() -> tuple[int, int]:
116
+ """Return (rows, cols) needed to draw the board and panel, plus a
117
+ 1-line/1-column margin (curses can refuse writes to the very last
118
+ row/column of the screen)."""
119
+ rows = 3 + 1 + SIZE * CELL_H + 6 + 1
120
+ cols = 4 + 3 + SIZE * CELL_W + 1
121
+ return rows, cols
122
+
123
+
124
+ def _draw_too_small(stdscr: "curses._CursesWindow") -> None:
125
+ rows, cols = _required_size()
126
+ stdscr.erase()
127
+ try:
128
+ stdscr.addstr(0, 0, "ターミナルが小さすぎます。")
129
+ stdscr.addstr(1, 0, f"必要サイズ: {cols}列 x {rows}行 以上")
130
+ stdscr.addstr(2, 0, "ウィンドウを大きくしてください。何かキーを押すと終了します。")
131
+ except curses.error:
132
+ pass
133
+ stdscr.refresh()
134
+ stdscr.getch()
135
+
136
+
109
137
  def _draw_board(
110
138
  stdscr: "curses._CursesWindow",
111
139
  board: Board,
@@ -115,7 +143,15 @@ def _draw_board(
115
143
  ai_level: int,
116
144
  message: str,
117
145
  top: int = 0,
118
- ) -> None:
146
+ ) -> bool:
147
+ """Draw the board. Returns False (and shows a hint) if the terminal is
148
+ too small to fit it."""
149
+ required_rows, required_cols = _required_size()
150
+ max_y, max_x = stdscr.getmaxyx()
151
+ if max_y < required_rows or max_x < required_cols:
152
+ _draw_too_small(stdscr)
153
+ return False
154
+
119
155
  stdscr.erase()
120
156
  stdscr.addstr(top, 2, "♟ CLI OTHELLO", curses.color_pair(COLOR_HEADER) | curses.A_BOLD)
121
157
  stdscr.addstr(
@@ -184,6 +220,7 @@ def _draw_board(
184
220
  curses.color_pair(COLOR_STATUS),
185
221
  )
186
222
  stdscr.refresh()
223
+ return True
187
224
 
188
225
 
189
226
  def play_game(stdscr: "curses._CursesWindow", human_player: int, ai_level: int) -> None:
@@ -207,7 +244,10 @@ def play_game(stdscr: "curses._CursesWindow", human_player: int, ai_level: int)
207
244
 
208
245
  if turn == human_player:
209
246
  message = "あなたの番です"
210
- _draw_board(stdscr, board, tuple(cursor), legal, human_player, ai_level, message)
247
+ if not _draw_board(
248
+ stdscr, board, tuple(cursor), legal, human_player, ai_level, message
249
+ ):
250
+ continue
211
251
  key = stdscr.getch()
212
252
  if key in (curses.KEY_UP, ord("k")):
213
253
  cursor[0] = (cursor[0] - 1) % SIZE
@@ -228,6 +268,9 @@ def play_game(stdscr: "curses._CursesWindow", human_player: int, ai_level: int)
228
268
  else:
229
269
  message = "AIが考えています…"
230
270
  _draw_board(stdscr, board, tuple(cursor), legal, human_player, ai_level, message)
271
+ # If the terminal is too small, _draw_too_small() already
272
+ # blocked on a keypress above; proceed with the AI move
273
+ # regardless so the game keeps progressing once resized.
231
274
  move = ai.choose_move(board)
232
275
  if move is not None:
233
276
  board.play(*move, turn)
@@ -240,13 +283,18 @@ def play_game(stdscr: "curses._CursesWindow", human_player: int, ai_level: int)
240
283
  result = "あなたの勝ちです!"
241
284
  else:
242
285
  result = "AIの勝ちです"
243
- _draw_board(stdscr, board, tuple(cursor), set(), human_player, ai_level, result)
244
- stdscr.addstr(
245
- SIZE + 8,
246
- 4,
247
- "何かキーを押すと終了します",
248
- curses.color_pair(COLOR_STATUS),
249
- )
286
+
287
+ while not _draw_board(
288
+ stdscr, board, tuple(cursor), set(), human_player, ai_level, result
289
+ ):
290
+ pass
291
+
292
+ max_y, max_x = stdscr.getmaxyx()
293
+ footer_y = min(SIZE + 8, max_y - 1)
294
+ try:
295
+ stdscr.addstr(footer_y, 4, "何かキーを押すと終了します", curses.color_pair(COLOR_STATUS))
296
+ except curses.error:
297
+ pass
250
298
  stdscr.refresh()
251
299
  stdscr.getch()
252
300
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cli-othello
3
- Version: 1.0.1
3
+ Version: 1.0.2
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