import pygame import random import sys pygame.init() # --- Konstanty okna a rozvržení mřížky --- SIRKA_OKNA = 600 VYSKA_OKNA = 600 FPS = 30 RADKY = 4 SLOUPCE = 4 KARTICKA_VELIKOST = 100 MEZERA = 20 # Výpočet celkové šířky a výšky mřížky, abychom ji mohli vycentrovat Mrizka_sirka = (SLOUPCE * KARTICKA_VELIKOST) + ((SLOUPCE - 1) * MEZERA) Mrizka_vyska = (RADKY * KARTICKA_VELIKOST) + ((RADKY - 1) * MEZERA) # Odskoky zleva a shora pro vykreslování Odsazeni_x = (SIRKA_OKNA - Mrizka_sirka) // 2 Odsazeni_y = (VYSKA_OKNA - Mrizka_vyska) // 2 # Barvy (R, G, B) BILA = (255, 255, 255) SEDA = (150, 150, 150) TMAVE_MODRA = (20, 20, 80) ZELENA_TEXT = (50, 255, 50) # Potřebujeme 8 barev pro 8 párů = 16 karet 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á ] okno = pygame.display.set_mode((SIRKA_OKNA, VYSKA_OKNA)) pygame.display.set_caption("Pexeso (Hledání barevných párů)") hodiny = pygame.time.Clock() font = pygame.font.SysFont("arial", 40, bold=True) font_maly = pygame.font.SysFont("arial", 20) # --- Třída objektu - objektově orientované programování (OOP) --- # Použití objektu pro "Kartičku" nám velmi zjednoduší udržování informace # o tom, jaká barva na kartičce je, a jestli je otočená nebo zakrytá. class Karticka: def __init__(self, radek, sloupec, barva_vnitrku): self.barva = barva_vnitrku # Stavy kartičky (boolean) self.odkryta = False # Zda ji hráč právě otočil self.nalezena = False # Zda už hráč našel její pár (tím ji vyřadil) # Výpočet její pevné x,y souřadnice na obrazovce podle toho v jakém je sloupci a řádku self.x = Odsazeni_x + sloupec * (KARTICKA_VELIKOST + MEZERA) self.y = Odsazeni_y + radek * (KARTICKA_VELIKOST + MEZERA) # Uložíme si Rect pro zjišťování kolize s myší self.rect = pygame.Rect(self.x, self.y, KARTICKA_VELIKOST, KARTICKA_VELIKOST) def vykresli(self): # Pokud je karta lícem nahoru (odkrytá nebo už nalezena), kreslíme její skrytou barvu if self.odkryta or self.nalezena: pygame.draw.rect(okno, self.barva, self.rect) else: # Rub karty - šedivá barva pygame.draw.rect(okno, SEDA, self.rect) # Obrys kolem kartičky pro lepší vzhled pygame.draw.rect(okno, BILA, self.rect, 3) def hlavni_smycka(): # 1. Příprava seznamu barev # Seznam BARVY_PARU znásobíme 2, abychom od každé barvy měli dvě (pár) barvy_do_hry = BARVY_PARU * 2 random.shuffle(barvy_do_hry) # Náhodně zamícháme pořadí # 2. Vytvoření mřížky kartiček (2D pole) # Vznikne struktura 'seznam v seznamu', ke kartě se přistoupí pomocí karticky[radek][sloupec] karticky = [] index_barvy = 0 for radek in range(RADKY): rada = [] for sloupec in range(SLOUPCE): karta = Karticka(radek, sloupec, barvy_do_hry[index_barvy]) rada.append(karta) index_barvy += 1 karticky.append(rada) # Proměnné pro pamatování si, na které karty hráč zrovna kliknul prvni_vybrana = None druha_vybrana = None pocet_pokusu = 0 nalezeno_paru = 0 while True: # --- Zpracování událostí --- for udalost in pygame.event.get(): if udalost.type == pygame.QUIT: pygame.quit() sys.exit() # Zjišťování KLIKNUTÍ MYŠÍ if udalost.type == pygame.MOUSEBUTTONDOWN and udalost.button == 1: # button 1 = levé tlačítko # Bezpečnostní pojistka - zablokujeme klikání, pokud už máme 2 karty otočené # a čekáme např. na jejich skrytí v případě, že se neshodují. if prvni_vybrana is not None and druha_vybrana is not None: continue # Kde přesně je myš? Získáme X a Y obrazovky mys_x, mys_y = pygame.mouse.get_pos() # Projdeme všechny karty a zjistíme, jestli bod myši je v obdélníku karty for radek in range(RADKY): for sloupec in range(SLOUPCE): karta = karticky[radek][sloupec] # collidepoint() vrací True, pokud je x,y uvnitř obdélníku karty if karta.rect.collidepoint(mys_x, mys_y): # Otočíme kartu, jen když ještě není odkrytá nebo nalezena if not karta.odkryta and not karta.nalezena: karta.odkryta = True # Je to první vybraná karta v tomto tahu? if prvni_vybrana is None: prvni_vybrana = karta else: # Je to druhá vybraná karta! Tah je dokončen. druha_vybrana = karta pocet_pokusu += 1 # --- Vykreslování --- okno.fill(TMAVE_MODRA) # Zavoláme metodu vykresli() pro všechny kartičky v tabulce for radek in range(RADKY): for sloupec in range(SLOUPCE): karticky[radek][sloupec].vykresli() # UI s počtem tahů text_tahy = font_maly.render(f"Počet pokusů: {pocet_pokusu}", True, BILA) okno.blit(text_tahy, (10, 10)) # Zpráva o vítězství if nalezeno_paru == 8: # Maximum možných párů je polovina počtu karet text_konec = font.render("Vítězství! Skvělá paměť.", True, ZELENA_TEXT) rect = text_konec.get_rect(center=(SIRKA_OKNA // 2, VYSKA_OKNA - 30)) okno.blit(text_konec, rect) # Provedeme "vyfocení" na obrazovku ABY BYLA DRUHÁ KARTA VIDĚT PŘED PAUZOU! pygame.display.flip() # --- Logika Pexesa (Vyhodnocení po odkrytí druhé karty) --- if prvni_vybrana is not None and druha_vybrana is not None: if prvni_vybrana.barva == druha_vybrana.barva: # Našli jsme PÁR! prvni_vybrana.nalezena = True druha_vybrana.nalezena = True nalezeno_paru += 1 else: # NENAŠLI. Karty se k sobě nehodí. # Musíme na 1 vteřinu zastavit program, aby si hráč stihl zapamatovat barvy. # Použijeme pygame.time.wait(), které "zmrazí" program (hráč nemůže klikat atd.). # Pro takhle jednoduché výukové pexeso je to naprosto v pořádku. pygame.time.wait(1000) # Zase je otočíme rubem vzhůru prvni_vybrana.odkryta = False druha_vybrana.odkryta = False # Vynulujeme výběr pro další tah, ať hráč může volit další karty prvni_vybrana = None druha_vybrana = None # Rychlost smyčky hodiny.tick(FPS) if __name__ == "__main__": # Tady pexeso neběží donekonečna, po vítězství program čeká, dokud jej nezavřeme hlavni_smycka()