You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
10 KiB
216 lines
10 KiB
import pygame
|
|
import random
|
|
import sys
|
|
|
|
# pygame.init() nastartuje všechny vnitřní moduly Pygame.
|
|
# Je to naprosto povinný první krok před tím, než můžeme v Pygame cokoliv udělat.
|
|
pygame.init()
|
|
|
|
# --- Konstanty okna a rozvržení mřížky ---
|
|
# Konstanty (velkými písmeny) se během hry nemění. Určují základní vlastnosti naší hry.
|
|
SIRKA_OKNA = 600
|
|
VYSKA_OKNA = 600
|
|
FPS = 30 # Počet snímků za sekundu (jak rychle se hra překresluje). 30 bohatě stačí pro Pexeso.
|
|
|
|
# Kolik karet chceme mít na šířku a na výšku?
|
|
RADKY = 4
|
|
SLOUPCE = 4
|
|
# Velikost jedné karty v pixelech (obrazových bodech)
|
|
KARTICKA_VELIKOST = 100
|
|
# Mezera mezi kartičkami
|
|
MEZERA = 20
|
|
|
|
# Výpočet celkové šířky a výšky celé mřížky karet, abychom ji pak mohli na obrazovce vycentrovat
|
|
Mrizka_sirka = (SLOUPCE * KARTICKA_VELIKOST) + ((SLOUPCE - 1) * MEZERA)
|
|
Mrizka_vyska = (RADKY * KARTICKA_VELIKOST) + ((RADKY - 1) * MEZERA)
|
|
|
|
# Vypočítáme, kde mřížka začíná na osách X (vodorovně) a Y (svisle), aby byla přesně uprostřed okna
|
|
Odsazeni_x = (SIRKA_OKNA - Mrizka_sirka) // 2
|
|
Odsazeni_y = (VYSKA_OKNA - Mrizka_vyska) // 2
|
|
|
|
# Barvy v Pygame se zadávají ve formátu (R, G, B) = Red, Green, Blue.
|
|
# Každá hodnota je od 0 (nic) do 255 (maximum dané barvy).
|
|
BILA = (255, 255, 255)
|
|
SEDA = (150, 150, 150)
|
|
TMAVE_MODRA = (20, 20, 80)
|
|
ZELENA_TEXT = (50, 255, 50)
|
|
|
|
# Budeme mít celkem 16 karet (4x4), což znamená 8 různých párů (8 unikátních barev).
|
|
BARVY_PARU = [
|
|
(255, 0, 0), # Červená
|
|
(0, 255, 0), # Světle Zelená
|
|
(0, 0, 255), # Modrá
|
|
(255, 255, 0), # Žlutá
|
|
(255, 0, 255), # Fialová
|
|
(0, 255, 255), # Azurová
|
|
(255, 165, 0), # Oranžová
|
|
(139, 69, 19) # Hnědá
|
|
]
|
|
|
|
# Vytvoříme samotné okno (obrazovku), kam se bude vše vykreslovat
|
|
okno = pygame.display.set_mode((SIRKA_OKNA, VYSKA_OKNA))
|
|
# Nastavíme text, který uvidíme nahoře v liště okna
|
|
pygame.display.set_caption("Pexeso (Hledání barevných párů)")
|
|
|
|
# Založíme si herní "hodiny" - pomohou nám udržovat hru v rychlosti stanovené přes FPS
|
|
hodiny = pygame.time.Clock()
|
|
|
|
# Fonty slouží pro vykreslování textu. Načteme si dva různé.
|
|
font = pygame.font.SysFont("arial", 40, bold=True)
|
|
font_maly = pygame.font.SysFont("arial", 20)
|
|
|
|
# --- Třída objektu - objektově orientované programování (OOP) ---
|
|
# Třída je jako "plánek" na vytvoření konkrétních věcí. Zde je to plánek na vytvoření "Kartičky".
|
|
# Každá kartička si bude sama pamatovat, jakou má barvu a jestli je už otočená.
|
|
class Karticka:
|
|
def __init__(self, radek, sloupec, barva_vnitrku):
|
|
self.barva = barva_vnitrku # Tato barva bude vidět, když se karta otočí
|
|
|
|
# Stavové proměnné (True = ano, False = ne)
|
|
self.odkryta = False # Zda ji hráč v tomto tahu právě teď otočil
|
|
self.nalezena = False # Zda už hráč našel její pár a karta je tak z kola venku
|
|
|
|
# Matematika! Vypočítáme přesnou pozici X a Y (v pixelech), kam se tato karta nakreslí.
|
|
self.x = Odsazeni_x + sloupec * (KARTICKA_VELIKOST + MEZERA)
|
|
self.y = Odsazeni_y + radek * (KARTICKA_VELIKOST + MEZERA)
|
|
|
|
# pygame.Rect vytvoří "neviditelný obdélník" kolem naší kartičky.
|
|
# Díky němu se mnohem snadněji zjišťuje, jestli na kartičku hráč kliknul myší.
|
|
self.rect = pygame.Rect(self.x, self.y, KARTICKA_VELIKOST, KARTICKA_VELIKOST)
|
|
|
|
def vykresli(self):
|
|
# Funkce (metoda), která zajistí, že se karta správně namaluje na obrazovku
|
|
|
|
if self.odkryta or self.nalezena:
|
|
# Pokud je karta odkrytá (otočená), namalujeme její tajnou barvu
|
|
pygame.draw.rect(okno, self.barva, self.rect)
|
|
else:
|
|
# Pokud karta leží rubem nahoru, namalujeme ji šedou (nebo jakýkoliv jiný vzor chceme)
|
|
pygame.draw.rect(okno, SEDA, self.rect)
|
|
|
|
# Kromě výplně nakreslíme ještě bílý obrys (rámeček) o tloušťce 3 pixely, ať to lépe vypadá
|
|
pygame.draw.rect(okno, BILA, self.rect, 3)
|
|
|
|
def hlavni_smycka():
|
|
# --- PŘÍPRAVA HRY ---
|
|
# 1. Připravíme si seznam barev. Chceme 8 párů, takže každou barvu z BARVY_PARU potřebujeme dvakrát.
|
|
barvy_do_hry = BARVY_PARU * 2
|
|
# Modul random má funkci shuffle, která pořadí položek v seznamu krásně zamíchá.
|
|
random.shuffle(barvy_do_hry)
|
|
|
|
# 2. Vytvoření "mřížky" kartiček (2D pole, tedy seznam v seznamu)
|
|
karticky = []
|
|
index_barvy = 0 # Slouží k tomu, abychom z listu barvy_do_hry postupně brali barvy
|
|
|
|
for radek in range(RADKY):
|
|
rada = [] # Vytvoříme prázdný seznam pro jeden konkrétní řádek
|
|
for sloupec in range(SLOUPCE):
|
|
# Pro každé políčko vytvoříme nový objekt podle našeho "plánku" Karticka
|
|
karta = Karticka(radek, sloupec, barvy_do_hry[index_barvy])
|
|
rada.append(karta) # Kartu přidáme do řádku
|
|
index_barvy += 1
|
|
karticky.append(rada) # Celý naplněný řádek přidáme do hlavní mřížky
|
|
|
|
# Proměnné pro systém hry - pamatujeme si, co hráč naklikal v aktuálním tahu
|
|
prvni_vybrana = None
|
|
druha_vybrana = None
|
|
|
|
pocet_pokusu = 0
|
|
nalezeno_paru = 0
|
|
|
|
# --- HLAVNÍ HERNÍ SMYČKA ---
|
|
# Tento cyklus 'while True' běží pořád dokola, stokrát za sekundu a tvoří samotnou hru
|
|
while True:
|
|
|
|
# 1. ZPRACOVÁNÍ UDÁLOSTÍ (Event handling)
|
|
# Události jsou vstupy od hráče: stisknutí klávesy, kliknutí myší, zavření okna křížkem...
|
|
for udalost in pygame.event.get():
|
|
# Pokud hráč klikl na červený křížek okna, ukončíme Pygame a celou aplikaci
|
|
if udalost.type == pygame.QUIT:
|
|
pygame.quit()
|
|
sys.exit()
|
|
|
|
# Kontrola kliknutí myší (MOUSEBUTTONDOWN = tlačítko zmáčknuto dolů, button 1 = levé tlačítko)
|
|
if udalost.type == pygame.MOUSEBUTTONDOWN and udalost.button == 1:
|
|
|
|
# Pokud už hráč v tomto tahu otočil dvě karty a čekáme, zabráníme mu klikat dál!
|
|
if prvni_vybrana is not None and druha_vybrana is not None:
|
|
continue # "continue" přeskočí zbytek kódu v této smyčce a nedovolí mu kartu otočit
|
|
|
|
# Kde přesně se myš nachází? Souřadnice X,Y na obrazovce.
|
|
mys_x, mys_y = pygame.mouse.get_pos()
|
|
|
|
# Projdeme všechny naše karty jednu po druhé a zkontrolujeme, zda hráč neklikl na některou z nich
|
|
for radek in range(RADKY):
|
|
for sloupec in range(SLOUPCE):
|
|
karta = karticky[radek][sloupec]
|
|
|
|
# Metoda collidepoint zjistí, zda se bod (myš) nachází uvnitř obdélníku (karty)
|
|
if karta.rect.collidepoint(mys_x, mys_y):
|
|
# Otočit můžeme jen kartu, která ještě NENÍ otočená
|
|
if not karta.odkryta and not karta.nalezena:
|
|
karta.odkryta = True # Hráč ji otočil!
|
|
|
|
# Systém logiky: Byla tohle první karta v tahu?
|
|
if prvni_vybrana is None:
|
|
prvni_vybrana = karta
|
|
else:
|
|
# Nebyla, takže to už musí být druhá karta v tahu.
|
|
druha_vybrana = karta
|
|
pocet_pokusu += 1 # Tah končí, započítáme pokus
|
|
|
|
# 2. VYKRESLOVÁNÍ (Kreslíme nový "snímek" - frame)
|
|
# Nejdřív vždy smažeme starý obraz tím, že celé okno přebarvíme jednolitou barvou
|
|
okno.fill(TMAVE_MODRA)
|
|
|
|
# Projdeme mřížku a řekneme každé kartičce, aby se nakreslila na okno
|
|
for radek in range(RADKY):
|
|
for sloupec in range(SLOUPCE):
|
|
karticky[radek][sloupec].vykresli()
|
|
|
|
# Vykreslíme text s počtem pokusů. Funkce render vytvoří z textu "obrázek", který pak můžeme vykreslit
|
|
text_tahy = font_maly.render(f"Počet pokusů: {pocet_pokusu}", True, BILA)
|
|
# blit je příkaz pro "nalep tento obrázek na dané souřadnice"
|
|
okno.blit(text_tahy, (10, 10))
|
|
|
|
# Zkontrolujeme vítězství
|
|
if nalezeno_paru == 8: # Maximum možných párů je 8
|
|
text_konec = font.render("Vítězství! Skvělá paměť.", True, ZELENA_TEXT)
|
|
# Center zarovná text hezky doprostřed požadované X pozice
|
|
rect = text_konec.get_rect(center=(SIRKA_OKNA // 2, VYSKA_OKNA - 30))
|
|
okno.blit(text_konec, rect)
|
|
|
|
# ZÁSADNÍ VĚC: Po tom co jsme do paměti Pygame naskládali příkazy kreslení,
|
|
# musíme to všechno najednou zviditelnit na obrazovce pomocí příkazu flip() nebo update()!
|
|
# Děláme to už teď, abychom (pokud budeme dole hru pauzovat), viděli otočenou druhou kartu.
|
|
pygame.display.flip()
|
|
|
|
# 3. HERNÍ LOGIKA: Vyhodnocení tahu
|
|
# Pokud už hráč vybral dvě karty, musíme zjistit, jestli udělal pár
|
|
if prvni_vybrana is not None and druha_vybrana is not None:
|
|
if prvni_vybrana.barva == druha_vybrana.barva:
|
|
# SUPER! Barvy se shodují, je to PÁR!
|
|
prvni_vybrana.nalezena = True
|
|
druha_vybrana.nalezena = True
|
|
nalezeno_paru += 1
|
|
else:
|
|
# ŠPATNĚ! Barvy se liší.
|
|
# Aby hráč vůbec stihl zaregistrovat barvu druhé karty, musíme na chvíli zmrazit hru
|
|
# wait(1000) hru zastaví přesně na 1000 milisekund (1 sekundu)
|
|
pygame.time.wait(1000)
|
|
|
|
# A pak obě karty otočíme zase lícem dolů (šedá strana nahoru)
|
|
prvni_vybrana.odkryta = False
|
|
druha_vybrana.odkryta = False
|
|
|
|
# Tah je u konce, ať už to byl pár nebo ne. Vyčistíme výběr pro další tah!
|
|
prvni_vybrana = None
|
|
druha_vybrana = None
|
|
|
|
# Rychlost smyčky: Řekneme hodinám, že chceme, aby smyčka běžela maximálně tolikrát za vteřinu, jak určuje FPS
|
|
hodiny.tick(FPS)
|
|
|
|
# Tohle říká Pythonu: Pokud tento soubor spouštíš jako hlavní program (ne jen importuješ),
|
|
# tak teprve tehdy spusť hlani_smycka()
|
|
if __name__ == "__main__":
|
|
hlavni_smycka()
|
|
|