global_match_memory/combined_timer_design.py
2025-11-12 16:11:33 +01:00

401 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import pygame
import random
import sys
import os
import time
# -------------------------------
# Global Match CountryCapital Memory Game
# -------------------------------
# --- Colors & Layout ---
CARD_FRONT_COLOR = (245, 246, 248)
CARD_BACK_COLOR = (100, 100, 200)
MATCH_COLOR = (160, 220, 160)
TEXT_COLOR = (10, 30, 40)
CAPITAL_COLOR = (0, 60, 180)
BG_COLOR = (10, 42, 83)
BUTTON_FILL = (18, 122, 138)
BUTTON_BORDER = (255, 255, 255)
FPS = 30
SCREEN_WIDTH, SCREEN_HEIGHT = 900, 600
# --- Background / Logo ---
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
BACKGROUND_FILE = os.path.join(BASE_DIR, "GlobalHintergrund.png")
# -------------------------------
# Helper: Card Back (Logo)
# -------------------------------
def build_card_back(image_path, size):
"""Load and scale a logo image to fill card backs."""
w, h = size
surf = pygame.Surface((w, h), pygame.SRCALPHA).convert_alpha()
if os.path.exists(image_path):
try:
img = pygame.image.load(image_path).convert_alpha()
img = pygame.transform.smoothscale(img, (w, h))
surf.blit(img, (0, 0))
except pygame.error as e:
print(f"⚠️ Error loading {image_path}: {e}")
surf.fill((127, 127, 200))
else:
print(f"⚠️ Image not found: {image_path}")
surf.fill((127, 127, 200))
return surf
# -------------------------------
# Memory Game Class
# -------------------------------
class MemoryGame:
def __init__(self):
# Game Data
self.deck = []
self.pair_map = {}
self.matched = []
self.revealed = []
self.cards = []
self.card_rects = []
self.selected = []
self.scores = [0, 0]
self.current_player = 0
self.found_pairs = 0
self.total_pairs = 0
# UI and States
self.font = None
self.small_font = None
self.buttons = []
self.running = True
self.state = "mode"
self.selected_continents = []
self.level = None
self.pair_count = 6
self.player_mode = 2
# Confirmation phase
self.awaiting_confirmation = False
self.confirmation_result = None
self.correct_answer_expected = None
self.confirmation_start_time = None
self.confirmation_time_limit = 5
# Visuals
self.card_back = None
# -------------------------------
# File Loading
# -------------------------------
def load_cards(self, filename):
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):
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 your text files.")
sys.exit()
random.shuffle(self.deck)
self.deck = self.deck[:self.pair_count]
# -------------------------------
# Setup & Layout
# -------------------------------
def setup_game(self):
self.cards = []
self.pair_map = {}
for country, capital in self.deck:
self.cards.append({"text": country, "type": "country"})
self.cards.append({"text": capital, "type": "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.selected = []
self.found_pairs = 0
self.current_player = 0
self.scores = [0, 0]
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
self.card_back = build_card_back(BACKGROUND_FILE, (card_width, card_height))
y_offset = 80
self.card_rects = []
for i in range(len(self.cards)):
col = i % cols
row = i // cols
x = margin + col * (card_width + margin)
y = y_offset + margin + row * (card_height + margin)
self.card_rects.append(pygame.Rect(x, y, card_width, card_height))
# -------------------------------
# Drawing Functions
# -------------------------------
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, BUTTON_FILL, rect, border_radius=10)
pygame.draw.rect(screen, BUTTON_BORDER, rect, 2, border_radius=10)
text = self.font.render(option, True, (255, 255, 255))
screen.blit(text, text.get_rect(center=rect.center))
self.buttons.append((rect, option))
pygame.display.flip()
def draw_game(self, screen):
screen.fill(BG_COLOR)
if self.player_mode == 2:
title = self.font.render(f"Player {self.current_player + 1}'s turn", True, (255, 255, 255))
score_text = self.font.render(f"Scores: P1={self.scores[0]} P2={self.scores[1]}", True, (220, 230, 235))
else:
title = self.font.render("Single Player Mode", True, (255, 255, 255))
score_text = self.font.render(f"Score: {self.scores[0]}", True, (220, 230, 235))
screen.blit(title, (20, 20))
screen.blit(score_text, (20, 50))
for i, rect in enumerate(self.card_rects):
if self.matched[i]:
pygame.draw.rect(screen, MATCH_COLOR, rect)
elif self.revealed[i]:
pygame.draw.rect(screen, CARD_FRONT_COLOR, rect)
else:
screen.blit(self.card_back, rect.topleft)
pygame.draw.rect(screen, (0, 0, 0), rect, 2)
if self.revealed[i] or self.matched[i]:
card = self.cards[i]
text_color = CAPITAL_COLOR if card["type"] == "capital" else TEXT_COLOR
text = self.font.render(card["text"], True, text_color)
screen.blit(text, text.get_rect(center=(rect.centerx, rect.centery - 10)))
label = self.small_font.render(
"(Capital)" if card["type"] == "capital" else "(Country)", True, (80, 80, 80)
)
screen.blit(label, label.get_rect(center=(rect.centerx, rect.centery + 20)))
if self.awaiting_confirmation:
self.draw_confirmation_box(screen)
pygame.display.flip()
def draw_confirmation_box(self, screen):
box = pygame.Rect(SCREEN_WIDTH // 2 - 150, SCREEN_HEIGHT // 2 - 320, 300, 160)
pygame.draw.rect(screen, (250, 250, 250), box)
pygame.draw.rect(screen, (0, 0, 0), box, 3)
text = self.font.render("Is that correct?", True, (0, 0, 0))
screen.blit(text, (box.centerx - text.get_width() // 2, box.y + 20))
elapsed = time.time() - self.confirmation_start_time
remaining = max(0, self.confirmation_time_limit - elapsed)
timer = self.small_font.render(f"{remaining:.1f}s left", True, (150, 0, 0))
screen.blit(timer, (box.centerx - timer.get_width() // 2, box.y + 60))
self.yes_rect = pygame.Rect(box.x + 50, box.y + 90, 80, 40)
self.no_rect = pygame.Rect(box.x + 170, box.y + 90, 80, 40)
pygame.draw.rect(screen, (0, 200, 0), self.yes_rect)
pygame.draw.rect(screen, (200, 0, 0), self.no_rect)
screen.blit(self.font.render("Yes", True, (255, 255, 255)), self.yes_rect.move(20, 5))
screen.blit(self.font.render("No", True, (255, 255, 255)), self.no_rect.move(25, 5))
# -------------------------------
# Interaction Logic
# -------------------------------
def handle_click(self, pos):
if self.state in ["mode", "continent", "americas", "difficulty", "pairs", "timer"]:
for rect, option in self.buttons:
if rect.collidepoint(pos):
if self.state == "mode":
self.player_mode = 1 if option == "1 Player" else 2
self.state = "continent"
elif 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.state = "timer"
elif self.state == "timer":
self.confirmation_time_limit = int(option.replace("s", ""))
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
# -------------------------------
def check_selected(self):
if self.state != "game":
return
if len(self.selected) == 2 and not self.awaiting_confirmation:
a, b = self.selected
text_a = self.cards[a]["text"]
text_b = self.cards[b]["text"]
is_match = self.pair_map.get(text_a) == text_b
self.correct_answer_expected = "yes" if is_match else "no"
self.awaiting_confirmation = True
self.confirmation_start_time = time.time()
# Timeout logic
if self.awaiting_confirmation and time.time() - self.confirmation_start_time > self.confirmation_time_limit:
a, b = self.selected
self.revealed[a] = self.revealed[b] = False
self.awaiting_confirmation = False
self.selected = []
if self.player_mode == 2:
self.current_player = 1 - self.current_player
return
# Player response
if 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:
if expected == "yes":
self.matched[a] = self.matched[b] = True
self.scores[self.current_player] += 1
self.found_pairs += 1
else:
self.revealed[a] = self.revealed[b] = False
else:
self.scores[self.current_player] -= 1
self.revealed[a] = self.revealed[b] = False
self.awaiting_confirmation = False
self.confirmation_result = None
self.selected = []
if self.player_mode == 2:
self.current_player = 1 - self.current_player
# -------------------------------
# Winner Screen
# -------------------------------
def display_winner(self, screen):
if self.player_mode == 1:
text = f"🏆 Final Score: {self.scores[0]}"
else:
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))
screen.blit(win_text, win_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)))
pygame.display.flip()
# -------------------------------
# Main Loop
# -------------------------------
def run(self):
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Global Match CountryCapital Memory Game")
clock = pygame.time.Clock()
self.font = pygame.font.SysFont(None, 32)
self.small_font = pygame.font.SysFont(None, 22)
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 == "mode":
self.draw_menu(screen, "Select Player Mode", ["1 Player", "2 Players"])
elif 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 == "timer":
self.draw_menu(screen, "Select Confirmation Time", ["3s", "5s", "8s", "10s"])
elif self.state == "game":
self.draw_game(screen)
self.check_selected()
if self.found_pairs == self.total_pairs:
self.display_winner(screen)
pygame.time.wait(4000)
self.running = False
clock.tick(FPS)
pygame.quit()
sys.exit()
# -------------------------------
# Run
# -------------------------------
if __name__ == "__main__":
game = MemoryGame()
game.run()