Rozdział 17 · Ostatnie poprawki

Tic-Tac-Toe Pro — pełny program i wyniki rozdziału

Ta sama gra co w rozdziale 17.6 — ale teraz z modelem, zasadami, testami i architekturą, które wytrzymają rozwój projektu.

Program końcowy

Końcowe okno Tic-Tac-Toe Pro z trwającą grą i wynikiem X:1 O:2 Remisy:1
Prawdziwe okno finalnej wersji to model, zasady, partytura, podświetlenie i klawiatura razem. Poniżej znajduje się struktura całego pliku, nie tylko jednego fragmentu.

Plik jest kompletny, samodzielny i nie posiada niewidzialnych zależności od innych lekcji:

projects/tkinter/tic-tac-toe/tic_tac_toe.py

tic_tac_toe.py — struktura
WINNING_LINES = (...)

def find_winner(board): ...
def is_draw(board): ...
def load_scores(): ...        # opcjonalne zapisywanie wyniku (17.27)
def save_scores(state): ...

@dataclass
class GameState:
    ...

class TicTacToeApp:
    def __init__(self, root, *, persist_scores=False): ...
    def build_ui(self): ...
    def build_board(self, outer): ...
    def attempt_move(self, index): ...
    def on_cell_enter(self, index): ...
    def on_cell_leave(self, index): ...
    def on_key(self, event): ...
    def render(self): ...
    def new_round(self): ...
    def new_match(self): ...
    def pulse_winning_line(self, tick=0): ...
    def cancel_pulse(self): ...      # odwołuje zaplanowany after() (17:30)
    def on_close(self): ...

def main():
    root = tk.Tk()
    app = TicTacToeApp(root)
    root.mainloop()

if __name__ == "__main__":
    main()
Uruchom grę u siebie
python tic_tac_toe.py w terminalu — albo Run przycisku w VS Code, albo PyCharm. Porównaj z tic_tac_toe_basic.py (Rozdział 17.6) to ten sam wynik dla gracza, z zupełnie inną architekturą wewnętrzną.

Lista gotowych gier

MODEL
  • pole (board) jest oddzielna od widgetów
  • bieżący gracz — jawne pole stanu
  • terminal state (game_over/winner) jest polem jawnym, a nie wyjściem z widgetów
RULES
  • nieprawidłowe ruchy są odbite i nie zmieniają gracza
  • wszystkie 8 linii wypłatnych testowanych na X i O
  • losowanie jest sprawdzane PO wygranej
UI
  • status tury jest zawsze widoczny
  • zwycięzca jest widoczny nie tylko po kolorze
  • pole reaguje na zmiany rozmiaru okien
  • klawiatura działa
ARCHITEKTURA
  • callback- i krótkie: walidacja → model → render
  • czyste zasady są testowane bez okna
  • render() ustala kanoniczny widok na podstawie modelu; Efekty tymczasowe są nałożone na to

Most do rozdziału 18

Dalej: GDZIE, nie tylko KTO i CO
W tej grze wydarzenia pomogły nam zrozumieć, KTO zareagował i CO powinno się wydarzyć. Ponadto wydarzenia z myszy podają nam WSPÓŁRZĘDNE — event.x oraz event.y. W następnym rozdziale współrzędne myszy staną się podstawą do rysowania na Canvas.
Praktyka: Tic-Tac-Toe Pro całość
Moduł tkinter otwiera natywne okno Python — wykonaj lokalnie w VS Code, PyCharm lub Jupyter
Praktyka kursuje lokalnie
Otwórz praktykę →

Streszczenie rozdziału 17

Co zbudowaliśmy i czego się nauczyliśmy

  • Zdarzenie, callback, command i binding to cztery różne, powiązane pojęcia; callback command= zazwyczaj nie otrzymuje Event; callback zarejestrowany przez bind() go otrzymuje.
  • command= opisuje główną akcję Button; bind() jest jawną odpowiedzią na konkretne zdarzenie myszy lub klawiatury. Wbudowane sposoby aktywacji Button zależą od klasy i platformy widgetu, więc command i bind nie powinny być traktowane jako zamienne.
  • Stan gry — nie to samo co widżety, które go pokazują: najechanie myszą udowadnia to najlepiej.
  • find_winner(board) i is_draw(board) — funkcje czyste, testowane bez żadnego otwartego okna; kolejność „najpierw zwycięstwo, potem remis” — część zasad, a nie szczegół implementacyjny.
  • Mysz (command=) i klawiatura (bind na root) zbiegają się do tej samej funkcji attempt_move() – zasady gry istnieją tylko w jednym miejscu.
  • render() ustawia kanoniczny wyświetlacz bazy Z modelu. Najechanie myszką i krótki akcent zwycięstwa tymczasowo zmieniają widok na górze bez zmiany GameState; następny render() ponownie całkowicie przywraca widok modelu.
  • Subtelne efekty wizualne (podgląd po najechaniu, podświetlenie linii, puls zwycięstwa) opierają się na solidnej architekturze — są możliwe właśnie dlatego, że model jest oddzielony od widoku.