Jak stworzyć grę w kółko i krzyżyk w Pythonie?

Zbudujmy wspólnie prostą grę w kółko i krzyżyk, wykorzystując język Python. To znakomity sposób, aby zgłębić logikę gier i nauczyć się, jak efektywnie organizować kod.

Gry stanowią popularną formę rozrywki. Różnorodne tytuły dostępne są w Internecie, na urządzeniach mobilnych, komputerach stacjonarnych i innych platformach. Tym razem nie skupimy się na tworzeniu zaawansowanej, rozbudowanej gry. Naszym celem jest stworzenie klasycznej gry w kółko i krzyżyk, działającej w wierszu poleceń (CLI), z wykorzystaniem Pythona.

Jeśli nie jesteś zaznajomiony z zasadami gry w kółko i krzyżyk, możesz zapoznać się z nią wizualnie, klikając tutaj. Nie martw się, jeśli zasady nie są dla Ciebie oczywiste – wszystko wyjaśnimy krok po kroku.

Gra w Kółko i Krzyżyk

Ten poradnik składa się z trzech głównych części. Na początku omówimy zasady gry w kółko i krzyżyk. Następnie przejdziemy do algorytmu, który pomoże nam skonstruować logikę gry. Wreszcie, zaprezentujemy kod oraz jego szczegółowe wyjaśnienie.

Jeśli zasady gry są Ci dobrze znane, możesz pominąć pierwszą sekcję.

Zacznijmy więc od pierwszej części naszego poradnika.

Zasady Gry

W grze bierze udział dwóch graczy. Każdy gracz jest reprezentowany przez unikalny symbol – zazwyczaj są to „X” i „O”. Gra toczy się na planszy składającej się z 9 pól.

Spójrz na wizualizację planszy do gry w kółko i krzyżyk.

Plansza do kółka i krzyżyka

Przebieg rozgrywki wygląda następująco:

  • Gracz numer jeden umieszcza swój symbol na wybranym, wolnym polu.
  • Następnie, gracz numer dwa umieszcza swój symbol na kolejnym, pustym polu.
  • Celem każdego z graczy jest ułożenie swoich symboli w jednej linii – w poziomie, pionie lub po przekątnej.
  • Gra trwa do momentu, gdy jeden z graczy osiągnie zwycięstwo lub gdy wszystkie pola zostaną zajęte, a gra zakończy się remisem.

Przyjrzyjmy się kilku przykładom rozgrywki.

W powyższym przykładzie gracz oznaczony symbolem „X” odnosi zwycięstwo. Jego symbole ułożyły się w linii po przekątnej. W taki sposób gracz zdobywa wygraną.

Istnieje łącznie osiem sposobów na ułożenie trzech identycznych symboli w linii prostej i wygranie gry. Spójrzmy na wszystkie osiem możliwości.

Remis następuje, gdy wszystkie pola zostaną zajęte, a żaden z graczy nie ułoży swoich symboli w zwycięskim układzie. Mam nadzieję, że teraz rozumiesz, jak grać w kółko i krzyżyk.

Czas na zabawę! Możesz odwiedzić tę stronę, aby zagrać i w pełni zrozumieć mechanikę gry. Jeśli jednak masz już jasność, pomiń ten krok.

Teraz przejdźmy do sekcji poświęconej algorytmowi.

Algorytm

W tej części omówimy algorytm, który pomoże nam w napisaniu kodu. Ten algorytm jest uniwersalny i możesz go zastosować w dowolnym języku programowania. Zobaczmy, jak to działa.

  • Zacznij od stworzenia dwuwymiarowej tablicy, która będzie reprezentować planszę. Wszystkie pola powinny być na początku puste.
    • Puste pola możesz reprezentować za pomocą dowolnego znaku. W naszym przypadku użyjemy łącznika: ’-’.
  • Zaimplementuj funkcję, która sprawdzi, czy plansza jest w pełni zapełniona.
    • Przejdź przez wszystkie elementy tablicy. Jeśli znajdziesz puste pole, zwróć `false`. W przeciwnym wypadku, zwróć `true`.
  • Napisz funkcję, która sprawdzi, czy dany gracz wygrał grę.
    • Sprawdź wszystkie możliwości ułożenia trzech symboli w jednej linii, o których wspomnieliśmy w poprzedniej sekcji.
    • Zweryfikuj wszystkie wiersze, kolumny i obie przekątne.
  • Utwórz funkcję do wyświetlania planszy. Będziemy jej używać wielokrotnie w trakcie rozgrywki.
  • Zaimplementuj funkcję, która uruchomi grę.
    • Wybierz losowo gracza, który rozpocznie grę.
    • Stwórz nieskończoną pętlę, która będzie działać do momentu zakończenia gry (zwycięstwo lub remis).
      • Wyświetl planszę, aby użytkownik mógł wybrać pole na swój ruch.
      • Poproś użytkownika o wprowadzenie numeru wiersza i kolumny.
      • Zaktualizuj wybrane pole symbolem aktualnego gracza.
      • Sprawdź, czy bieżący gracz wygrał.
      • Jeśli aktualny gracz wygrał, wyświetl komunikat o zwycięstwie i przerwij pętlę.
      • Następnie sprawdź, czy plansza jest w pełni zapełniona.
      • Jeśli plansza jest pełna, wyświetl komunikat o remisie i przerwij pętlę.
    • Na koniec wyświetl ostateczny widok planszy.

Mam nadzieję, że teraz lepiej rozumiesz, jak to działa. Jeśli jednak nie wszystko jest dla Ciebie jasne, nie martw się. Kod, który zaraz zobaczysz, rozjaśni wszystkie wątpliwości.

Przejdźmy więc do sekcji z kodem. Zakładam, że masz zainstalowanego Pythona, aby móc przetestować kod.

Kod

Przeanalizuj poniższy kod.

import random

class TicTacToe:

    def __init__(self):
        self.board = []

    def create_board(self):
        for i in range(3):
            row = []
            for j in range(3):
                row.append('-')
            self.board.append(row)

    def get_random_first_player(self):
        return random.randint(0, 1)

    def fix_spot(self, row, col, player):
        self.board[row][col] = player

    def is_player_win(self, player):
        win = None

        n = len(self.board)

        # checking rows
        for i in range(n):
            win = True
            for j in range(n):
                if self.board[i][j] != player:
                    win = False
                    break
            if win:
                return win

        # checking columns
        for i in range(n):
            win = True
            for j in range(n):
                if self.board[j][i] != player:
                    win = False
                    break
            if win:
                return win

        # checking diagonals
        win = True
        for i in range(n):
            if self.board[i][i] != player:
                win = False
                break
        if win:
            return win

        win = True
        for i in range(n):
            if self.board[i][n - 1 - i] != player:
                win = False
                break
        if win:
            return win
        return False

    def is_board_filled(self):
        for row in self.board:
            for item in row:
                if item == '-':
                    return False
        return True

    def swap_player_turn(self, player):
        return 'X' if player == 'O' else 'O'

    def show_board(self):
        for row in self.board:
            for item in row:
                print(item, end=" ")
            print()

    def start(self):
        self.create_board()

        player="X" if self.get_random_first_player() == 1 else 'O'
        while True:
            print(f"Player {player} turn")

            self.show_board()

            # taking user input
            row, col = list(
                map(int, input("Enter row and column numbers to fix spot: ").split()))
            print()

            # fixing the spot
            self.fix_spot(row - 1, col - 1, player)

            # checking whether current player is won or not
            if self.is_player_win(player):
                print(f"Player {player} wins the game!")
                break

            # checking whether the game is draw or not
            if self.is_board_filled():
                print("Match Draw!")
                break

            # swapping the turn
            player = self.swap_player_turn(player)

        # showing the final view of board
        print()
        self.show_board()


# starting the game
tic_tac_toe = TicTacToe()
tic_tac_toe.start()

Poniżej znajduje się przykład działania kodu.

$ python tic_tac_toe.py 
Player X turn
- - -
- - -
- - -
Enter row and column numbers to fix spot: 1 1

Player O turn
X - -
- - -
- - -
Enter row and column numbers to fix spot: 2 1

Player X turn
X - -
O - -
- - -
Enter row and column numbers to fix spot: 1 2

Player O turn
X X -
O - -
- - -
Enter row and column numbers to fix spot: 1 3

Player X turn
X X O
O - -
- - -
Enter row and column numbers to fix spot: 2 2

Player O turn
X X O
O X -
- - -
Enter row and column numbers to fix spot: 3 3

Player X turn
X X O        
O X -        
- - O
Enter row and column numbers to fix spot: 3 2

Player X wins the game!

X X O
O X -
- X O

Oto kilka kluczowych aspektów, które ułatwią Ci zrozumienie struktury kodu:

  • Użyliśmy klasy, aby zgrupować wszystkie metody w jednym miejscu. Dzięki temu kod staje się bardziej modułowy i łatwiejszy do ponownego użycia.
  • Dla każdego zadania, nawet najmniejszego, stworzyliśmy osobną funkcję. To podejście ułatwia utrzymanie i modyfikację kodu.
  • Powyższe dwa rozwiązania sprawiają, że aplikacja jest łatwa do aktualizacji i rozbudowy.

Możesz dostosować strukturę kodu i wprowadzić ulepszenia według własnych potrzeb. Struktura kodu nie jest sztywna i możesz ją zmieniać.

Podsumowanie

Gratulacje! 😎 Właśnie stworzyłeś grę w kółko i krzyżyk od podstaw. To nie jest gra z zaawansowaną grafiką, do jakich jesteśmy przyzwyczajeni. Jednak ten proces pomógł Ci zrozumieć logikę gier i nauczyć się tworzyć czystą i dobrze zorganizowaną strukturę kodu. Korzystaj z tych wskazówek, tworząc kolejne gry. Przypomnij sobie gry, w które grałeś w dzieciństwie, i spróbuj je odtworzyć.

Życzę Ci udanego kodowania! 👩‍💻

Następnie, możesz nauczyć się, jak stworzyć grę w odgadywanie liczb oraz jak pisać testy jednostkowe z wykorzystaniem modułu Python `unittest`.

Podobał Ci się ten artykuł? Podziel się nim ze znajomymi!