global_match_memory/Finished_Memory_Mouse.py

454 lines
18 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
from pythonosc import dispatcher, osc_server
import threading
# ===== OSC Setup =====
touch_x, touch_y = None, None
clap_trigger = False
def osc_touch(address, x, y):
global touch_x, touch_y
touch_x, touch_y = x, y
def osc_clap(address):
global clap_trigger
clap_trigger = True
def start_osc_server():
disp = dispatcher.Dispatcher()
disp.map("/touch", osc_touch)
disp.map("/clap", osc_clap)
server = osc_server.ThreadingOSCUDPServer(("127.0.0.1", 8000), disp)
print("🔊 OSC server läuft auf Port 8000")
server.serve_forever()
# Starte den OSC Listener im Hintergrund
threading.Thread(target=start_osc_server, daemon=True).start()
# -------------------------------
# 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)
global touch_x, touch_y, clap_trigger
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)
# 👇 OSC-Eingaben integrieren
if touch_x is not None:
self.handle_click((touch_x, touch_y))
touch_x, touch_y = None, None
if clap_trigger:
if self.awaiting_confirmation:
self.confirmation_result = "yes"
clap_trigger = False
# Menü- und Spiel-Rendering
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()
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))
rect = win_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
screen.blit(win_text, rect)
# -------------------------------
# Run
# -------------------------------
if __name__ == "__main__":
game = MemoryGame()
game.run()