global_match_memory/Memory_timer.py
2025-11-12 15:18:25 +01:00

386 lines
16 KiB
Python
Raw Permalink 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
# -------------------------------
# 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)
CAPITAL_COLOR = (0, 60, 180) # Different color for capitals
BG_COLOR = (50, 50, 80)
SCREEN_WIDTH, SCREEN_HEIGHT = 800, 600
FPS = 30
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.small_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.confirmation_start_time = None # Track when the box appeared
self.state = "mode" # start at player mode select
self.buttons = []
self.selected_continents = []
self.level = None
self.pair_count = 6 # Default
self.player_mode = 2 # Default 2 players
self.confirmation_time_limit = 5 # Default 5 seconds
# -------------------------------
# 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)
self.deck = self.deck[:self.pair_count] # Limit to selected pair count
def setup_game(self):
"""Create card objects with type info (country/capital)."""
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.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)
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, (200, 200, 200))
else:
title = self.font.render("Single Player Mode", True, (255, 255, 255))
score_text = self.font.render(f"Score: {self.scores[0]}", True, (200, 200, 200))
screen.blit(title, (20, 20))
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]:
card = self.cards[i]
display_text = card["text"]
text_color = CAPITAL_COLOR if card["type"] == "capital" else TEXT_COLOR
# Draw main text
text = self.font.render(display_text, True, text_color)
text_rect = text.get_rect(center=(rect.centerx, rect.centery - 10))
screen.blit(text, text_rect)
# Draw small label ("Country" / "Capital")
label_text = "(Capital)" if card["type"] == "capital" else "(Country)"
label = self.small_font.render(label_text, True, (80, 80, 80))
label_rect = label.get_rect(center=(rect.centerx, rect.centery + 20))
screen.blit(label, label_rect)
# Draw confirmation box with countdown if needed
if self.awaiting_confirmation:
self.draw_confirmation_box(screen)
pygame.display.flip()
def draw_confirmation_box(self, screen):
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))
# Draw countdown timer
elapsed = time.time() - self.confirmation_start_time
remaining = max(0, self.confirmation_time_limit - elapsed)
timer_text = self.small_font.render(f"{remaining:.1f}s left", True, (150, 0, 0))
screen.blit(timer_text, (box_rect.centerx - timer_text.get_width() // 2, box_rect.y + 60))
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 ["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 check
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.confirmation_result = None
self.selected = []
if self.player_mode == 2:
self.current_player = 1 - self.current_player
return
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
# -------------------------------
# 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)
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.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.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 the Game
# -------------------------------
if __name__ == "__main__":
game = MemoryGame()
game.run()
#189 Yes or no Box
#207 Main menu clicks
#124 1p mode
#45 timer 1p
#Added a new variable: self.confirmation_time_limit