Adds timer to gameplay
This commit is contained in:
parent
3b3cfa9d8a
commit
ee14d51d35
1 changed files with 48 additions and 3 deletions
|
|
@ -28,6 +28,7 @@ Notes
|
|||
|
||||
import curses
|
||||
import random
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
|
|
@ -141,8 +142,21 @@ class FreeCellGame:
|
|||
self.cursor_index = 0
|
||||
|
||||
self.status = "Arrow keys move, v selects a stack, ? shows a hint."
|
||||
self.start_time = time.monotonic()
|
||||
self.finished_time_seconds: Optional[int] = None
|
||||
self._deal_new_game()
|
||||
|
||||
def elapsed_time_seconds(self) -> int:
|
||||
"""Return elapsed play time, freezing it after a win."""
|
||||
if self.finished_time_seconds is not None:
|
||||
return self.finished_time_seconds
|
||||
|
||||
elapsed = int(time.monotonic() - self.start_time)
|
||||
if self.is_won():
|
||||
self.finished_time_seconds = elapsed
|
||||
return self.finished_time_seconds
|
||||
return elapsed
|
||||
|
||||
def clear_hint(self) -> None:
|
||||
"""Drop the currently remembered hint highlight."""
|
||||
self.hint_move = None
|
||||
|
|
@ -211,7 +225,9 @@ class FreeCellGame:
|
|||
|
||||
move = self.move_history[-1]
|
||||
if not self._remove_cards_from_destination(move):
|
||||
self.status = "Undo failed because the board no longer matches the last move."
|
||||
self.status = (
|
||||
"Undo failed because the board no longer matches the last move."
|
||||
)
|
||||
return
|
||||
|
||||
self.move_history.pop()
|
||||
|
|
@ -917,7 +933,9 @@ class FreeCellGame:
|
|||
else:
|
||||
self.freecells[source[1]] = None
|
||||
|
||||
self.record_move(source[0], source[1], "foundation", SUITS.index(card.suit), [card])
|
||||
self.record_move(
|
||||
source[0], source[1], "foundation", SUITS.index(card.suit), [card]
|
||||
)
|
||||
|
||||
self.status = f"Moved {card.short_name()} to foundation."
|
||||
|
||||
|
|
@ -1229,11 +1247,18 @@ def draw_help(stdscr, max_y: int) -> None:
|
|||
stdscr.addnstr(y, 2, help_text, max(0, curses.COLS - 4), curses.color_pair(1))
|
||||
|
||||
|
||||
def format_elapsed_time(seconds: int) -> str:
|
||||
"""Format elapsed seconds as MM:SS."""
|
||||
minutes, seconds = divmod(max(0, seconds), 60)
|
||||
return f"{minutes:02d}:{seconds:02d}"
|
||||
|
||||
|
||||
def render(stdscr, game: FreeCellGame) -> None:
|
||||
"""Redraw the full screen."""
|
||||
stdscr.erase()
|
||||
max_y, max_x = stdscr.getmaxyx()
|
||||
layout = compute_board_layout(max_x)
|
||||
elapsed_text = f"Time: {format_elapsed_time(game.elapsed_time_seconds())}"
|
||||
|
||||
title = "mcfreecell 0.1"
|
||||
if len(title) > max_x - 4:
|
||||
|
|
@ -1247,6 +1272,16 @@ def render(stdscr, game: FreeCellGame) -> None:
|
|||
curses.color_pair(1) | curses.A_BOLD,
|
||||
)
|
||||
|
||||
timer_x = max(2, max_x - len(elapsed_text) - 2)
|
||||
if timer_x > title_x + len(title):
|
||||
stdscr.addnstr(
|
||||
0,
|
||||
timer_x,
|
||||
elapsed_text,
|
||||
max(0, max_x - timer_x - 1),
|
||||
curses.color_pair(1) | curses.A_BOLD,
|
||||
)
|
||||
|
||||
if game.visual_mode:
|
||||
visual_text = "-- VISUAL --"
|
||||
visual_x = min(max_x - len(visual_text) - 2, title_x + len(title) + 3)
|
||||
|
|
@ -1262,7 +1297,14 @@ def render(stdscr, game: FreeCellGame) -> None:
|
|||
draw_help(stdscr, max_y)
|
||||
|
||||
if game.is_won():
|
||||
stdscr.addstr(3, 2, "You won.", curses.color_pair(5) | curses.A_BOLD)
|
||||
win_text = f"You won in {format_elapsed_time(game.elapsed_time_seconds())}."
|
||||
stdscr.addnstr(
|
||||
3,
|
||||
2,
|
||||
win_text,
|
||||
max(0, max_x - 4),
|
||||
curses.color_pair(5) | curses.A_BOLD,
|
||||
)
|
||||
|
||||
stdscr.refresh()
|
||||
|
||||
|
|
@ -1395,6 +1437,7 @@ def curses_main(stdscr) -> None:
|
|||
"""Main UI entry point."""
|
||||
curses.curs_set(0)
|
||||
stdscr.keypad(True)
|
||||
stdscr.timeout(100)
|
||||
|
||||
init_colors()
|
||||
|
||||
|
|
@ -1403,6 +1446,8 @@ def curses_main(stdscr) -> None:
|
|||
while True:
|
||||
render(stdscr, game)
|
||||
ch = stdscr.getch()
|
||||
if ch == -1:
|
||||
continue
|
||||
if not handle_key(game, ch):
|
||||
break
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue