Tic tac toe, czy też kółko i krzyżyk, to jedna z najpopularniejszych gier na świecie, oraz doskonaly projekt dla początkujących programistów. Poniżej zobaczymy jeden z sposobów w jaki możemy tą grę napisać i wykorzystamy do tego prostą bibliotekę Python Turtle.

Import biblioteki Python Turtle oraz podstawowe ustawienia

Standardowo importujemy bibliotekę Turtle. Dodatkowo random oraz time. Przydadzą się później.

Tworzymy planszę gry o wymiarach 600 x 600. Rozmiar możemy ustawić za pomocą funkcji window.setup(). Współżędne lewego, górnego rogu to (-300, 300). Przyda się to nam potem. Do tego tworzymy naszego żółwia o ksywce ‚xo’, który będzie odpowiadać za rysowanie linii, Xów oraz O.

import turtle
import random
import time

window = turtle.Screen()

BOK = 600
X = -300
Y = 300

window.setup(BOK,BOK)
window.title('Kółko i krzyżyk')
window.bgcolor('black')

xo = turtle.Turtle()
xo.color('white')
xo.speed(0)
xo.pensize(7)
xo.hideturtle()

Najważniejsze zmienne

Cała tablica do gry w tic, tac, toe, składa się z 9 pól. 3 na 3.

Potrzebujemy zmiennej która będzie przechować informację czy i gdzie są postawione X oraz O. Możemy wykorzystać do tego prostą listę 3-elementową. Każdy jej element odpowiada za wiersz, i jest również listą 3 elementową. W ten sposób mamy możliwość przechowania 9 elementów.

tablica = [[None,None,None],
            [None,None,None],
            [None,None,None]]

kolej = random.choice(['x','o'])

Jeżeli użytkownik kliknie w powiedzmy, w pole po lewej na dole, to będziemy mogli odwołać się do tablicy poprzez tablica [ 2 ] [ 0 ]. Ale to zobaczymy za chwilę.

następną zmienną którą potrzebujemy to ‚kolej’. Zmienna kolej będzie przechowywać informację czyja jest kolej. Czy X czy O. Na początku jest losowana ta informacja, dlatego potrzebowaliśmy zaimportować bibliotekę random na początku programu.

Rysujemy siatkę do gry

Linie rysujemy w odstępie 1/3 szerokości. Zarówno w pionie jak i w poziomie. Tutaj przydają się X oraz Y zdefiniowane na początku. Pierwsza linia pionowa jest w odległości 1/3 długości boku oraz X. itd.

ODSTĘP = int(BOK / 3)

for a in [1,2]:

    # linie w pionie
    xo.penup()
    xo.goto(X + a*ODSTĘP, Y)
    xo.pendown()
    xo.goto(X + a*ODSTĘP, -Y)

    # linie w poziomie
    xo.penup()
    xo.goto(X, Y -a*ODSTĘP)
    xo.pendown()
    xo.goto(-X, Y -a*ODSTĘP)

W rezultacie otrzymujemy piękną siatkę i 9 pól.

Obsługa zdarzenia kliknięcia myszki

Na naszej siatce, będą pojawiać się X oraz O, w zależności od tego gdzie klieknie gracz. Należy poinformować Turtle, że po kliknięciu w planszę ma podjąć akcję.

window.onclick(click)

window.listen()
window.mainloop()

Następnie będziemy musieli utworzyć funkcję click()

Rysowanie X lub O

Funkcja click, ma całkiem sporo do zrobienia:

  1. Musi stwierdzić które pole klikną gracz. nie chodzi tylko o x i y, gdyż to zostanie jej przekazane przez parametry, ale o to które z 9 pól to jest.
  2. Następnie musi sprawdzić w zmiennej tablica czy to pole jest puste. Jeżeli jest tam już x albo o, to należy zignorować kliknięcie myszy
  3. Jeżeli pole jest puste, to należy narysować tam X lub O. W zależności czyja jest kolej
  4. Musimy dodać informację do zmiennej tablica, o nowym X lub O
  5. A następnie sprawdzić czy X lub O wygrywa. Jednak, do tego celu napiszemy osobną funkcję – sprawdź()
  6. Jeżeli mamy zwycięzce, to wstrzymujemy program na 1 sekundę, a następnie piszemy na środku ekranu, kto wygrał
def click(x,y):
    
    global kolej

    # które pole klikną gracz
    kolumna = 0
    wiersz = 0

    if x < X + ODSTĘP: kolumna = 0
    elif x > X + 2*ODSTĘP: kolumna = 2
    else: kolumna = 1

    if y < Y - 2*ODSTĘP: wiersz = 2
    elif y > Y - ODSTĘP: wiersz =0
    else: wiersz = 1

    # Czy pole, które klikną gracz, jest puste ?

    if tablica[wiersz][kolumna] != None: return

    # narysować X lub O, w zależności czyja jest kolej

    kolumna_środek = (kolumna*ODSTĘP + ODSTĘP/2) - BOK/2
    wiersz_środek = (-wiersz*ODSTĘP - ODSTĘP/2) + BOK/2

    xo.penup()
    xo.goto(kolumna_środek-25, wiersz_środek-25)
    if kolej == 'x': xo.write('X', font=('Arial',50))
    else: xo.write('O', font=('Arial',50))

    # dodać informację x / o do tablicy

    tablica[wiersz][kolumna] = kolej

    if kolej == 'o': kolej = 'x'
    else: kolej = 'o'

    # sprawdzić czy x lub o wygrywają

    if sprawdz() != None:
        xo.penup()
        xo.goto(-150,0)
        time.sleep(1)
        xo.clear()
        xo.write(" Wygrały " + sprawdz(), font=("Arial",50))

Sprawdzanie czy X lub O wygrały

Funkcja sprawdź(), jest wykorzystywa przez funkcję click() i wywolywana po pojawieniu sie nowego X oraz O. Jej zadaniem jest sprawdzenie czy mamy zwyciężcę, a jeżeli tak, to zwrócenie informacji czy jest to X czy O. Gracz wygrywa, w momencie w którym X lub O:

  • Zajmują całą kolumnę
  • Zajmują cały wiersz
  • Zajmują 3 pola po skosie

Jeżeli funkcja stwierdzi że ma takie same wartości, X lub O, to zwraca tą wartość.

def sprawdz():
    
    # po skosie
    if tablica[0][0] == tablica[1][1] == tablica[2][2]: return tablica[2][2]
    if tablica[0][2] == tablica[1][1] == tablica[2][0]: return tablica[2][0]

    # w wierszu
    for w in range(3): 
        if tablica[w][0] == tablica[w][1] == tablica[w][2]: return tablica[w][0]
        
    # w kolumnie
    for k in range(2):
        if tablica[0][k] == tablica[1][k] == tablica[2][k]: return tablica[0][k]

    return None

Podsumowując

Python Turtle, poradził sobie z prostą grafiką, jaka była potrzebna do gry tic tac toe, jednak nie jest to biblioteka, która jest zoptymalizowana pod gry. W kolejnych artykułach, będziemy pokazywać bardziej złożone gry takie jak pac man czy tetris i tym razem sięgniemy po bibliotekę pygame. Działa ona bardzo podobnie do Python Turtle, tak więc zmiana będzie bardzo prosta, natomiast przy bardziej rozbudowanych grach, spisze się lepiej.

Do Python Trutle, będziemy wracać, gdyż jest to bardzo dobra biblioteka aby uczyć się Python oraz wizualizować różne ciekawe koncepcje, jak na przykład funkcje rekurencyjne.

Python Turtle

 

 

Całość kodu

import turtle
import random
import time

window = turtle.Screen()

BOK = 600
X = -300
Y = 300

window.setup(BOK,BOK)
window.title('Kółko i krzyżyk')
window.bgcolor('black')

xo = turtle.Turtle()
xo.color('white')
xo.speed(0)
xo.pensize(7)
xo.hideturtle()

tablica = [[None,None,None],
            [None,None,None],
            [None,None,None]]

kolej = random.choice(['x','o'])

# linie

ODSTĘP = int(BOK / 3)

for a in [1,2]:
    xo.penup()
    xo.goto(X + a*ODSTĘP, Y)
    xo.pendown()
    xo.goto(X + a*ODSTĘP, -Y)

    xo.penup()
    xo.goto(X, Y -a*ODSTĘP)
    xo.pendown()
    xo.goto(-X, Y -a*ODSTĘP)

def sprawdz():
    
    # po skosie
    if tablica[0][0] == tablica[1][1] == tablica[2][2]: return tablica[2][2]
    if tablica[0][2] == tablica[1][1] == tablica[2][0]: return tablica[2][0]

    # w wierszu
    for w in range(3): 
        if tablica[w][0] == tablica[w][1] == tablica[w][2]: return tablica[w][0]
        
    # w kolumnie
    for k in range(2):
        if tablica[0][k] == tablica[1][k] == tablica[2][k]: return tablica[0][k]

    return None

def click(x,y):
    
    global kolej

    # które to pole
    kolumna = 0
    wiersz = 0

    if x < X + ODSTĘP: kolumna = 0
    elif x > X + 2*ODSTĘP: kolumna = 2
    else: kolumna = 1

    if y < Y - 2*ODSTĘP: wiersz = 2
    elif y > Y - ODSTĘP: wiersz =0
    else: wiersz = 1

    # pole jest puste ?

    if tablica[wiersz][kolumna] != None: return

    # narysować

    kolumna_środek = (kolumna*ODSTĘP + ODSTĘP/2) - BOK/2
    wiersz_środek = (-wiersz*ODSTĘP - ODSTĘP/2) + BOK/2

    xo.penup()
    xo.goto(kolumna_środek-25, wiersz_środek-25)
    if kolej == 'x': xo.write('X', font=('Arial',50))
    else: xo.write('O', font=('Arial',50))

    # dodać informację x / o

    tablica[wiersz][kolumna] = kolej

    if kolej == 'o': kolej = 'x'
    else: kolej = 'o'

    # sprawdź

    if sprawdz() != None:
        xo.penup()
        xo.goto(-150,0)
        time.sleep(1)
        xo.clear()
        xo.write(" Wygrały " + sprawdz(), font=("Arial",50))

window.onclick(click)

window.listen()
window.mainloop()