uploud new

This commit is contained in:
Alina Bhatti 2025-11-12 14:41:22 +01:00
parent f780897670
commit 63d73ad605
4 changed files with 377 additions and 640 deletions

View File

@ -1,327 +0,0 @@
import pygame
import random
import sys
import os
# -------------------------------
# CountryCapital Memory Game
# -------------------------------
CARD_BACK_COLOR = (100, 100, 200)
CARD_FRONT_COLOR = (230, 230, 250)
MATCH_COLOR = (120, 200, 120)
TEXT_COLOR = (0, 0, 0)
BG_COLOR = (50, 50, 80)
SCREEN_WIDTH, SCREEN_HEIGHT = 800, 600
FPS = 30
# Design-Bild (für Kartenrückseite + optionalen Hintergrund)
DESIGN_FILE = "GlobalHintergrund.png"
class MemoryGame:
def __init__(self):
self.deck = []
self.pair_map = {}
self.matched = []
self.revealed = []
self.scores = [0, 0]
self.current_player = 0
self.font = None
self.card_rects = []
self.selected = []
self.found_pairs = 0
self.total_pairs = 0
self.running = True
self.awaiting_confirmation = False
self.confirmation_result = None
self.correct_answer_expected = None
self.state = "continent" # continent → americas → difficulty → pairs → game
self.buttons = []
self.selected_continents = []
self.level = None
self.pair_count = 6 # Default
# -------------------------------
# Card Loading
# -------------------------------
def load_cards(self, filename):
"""Loads pairs from a text file."""
if not os.path.exists(filename):
print(f"⚠️ File not found: {filename}")
return []
pairs = []
with open(filename, "r", encoding="utf-8") as f:
for line in f:
parts = line.strip().split()
if len(parts) >= 2:
pairs.append((parts[0], parts[1]))
return pairs
def prepare_deck(self):
"""Loads all relevant continent + difficulty files."""
self.deck = []
for continent in self.selected_continents:
base = continent
if self.level == "Easy":
self.deck += self.load_cards(base + "-major.txt")
elif self.level == "Normal":
self.deck += self.load_cards(base + "-major.txt")
self.deck += self.load_cards(base + "-Minor.txt")
elif self.level == "Hard":
self.deck += self.load_cards(base + "-major.txt")
self.deck += self.load_cards(base + "-Minor.txt")
self.deck += self.load_cards(base + "-Dependent.txt")
if not self.deck:
print("⚠️ No cards loaded, check text files.")
sys.exit()
random.shuffle(self.deck)
# Limit to selected pair count
self.deck = self.deck[:self.pair_count]
def setup_game(self):
self.cards = []
self.pair_map = {}
for country, capital in self.deck:
self.cards.append(country)
self.cards.append(capital)
self.pair_map[country] = capital
self.pair_map[capital] = country
random.shuffle(self.cards)
self.matched = [False] * len(self.cards)
self.revealed = [False] * len(self.cards)
self.total_pairs = len(self.deck)
self.card_rects = []
self.selected = []
cols = 4
rows = (len(self.cards) + cols - 1) // cols
margin = 10
card_width = (SCREEN_WIDTH - (cols + 1) * margin) // cols
card_height = (SCREEN_HEIGHT - (rows + 1) * margin - 100) // rows
y_offset = 80
for i, _ in enumerate(self.cards):
col = i % cols
row = i // cols
x = margin + col * (card_width + margin)
y = y_offset + margin + row * (card_height + margin)
rect = pygame.Rect(x, y, card_width, card_height)
self.card_rects.append(rect)
# -------------------------------
# Drawing Menus
# -------------------------------
def draw_menu(self, screen, title, options):
screen.fill(BG_COLOR)
title_text = self.font.render(title, True, (255, 255, 255))
screen.blit(title_text, (SCREEN_WIDTH // 2 - title_text.get_width() // 2, 100))
self.buttons = []
for i, option in enumerate(options):
rect = pygame.Rect(SCREEN_WIDTH // 2 - 150, 200 + i * 70, 300, 50)
pygame.draw.rect(screen, (100, 100, 250), rect)
pygame.draw.rect(screen, (255, 255, 255), rect, 2)
text = self.font.render(option, True, (255, 255, 255))
screen.blit(text, (rect.centerx - text.get_width() // 2, rect.centery - text.get_height() // 2))
self.buttons.append((rect, option))
pygame.display.flip()
def draw_game(self, screen):
screen.fill(BG_COLOR)
title = self.font.render(f"Player {self.current_player + 1}'s turn", True, (255, 255, 255))
screen.blit(title, (20, 20))
score_text = self.font.render(f"Scores: P1={self.scores[0]} P2={self.scores[1]}", True, (200, 200, 200))
screen.blit(score_text, (20, 50))
for i, rect in enumerate(self.card_rects):
if self.matched[i]:
color = MATCH_COLOR
elif self.revealed[i]:
color = CARD_FRONT_COLOR
else:
color = CARD_BACK_COLOR
pygame.draw.rect(screen, color, rect)
pygame.draw.rect(screen, (0, 0, 0), rect, 2)
if self.revealed[i] or self.matched[i]:
text = self.font.render(self.cards[i], True, TEXT_COLOR)
text_rect = text.get_rect(center=rect.center)
screen.blit(text, text_rect)
if self.awaiting_confirmation:
self.draw_confirmation_box(screen)
pygame.display.flip()
def draw_confirmation_box(self, screen): #y-axis Box
box_rect = pygame.Rect(SCREEN_WIDTH // 2 - 150, SCREEN_HEIGHT // 2 - 320, 300, 160)
pygame.draw.rect(screen, (250, 250, 250), box_rect)
pygame.draw.rect(screen, (0, 0, 0), box_rect, 3)
text = self.font.render("Is that correct?", True, (0, 0, 0))
screen.blit(text, (box_rect.centerx - text.get_width() // 2, box_rect.y + 20))
yes_rect = pygame.Rect(box_rect.x + 50, box_rect.y + 90, 80, 40)
no_rect = pygame.Rect(box_rect.x + 170, box_rect.y + 90, 80, 40)
pygame.draw.rect(screen, (0, 200, 0), yes_rect)
pygame.draw.rect(screen, (200, 0, 0), no_rect)
yes_text = self.font.render("Yes", True, (255, 255, 255))
no_text = self.font.render("No", True, (255, 255, 255))
screen.blit(yes_text, (yes_rect.centerx - yes_text.get_width() // 2, yes_rect.centery - yes_text.get_height() // 2))
screen.blit(no_text, (no_rect.centerx - no_text.get_width() // 2, no_rect.centery - no_text.get_height() // 2))
self.yes_rect, self.no_rect = yes_rect, no_rect
# -------------------------------
# Handling Clicks
# -------------------------------
def handle_click(self, pos):
if self.state in ["continent", "americas", "difficulty", "pairs"]:
for rect, option in self.buttons:
if rect.collidepoint(pos):
if self.state == "continent":
if option == "Americas":
self.state = "americas"
elif option == "All Continents":
self.selected_continents = ["Europe", "Asia", "Africa", "Oceania", "North-America", "South-America"]
self.state = "difficulty"
else:
self.selected_continents = [option]
self.state = "difficulty"
elif self.state == "americas":
if option == "North-America":
self.selected_continents = ["North-America"]
elif option == "South-America":
self.selected_continents = ["South-America"]
elif option == "Americas":
self.selected_continents = ["North-America", "South-America"]
self.state = "difficulty"
elif self.state == "difficulty":
self.level = option
self.state = "pairs"
elif self.state == "pairs":
self.pair_count = int(option)
self.prepare_deck()
self.setup_game()
self.state = "game"
return
elif self.state == "game":
if self.awaiting_confirmation:
if self.yes_rect.collidepoint(pos):
self.confirmation_result = "yes"
elif self.no_rect.collidepoint(pos):
self.confirmation_result = "no"
return
for i, rect in enumerate(self.card_rects):
if rect.collidepoint(pos) and not self.revealed[i] and not self.matched[i]:
self.revealed[i] = True
self.selected.append(i)
return
# -------------------------------
# Game Logic Most important
# -------------------------------
def check_selected(self):
if self.state != "game":
return
# Wenn zwei Karten ausgewählt wurden → prüfen
if len(self.selected) == 2 and not self.awaiting_confirmation:
a, b = self.selected
is_match = self.pair_map.get(self.cards[a]) == self.cards[b]
self.correct_answer_expected = "yes" if is_match else "no"
self.awaiting_confirmation = True
# Wenn der Spieler im "Is that correct?"-Dialog geantwortet hat
elif self.awaiting_confirmation and self.confirmation_result:
a, b = self.selected
expected = self.correct_answer_expected
player_correct = self.confirmation_result == expected
if player_correct:
# Spieler hat korrekt geantwortet
if expected == "yes":
# Richtiges Paar bestätigt
self.matched[a] = self.matched[b] = True
self.scores[self.current_player] += 1
self.found_pairs += 1
else:
# "No" richtig bestätigt → kein Paar
self.revealed[a] = self.revealed[b] = False
else:
# Spieler hat sich vertan → Karten umdrehen & Punkt abziehen
self.scores[self.current_player] -= 1
self.revealed[a] = self.revealed[b] = False
# Reset für nächsten Zug
self.awaiting_confirmation = False
self.confirmation_result = None
self.selected = []
self.current_player = 1 - self.current_player
# -------------------------------
# Main Game Loop
# -------------------------------
def run(self):
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("CountryCapital Memory Game")
clock = pygame.time.Clock()
self.font = pygame.font.SysFont(None, 32)
while self.running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
self.handle_click(event.pos)
if self.state == "continent":
self.draw_menu(screen, "Select Continent", ["Europe", "Americas", "Asia", "Africa", "Oceania", "All Continents"])
elif self.state == "americas":
self.draw_menu(screen, "Select Region", ["North-America", "South-America", "Americas"])
elif self.state == "difficulty":
self.draw_menu(screen, "Select Difficulty", ["Easy", "Normal", "Hard"])
elif self.state == "pairs":
self.draw_menu(screen, "Select Number of Pairs", ["4", "6", "8", "10", "12"])
elif self.state == "game":
self.draw_game(screen)
self.check_selected()
if self.found_pairs == self.total_pairs:
self.display_winner(screen)
pygame.display.flip()
pygame.time.wait(4000)
self.running = False
clock.tick(FPS)
pygame.quit()
sys.exit()
# -------------------------------
# Winner Display
# -------------------------------
def display_winner(self, screen):
if self.scores[0] > self.scores[1]:
text = "🏆 Player 1 Wins!"
elif self.scores[1] > self.scores[0]:
text = "🏆 Player 2 Wins!"
else:
text = "🤝 Draw!"
win_text = self.font.render(text, True, (255, 255, 0))
rect = win_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
screen.blit(win_text, rect)
# -------------------------------
# Run the Game
# -------------------------------
if __name__ == "__main__":
game = MemoryGame()
game.run()

34
app.py Normal file
View File

@ -0,0 +1,34 @@
from flask import Flask, request, render_template
import subprocess
import sys
import os
app = Flask(__name__)
# Option A: Direkt die Python-Funktion ausführen (wenn dein Spiel in demselben Prozess laufen darf)
# from global_match_memory import run_memory
@app.get("/")
def home():
return render_template("index.html")
@app.get("/start")
def start_game():
players = request.args.get("players", "1")
# --- Option A: direkt aufrufen ---
# run_memory(int(players))
# return "started"
# --- Option B: separates Fenster/Prozess (robuster) ---
# Startet global_match_memory.py als eigenen Prozess mit Argument "players"
py = sys.executable # aktueller Python-Interpreter
script_path = os.path.join(os.path.dirname(__file__), "global_match_memory.py")
subprocess.Popen([py, script_path, players])
return "started"
if __name__ == "__main__":
# Auf Mac/Windows lokal erreichbar: http://localhost:5000
app.run(host="127.0.0.1", port=5000, debug=True)

View File

@ -1,334 +1,345 @@
import pygame import pygame
import sys
import random import random
import sys
import os import os
from typing import List, Tuple
# ---------------------------------------------------------- # -------------------------------
# Design / Layout # CountryCapital Memory Game
# ---------------------------------------------------------- # -------------------------------
WINDOW_W, WINDOW_H = 900, 900
BG_COLOR = (10, 58, 94) # Global-Match Blau
HUD_BAR_H = 88
PADDING = 28
GRID_COLS, GRID_ROWS = 4, 3 # 12 Karten (6 Paare)
GAP = 18
CARD_RADIUS = 20
CARD_BORDER = (220, 226, 235)
CARD_FACE = (255, 255, 255)
CARD_TEXT = (22, 44, 66)
BADGE_BG = (18, 122, 138)
BADGE_TEXT = (255, 255, 255)
HIGHLIGHT = (255, 224, 128)
LOGO_FILE = "LogoSpiel.png" # <— Dein Logo (Rückseite) CARD_BACK_COLOR = (100, 100, 200)
CARD_FRONT_COLOR = (230, 230, 250)
MATCH_COLOR = (120, 200, 120)
TEXT_COLOR = (0, 0, 0)
BG_COLOR = (50, 50, 80)
SCREEN_WIDTH, SCREEN_HEIGHT = 800, 600
FPS = 30
# Design-Bild (für Kartenrückseite + optionalen Hintergrund)
DESIGN_FILE = "GlobalHintergrund.png"
MISMATCH_DELAY_MS = 900
SINGLEPLAYER_SECONDS = 90
FPS = 60
# ----------------------------------------------------------
# Daten (Deutsch)
# ----------------------------------------------------------
DATA = {
"Europa": [
("Deutschland", "Berlin"), ("Frankreich", "Paris"), ("Italien", "Rom"),
("Spanien", "Madrid"), ("Portugal", "Lissabon"), ("Niederlande", "Amsterdam"),
("Belgien", "Brüssel"), ("Österreich", "Wien"), ("Schweiz", "Bern"),
("Polen", "Warschau"), ("Tschechien", "Prag"), ("Ungarn", "Budapest"),
("Dänemark", "Kopenhagen"), ("Schweden", "Stockholm"), ("Norwegen", "Oslo")
],
"Amerika": [
("USA", "Washington, D.C."), ("Kanada", "Ottawa"), ("Mexiko", "Mexiko-Stadt"),
("Brasilien", "Brasília"), ("Argentinien", "Buenos Aires"), ("Chile", "Santiago"),
("Peru", "Lima"), ("Kolumbien", "Bogotá"), ("Venezuela", "Caracas"),
("Uruguay", "Montevideo"), ("Bolivien", "Sucre"), ("Ecuador", "Quito")
],
"Asien": [
("China", "Peking"), ("Japan", "Tokio"), ("Südkorea", "Seoul"),
("Indien", "Neu-Delhi"), ("Pakistan", "Islamabad"),
("Bangladesch", "Dhaka"), ("Sri Lanka", "Sri Jayewardenepura Kotte"),
("Nepal", "Kathmandu"), ("Saudi-Arabien", "Riad"),
("VAE", "Abu Dhabi"), ("Türkei", "Ankara"), ("Indonesien", "Jakarta"),
("Malaysia", "Kuala Lumpur"), ("Thailand", "Bangkok"), ("Vietnam", "Hanoi")
],
}
# ---------------------------------------------------------- class MemoryGame:
# Helpers def __init__(self):
# ---------------------------------------------------------- self.deck = []
def load_logo_scaled(size: Tuple[int, int]) -> pygame.Surface: self.pair_map = {}
"""Lädt LogoSpiel.png und skaliert mit 10% Rand. Fallback: dunkles GM-Pattern.""" self.matched = []
w, h = size self.revealed = []
surf = pygame.Surface((w, h), pygame.SRCALPHA) self.scores = [0, 0]
# weiße Karte self.current_player = 0
pygame.draw.rect(surf, CARD_FACE, (0, 0, w, h), border_radius=CARD_RADIUS) self.font = None
pygame.draw.rect(surf, CARD_BORDER, (0, 0, w, h), width=2, border_radius=CARD_RADIUS) self.card_rects = []
self.selected = []
self.found_pairs = 0
self.total_pairs = 0
self.running = True
self.awaiting_confirmation = False
self.confirmation_result = None
self.correct_answer_expected = None
self.state = "continent" # continent → americas → difficulty → pairs → game
self.buttons = []
self.selected_continents = []
self.level = None
self.pair_count = 6 # Default
inner_pad = int(min(w, h) * 0.12) # -------------------------------
logo_rect = pygame.Rect(inner_pad, inner_pad, w - 2*inner_pad, h - 2*inner_pad) # Card Loading
# -------------------------------
def load_cards(self, filename):
"""Loads pairs from a text file."""
if not os.path.exists(filename):
print(f"⚠️ File not found: {filename}")
return []
if os.path.exists(LOGO_FILE): pairs = []
try: with open(filename, "r", encoding="utf-8") as f:
img = pygame.image.load(LOGO_FILE).convert_alpha() for line in f:
img = scale_to_fit(img, logo_rect.size) parts = line.strip().split()
surf.blit(img, ( if len(parts) >= 2:
logo_rect.centerx - img.get_width() // 2, pairs.append((parts[0], parts[1]))
logo_rect.centery - img.get_height() // 2 return pairs
))
return surf
except Exception:
pass
# Fallback: Text "GLOBAL MATCH" def prepare_deck(self):
font = pygame.font.SysFont(None, int(h * 0.16), bold=True) """Loads all relevant continent + difficulty files."""
t1 = font.render("GLOBAL", True, (10, 80, 110)) self.deck = []
t2 = font.render("MATCH", True, (240, 180, 60)) for continent in self.selected_continents:
surf.blit(t1, (w//2 - t1.get_width()//2, h//2 - t1.get_height())) base = continent
surf.blit(t2, (w//2 - t2.get_width()//2, h//2 + 4)) if self.level == "Easy":
return surf self.deck += self.load_cards(base + "-major.txt")
elif self.level == "Normal":
self.deck += self.load_cards(base + "-major.txt")
self.deck += self.load_cards(base + "-Minor.txt")
elif self.level == "Hard":
self.deck += self.load_cards(base + "-major.txt")
self.deck += self.load_cards(base + "-Minor.txt")
self.deck += self.load_cards(base + "-Dependent.txt")
def scale_to_fit(img: pygame.Surface, target_size: Tuple[int, int]) -> pygame.Surface: if not self.deck:
tw, th = target_size print("⚠️ No cards loaded, check text files.")
iw, ih = img.get_width(), img.get_height() sys.exit()
scale = min(tw / iw, th / ih)
return pygame.transform.smoothscale(img, (int(iw * scale), int(ih * scale)))
def wrap_text(text: str, font: pygame.font.Font, max_w: int) -> List[str]: random.shuffle(self.deck)
words = text.split() # Limit to selected pair count
lines, line = [], "" self.deck = self.deck[:self.pair_count]
for w in words:
t = (line + " " + w).strip()
if font.size(t)[0] <= max_w:
line = t
else:
if line:
lines.append(line)
line = w
if line:
lines.append(line)
return lines
def pick_payloads(level: str, n_pairs=6) -> List[dict]: def setup_game(self):
pool = DATA[level][:] if level in DATA else DATA["Europa"][:] self.cards = []
random.shuffle(pool) self.pair_map = {}
chosen = pool[:n_pairs] for country, capital in self.deck:
payloads = [] self.cards.append(country)
pid = 0 self.cards.append(capital)
for land, cap in chosen: self.pair_map[country] = capital
payloads.append({"pair": pid, "label": land, "kind": "country"}) self.pair_map[capital] = country
payloads.append({"pair": pid, "label": cap, "kind": "capital"}) random.shuffle(self.cards)
pid += 1 self.matched = [False] * len(self.cards)
random.shuffle(payloads) self.revealed = [False] * len(self.cards)
return payloads self.total_pairs = len(self.deck)
self.card_rects = []
self.selected = []
# ---------------------------------------------------------- cols = 4
# Card rows = (len(self.cards) + cols - 1) // cols
# ---------------------------------------------------------- margin = 10
class Card: card_width = (SCREEN_WIDTH - (cols + 1) * margin) // cols
def __init__(self, rect: pygame.Rect, payload: dict, fonts, back_img: pygame.Surface): card_height = (SCREEN_HEIGHT - (rows + 1) * margin - 100) // rows
self.rect = rect y_offset = 80
self.payload = payload
self.font, self.small = fonts
self.back = pygame.transform.smoothscale(back_img, (rect.w, rect.h))
self.front = pygame.Surface((rect.w, rect.h), pygame.SRCALPHA)
self.is_revealed = False
self.is_matched = False
self._render_front()
def _render_front(self): for i, _ in enumerate(self.cards):
w, h = self.rect.w, self.rect.h col = i % cols
# weiße Karte + Rand row = i // cols
pygame.draw.rect(self.front, CARD_FACE, (0, 0, w, h), border_radius=CARD_RADIUS) x = margin + col * (card_width + margin)
pygame.draw.rect(self.front, CARD_BORDER, (0, 0, w, h), width=2, border_radius=CARD_RADIUS) y = y_offset + margin + row * (card_height + margin)
rect = pygame.Rect(x, y, card_width, card_height)
self.card_rects.append(rect)
# Badge # -------------------------------
badge = "Land" if self.payload["kind"] == "country" else "Hauptstadt" # Drawing Menus
bsurf = self.small.render(badge, True, BADGE_TEXT) # -------------------------------
bw, bh = bsurf.get_size() def draw_menu(self, screen, title, options):
badge_bg = pygame.Surface((bw + 18, bh + 8), pygame.SRCALPHA)
pygame.draw.rect(badge_bg, BADGE_BG, badge_bg.get_rect(), border_radius=12)
badge_bg.blit(bsurf, (9, 4))
self.front.blit(badge_bg, (w - badge_bg.get_width() - 12, 12))
# Text
lines = wrap_text(self.payload["label"], self.font, w - 28)
total_h = len(lines) * self.font.get_height()
y = h//2 - total_h//2
for line in lines:
ts = self.font.render(line, True, CARD_TEXT)
self.front.blit(ts, (w//2 - ts.get_width()//2, y))
y += self.font.get_height()
def draw(self, screen: pygame.Surface):
screen.blit(self.front if (self.is_revealed or self.is_matched) else self.back,
(self.rect.x, self.rect.y))
def handle_click(self, pos) -> bool:
if self.rect.collidepoint(pos) and not self.is_matched and not self.is_revealed:
self.is_revealed = True
return True
return False
# ----------------------------------------------------------
# Main Game
# ----------------------------------------------------------
def run_memory(level: str = "Europa", mode: str = "single"):
"""
level: 'Europa' | 'Amerika' | 'Asien'
mode : 'single' (Zeit) | 'two' (Punkte, abwechselnd)
"""
pygame.init()
screen = pygame.display.set_mode((WINDOW_W, WINDOW_H))
pygame.display.set_caption(f"Global Match {level} ({'1 Spieler' if mode=='single' else '2 Spieler'})")
clock = pygame.time.Clock()
ui_font = pygame.font.SysFont(None, 32, bold=True)
big_font = pygame.font.SysFont(None, 50, bold=True)
card_font = pygame.font.SysFont(None, 28, bold=True)
small_font = pygame.font.SysFont(None, 20, bold=True)
# Grid berechnen
grid_w = WINDOW_W - 2 * PADDING
grid_h = WINDOW_H - HUD_BAR_H - 2 * PADDING
cell_w = (grid_w - (GRID_COLS - 1) * GAP) // GRID_COLS
cell_h = (grid_h - (GRID_ROWS - 1) * GAP) // GRID_ROWS
card_size = min(cell_w, cell_h)
start_x = PADDING + (grid_w - (card_size * GRID_COLS + GAP * (GRID_COLS - 1))) // 2
start_y = HUD_BAR_H + PADDING + (grid_h - (card_size * GRID_ROWS + GAP * (GRID_ROWS - 1))) // 2
# Karten erzeugen
back_img = load_logo_scaled((card_size, card_size))
payloads = pick_payloads(level, n_pairs=6)
cards: List[Card] = []
k = 0
for r in range(GRID_ROWS):
for c in range(GRID_COLS):
if k >= len(payloads):
continue
rect = pygame.Rect(start_x + c * (card_size + GAP),
start_y + r * (card_size + GAP),
card_size, card_size)
cards.append(Card(rect, payloads[k], (card_font, small_font), back_img))
k += 1
# Spielstatus
revealed: List[Card] = []
lock_until = 0
total_matches = 0
need_matches = len(payloads) // 2
p_turn = 1
score = {1: 0, 2: 0}
time_left = SINGLEPLAYER_SECONDS * 1000 if mode == "single" else None
end_text = None
# Loop
while True:
dt = clock.tick(FPS)
now = pygame.time.get_ticks()
# Events
for e in pygame.event.get():
if e.type == pygame.QUIT:
pygame.quit()
sys.exit()
if e.type == pygame.KEYDOWN and end_text:
if e.key in (pygame.K_RETURN, pygame.K_SPACE):
pygame.quit()
return
if e.type == pygame.MOUSEBUTTONDOWN and e.button == 1 and not end_text:
if now < lock_until:
continue
for card in cards:
if card.handle_click(e.pos):
revealed.append(card)
if len(revealed) == 2:
a, b = revealed
# Match (gleiches Paar, aber unterschiedliche Art)
if a.payload["pair"] == b.payload["pair"] and a.payload["kind"] != b.payload["kind"]:
a.is_matched = b.is_matched = True
revealed.clear()
total_matches += 1
if mode == "two":
score[p_turn] += 1
if total_matches == need_matches:
if mode == "single":
end_text = "Geschafft! Alle 6 Paare."
else:
if score[1] > score[2]:
end_text = f"Spielende Spieler 1 gewinnt ({score[1]}:{score[2]})"
elif score[2] > score[1]:
end_text = f"Spielende Spieler 2 gewinnt ({score[2]}:{score[1]})"
else:
end_text = f"Unentschieden ({score[1]}:{score[2]})"
else:
lock_until = now + MISMATCH_DELAY_MS
elif len(revealed) > 2:
# Sicherheitsreset nur die letzten 2 behalten
for old in revealed[:-2]:
old.is_revealed = False
revealed = revealed[-2:]
# Timer (Singleplayer)
if not end_text and mode == "single" and time_left is not None:
time_left -= dt
if time_left <= 0:
time_left = 0
end_text = "Zeit abgelaufen!"
# Mismatch zurückdrehen + Spielerwechsel
if not end_text and len(revealed) == 2 and lock_until and now >= lock_until:
a, b = revealed
a.is_revealed = False
b.is_revealed = False
revealed.clear()
lock_until = 0
if mode == "two":
p_turn = 2 if p_turn == 1 else 1
# ----------------- Render -----------------
screen.fill(BG_COLOR) screen.fill(BG_COLOR)
title_text = self.font.render(title, True, (255, 255, 255))
screen.blit(title_text, (SCREEN_WIDTH // 2 - title_text.get_width() // 2, 100))
self.buttons = []
# HUD for i, option in enumerate(options):
pygame.draw.rect(screen, (7, 42, 70), (0, 0, WINDOW_W, HUD_BAR_H)) rect = pygame.Rect(SCREEN_WIDTH // 2 - 150, 200 + i * 70, 300, 50)
title = ui_font.render(f"Global Match {level}", True, (255, 255, 255)) pygame.draw.rect(screen, (100, 100, 250), rect)
screen.blit(title, (PADDING, HUD_BAR_H//2 - title.get_height()//2)) pygame.draw.rect(screen, (255, 255, 255), rect, 2)
text = self.font.render(option, True, (255, 255, 255))
if mode == "single": screen.blit(text, (rect.centerx - text.get_width() // 2, rect.centery - text.get_height() // 2))
tsec = (time_left // 1000) if time_left is not None else 0 self.buttons.append((rect, option))
timer = ui_font.render(f"Zeit: {tsec}s", True, HIGHLIGHT)
screen.blit(timer, (WINDOW_W - PADDING - timer.get_width(), HUD_BAR_H//2 - timer.get_height()//2))
else:
s = ui_font.render(f"P1: {score[1]} P2: {score[2]} Zug: P{p_turn}", True, HIGHLIGHT)
screen.blit(s, (WINDOW_W - PADDING - s.get_width(), HUD_BAR_H//2 - s.get_height()//2))
# Karten
for card in cards:
card.draw(screen)
# Overlay / Ende
if end_text:
overlay = pygame.Surface((WINDOW_W, WINDOW_H), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 140))
screen.blit(overlay, (0, 0))
msg = big_font.render(end_text, True, (255, 255, 255))
sub = ui_font.render("ENTER/SPACE zum Beenden", True, (240, 240, 240))
screen.blit(msg, (WINDOW_W//2 - msg.get_width()//2, WINDOW_H//2 - 30))
screen.blit(sub, (WINDOW_W//2 - sub.get_width()//2, WINDOW_H//2 + 20))
pygame.display.flip() pygame.display.flip()
# ---------------------------------------------------------- def draw_game(self, screen):
# Direktstart (zu Testzwecken) screen.fill(BG_COLOR)
# ---------------------------------------------------------- title = self.font.render(f"Player {self.current_player + 1}'s turn", True, (255, 255, 255))
screen.blit(title, (20, 20))
score_text = self.font.render(f"Scores: P1={self.scores[0]} P2={self.scores[1]}", True, (200, 200, 200))
screen.blit(score_text, (20, 50))
for i, rect in enumerate(self.card_rects):
if self.matched[i]:
color = MATCH_COLOR
elif self.revealed[i]:
color = CARD_FRONT_COLOR
else:
color = CARD_BACK_COLOR
pygame.draw.rect(screen, color, rect)
pygame.draw.rect(screen, (0, 0, 0), rect, 2)
if self.revealed[i] or self.matched[i]:
text = self.font.render(self.cards[i], True, TEXT_COLOR)
text_rect = text.get_rect(center=rect.center)
screen.blit(text, text_rect)
if self.awaiting_confirmation:
self.draw_confirmation_box(screen)
pygame.display.flip()
def draw_confirmation_box(self, screen): #y-axis Box
box_rect = pygame.Rect(SCREEN_WIDTH // 2 - 150, SCREEN_HEIGHT // 2 - 320, 300, 160)
pygame.draw.rect(screen, (250, 250, 250), box_rect)
pygame.draw.rect(screen, (0, 0, 0), box_rect, 3)
text = self.font.render("Is that correct?", True, (0, 0, 0))
screen.blit(text, (box_rect.centerx - text.get_width() // 2, box_rect.y + 20))
yes_rect = pygame.Rect(box_rect.x + 50, box_rect.y + 90, 80, 40)
no_rect = pygame.Rect(box_rect.x + 170, box_rect.y + 90, 80, 40)
pygame.draw.rect(screen, (0, 200, 0), yes_rect)
pygame.draw.rect(screen, (200, 0, 0), no_rect)
yes_text = self.font.render("Yes", True, (255, 255, 255))
no_text = self.font.render("No", True, (255, 255, 255))
screen.blit(yes_text, (yes_rect.centerx - yes_text.get_width() // 2, yes_rect.centery - yes_text.get_height() // 2))
screen.blit(no_text, (no_rect.centerx - no_text.get_width() // 2, no_rect.centery - no_text.get_height() // 2))
self.yes_rect, self.no_rect = yes_rect, no_rect
# -------------------------------
# Handling Clicks
# -------------------------------
def handle_click(self, pos):
if self.state in ["continent", "americas", "difficulty", "pairs"]:
for rect, option in self.buttons:
if rect.collidepoint(pos):
if self.state == "continent":
if option == "Americas":
self.state = "americas"
elif option == "All Continents":
self.selected_continents = ["Europe", "Asia", "Africa", "Oceania", "North-America", "South-America"]
self.state = "difficulty"
else:
self.selected_continents = [option]
self.state = "difficulty"
elif self.state == "americas":
if option == "North-America":
self.selected_continents = ["North-America"]
elif option == "South-America":
self.selected_continents = ["South-America"]
elif option == "Americas":
self.selected_continents = ["North-America", "South-America"]
self.state = "difficulty"
elif self.state == "difficulty":
self.level = option
self.state = "pairs"
elif self.state == "pairs":
self.pair_count = int(option)
self.prepare_deck()
self.setup_game()
self.state = "game"
return
elif self.state == "game":
if self.awaiting_confirmation:
if self.yes_rect.collidepoint(pos):
self.confirmation_result = "yes"
elif self.no_rect.collidepoint(pos):
self.confirmation_result = "no"
return
for i, rect in enumerate(self.card_rects):
if rect.collidepoint(pos) and not self.revealed[i] and not self.matched[i]:
self.revealed[i] = True
self.selected.append(i)
return
# -------------------------------
# Game Logic Most important
# -------------------------------
def check_selected(self):
if self.state != "game":
return
# Wenn zwei Karten ausgewählt wurden → prüfen
if len(self.selected) == 2 and not self.awaiting_confirmation:
a, b = self.selected
is_match = self.pair_map.get(self.cards[a]) == self.cards[b]
self.correct_answer_expected = "yes" if is_match else "no"
self.awaiting_confirmation = True
# Wenn der Spieler im "Is that correct?"-Dialog geantwortet hat
elif self.awaiting_confirmation and self.confirmation_result:
a, b = self.selected
expected = self.correct_answer_expected
player_correct = self.confirmation_result == expected
if player_correct:
# Spieler hat korrekt geantwortet
if expected == "yes":
# Richtiges Paar bestätigt
self.matched[a] = self.matched[b] = True
self.scores[self.current_player] += 1
self.found_pairs += 1
else:
# "No" richtig bestätigt → kein Paar
self.revealed[a] = self.revealed[b] = False
else:
# Spieler hat sich vertan → Karten umdrehen & Punkt abziehen
self.scores[self.current_player] -= 1
self.revealed[a] = self.revealed[b] = False
# Reset für nächsten Zug
self.awaiting_confirmation = False
self.confirmation_result = None
self.selected = []
self.current_player = 1 - self.current_player
# -------------------------------
# Main Game Loop
# -------------------------------
def run(self):
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("CountryCapital Memory Game")
clock = pygame.time.Clock()
self.font = pygame.font.SysFont(None, 32)
while self.running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
self.handle_click(event.pos)
if self.state == "continent":
self.draw_menu(screen, "Select Continent", ["Europe", "Americas", "Asia", "Africa", "Oceania", "All Continents"])
elif self.state == "americas":
self.draw_menu(screen, "Select Region", ["North-America", "South-America", "Americas"])
elif self.state == "difficulty":
self.draw_menu(screen, "Select Difficulty", ["Easy", "Normal", "Hard"])
elif self.state == "pairs":
self.draw_menu(screen, "Select Number of Pairs", ["4", "6", "8", "10", "12"])
elif self.state == "game":
self.draw_game(screen)
self.check_selected()
if self.found_pairs == self.total_pairs:
self.display_winner(screen)
pygame.display.flip()
pygame.time.wait(4000)
self.running = False
clock.tick(FPS)
pygame.quit()
sys.exit()
# -------------------------------
# Winner Display
# -------------------------------
def display_winner(self, screen):
if self.scores[0] > self.scores[1]:
text = "🏆 Player 1 Wins!"
elif self.scores[1] > self.scores[0]:
text = "🏆 Player 2 Wins!"
else:
text = "🤝 Draw!"
win_text = self.font.render(text, True, (255, 255, 0))
rect = win_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
screen.blit(win_text, rect)
def run_memory(players: int = 1):
pygame.init()
screen = pygame.display.set_mode((900, 600))
pygame.display.set_caption(f"Global Match {players} Spieler")
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((10, 42, 53))
# ... dein Memory-Rendering / Logic ...
pygame.display.flip()
clock.tick(60)
pygame.quit()
# -------------------------------
# Run the Game
# -------------------------------
if __name__ == "__main__": if __name__ == "__main__":
lvl = "Europa" game = MemoryGame()
md = "single" game.run()
if len(sys.argv) >= 2:
lvl = sys.argv[1]
if len(sys.argv) >= 3:
md = sys.argv[2]
run_memory(level=lvl, mode=md)

View File

@ -1,4 +1,4 @@
from global_match_memory import run_memory
<!DOCTYPE html> <!DOCTYPE html>
<html lang="de"> <html lang="de">
@ -134,7 +134,7 @@ from global_match_memory import run_memory
<div class="brand"> <div class="brand">
<!-- Logo als Text du kannst hier optional ein PNG/SVG einfügen --> <!-- Logo als Text du kannst hier optional ein PNG/SVG einfügen -->
<div class="logo" aria-hidden="true"> <div class="logo" aria-hidden="true">
<div class="logo-top">GLO <div class="logo-top">GL
<svg width="52" height="52" viewBox="0 0 100 100" style="vertical-align:middle"> <svg width="52" height="52" viewBox="0 0 100 100" style="vertical-align:middle">
<defs><radialGradient id="g" cx="50%" cy="35%" r="60%"><stop offset="0%" stop-color="#9ee7ef"/><stop offset="100%" stop-color="#127a8a"/></radialGradient></defs> <defs><radialGradient id="g" cx="50%" cy="35%" r="60%"><stop offset="0%" stop-color="#9ee7ef"/><stop offset="100%" stop-color="#127a8a"/></radialGradient></defs>
<circle cx="50" cy="50" r="46" fill="url(#g)" stroke="#08303b" stroke-width="6"/> <circle cx="50" cy="50" r="46" fill="url(#g)" stroke="#08303b" stroke-width="6"/>
@ -181,3 +181,22 @@ from global_match_memory import run_memory
</script> </script>
</body> </body>
</html> </html>
<!-- ... dein kompletter <head> & <body> wie bisher ... -->
<script>
// Jahr im Footer
document.getElementById('y').textContent = new Date().getFullYear();
// Start-Button → Backend ruft Pygame
document.getElementById('startBtn').addEventListener('click', async () => {
const players = document.querySelector('input[name="players"]:checked').value;
try {
const res = await fetch(`/start?players=${players}`);
// Optional: kleine Info für Nutzer
alert('Spiel wird gestartet! Schau nach dem Pygame-Fenster.');
} catch (e) {
alert('Konnte das Spiel nicht starten. Läuft der Server?');
console.error(e);
}
});
</script>