commit 7beeb6fe61f84a65a414104976450989a3622b19 Author: bhattial100541 Date: Wed Nov 12 12:10:43 2025 +0100 Initial commit – Global Match Memory diff --git a/.env b/.env new file mode 100644 index 0000000..7d529a1 --- /dev/null +++ b/.env @@ -0,0 +1,7 @@ +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 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/Memory GlobalMatch.iml b/.idea/Memory GlobalMatch.iml new file mode 100644 index 0000000..2c80e12 --- /dev/null +++ b/.idea/Memory GlobalMatch.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..46e9a4d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..36c4eef --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Africa-Dependent.txt b/Africa-Dependent.txt new file mode 100755 index 0000000..d70a6b3 --- /dev/null +++ b/Africa-Dependent.txt @@ -0,0 +1,6 @@ +Mayotte Mamoudzou +Réunion Saint-Denis +Saint-Helena Jamestown +Ascension-Island Georgetown +Tristan-da-Cunha Edinburgh-of-the-Seven-Seas +Western-Sahara El-Aaiún diff --git a/Africa-Major.txt b/Africa-Major.txt new file mode 100755 index 0000000..477f7eb --- /dev/null +++ b/Africa-Major.txt @@ -0,0 +1,20 @@ +Algeria Algiers +Angola Luanda +Egypt Cairo +Ethiopia Addis-Ababa +Ghana Accra +Kenya Nairobi +Libya Tripoli +Morocco Rabat +Mozambique Maputo +Nigeria Abuja +South-Africa Pretoria +Sudan Khartoum +Tanzania Dodoma +Tunisia Tunis +Uganda Kampala +Zimbabwe Harare +Democratic-Republic-of-Congo Kinshasa +Senegal Dakar +Mali Bamako +Côte-d'Ivoire Yamoussoukro diff --git a/Africa-Minor.txt b/Africa-Minor.txt new file mode 100755 index 0000000..7f93b5b --- /dev/null +++ b/Africa-Minor.txt @@ -0,0 +1,20 @@ +Benin Porto-Novo +Burundi Gitega +Cape-Verde Praia +Comoros Moroni +Djibouti Djibouti +Equatorial-Guinea Malabo +Eritrea Asmara +Eswatini Mbabane +Gabon Libreville +Gambia Banjul +Lesotho Maseru +Liberia Monrovia +Mauritius Port-Louis +Namibia Windhoek +Rwanda Kigali +Seychelles Victoria +Sierra-Leone Freetown +São-Tomé-and-Príncipe São-Tomé +Togo Lomé +Burkina-Faso Ouagadougou diff --git a/Asia-Dependent.txt b/Asia-Dependent.txt new file mode 100755 index 0000000..f2c16d7 --- /dev/null +++ b/Asia-Dependent.txt @@ -0,0 +1,5 @@ +Hong-Kong Hong-Kong +Macau Macau +Taiwan Taipei +Palestine Ramallah +Kuwait-Northern-Region (for historical/admin regions if needed) diff --git a/Asia-Major.txt b/Asia-Major.txt new file mode 100755 index 0000000..48d7120 --- /dev/null +++ b/Asia-Major.txt @@ -0,0 +1,20 @@ +China Beijing +India New-Delhi +Japan Tokyo +Indonesia Jakarta +Pakistan Islamabad +Bangladesh Dhaka +Russia Moscow +Saudi-Arabia Riyadh +Iran Tehran +Turkey Ankara +South-Korea Seoul +North-Korea Pyongyang +Thailand Bangkok +Vietnam Hanoi +Philippines Manila +Myanmar Naypyidaw +Iraq Baghdad +Afghanistan Kabul +Malaysia Kuala-Lumpur +Uzbekistan Tashkent diff --git a/Asia-Minor.txt b/Asia-Minor.txt new file mode 100755 index 0000000..e45f088 --- /dev/null +++ b/Asia-Minor.txt @@ -0,0 +1,25 @@ +Armenia Yerevan +Azerbaijan Baku +Bahrain Manama +Bhutan Thimphu +Brunei Bandar Seri Begawan +Cambodia Phnom-Penh +East-Timor Dili +Georgia Tbilisi +Israel Jerusalem +Jordan Amman +Kuwait Kuwait-City +Laos Vientiane +Lebanon Beirut +Maldives Malé +Mongolia Ulaanbaatar +Nepal Kathmandu +Oman Muscat +Qatar Doha +Singapore Singapore +Sri-Lanka Sri-Jayawardenepura-Kotte +Syria Damascus +Tajikistan Dushanbe +Turkmenistan Ashgabat +United-Arab-Emirates Abu-Dhabi +Yemen Sana'a diff --git a/Europe-Dependent.txt b/Europe-Dependent.txt new file mode 100755 index 0000000..922c2c8 --- /dev/null +++ b/Europe-Dependent.txt @@ -0,0 +1,13 @@ +Faroe-Islands Torshavn +Gibraltar Gibraltar +Guernsey St-Peter-Port +Jersey Saint-Helier +Isle-of-Man Douglas +Greenland Nuuk +Svalbard Longyearbyen +Åland-Islands Mariehamn +Kosovo Pristina +Transnistria Tiraspol +Abkhazia Sukhumi +South-Ossetia Tskhinvali +Nagorno-Karabakh Stepanakert diff --git a/Europe-Major.txt b/Europe-Major.txt new file mode 100755 index 0000000..b156d16 --- /dev/null +++ b/Europe-Major.txt @@ -0,0 +1,24 @@ +Austria Vienna +Belgium Brussels +Croatia Zagreb +Czechia Prague +Denmark Copenhagen +Finland Helsinki +France Paris +Germany Berlin +Greece Athens +Hungary Budapest +Ireland Dublin +Italy Rome +Netherlands Amsterdam +Norway Oslo +Poland Warsaw +Portugal Lisbon +Romania Bucharest +Spain Madrid +Sweden Stockholm +Switzerland Bern +United-Kingdom London +Ukraine Kyiv + + diff --git a/Europe-Minor.txt b/Europe-Minor.txt new file mode 100755 index 0000000..c5aefaa --- /dev/null +++ b/Europe-Minor.txt @@ -0,0 +1,19 @@ +Andorra Andorra-la-Vella +Liechtenstein Vaduz +Luxembourg Luxembourg +Malta Valletta +Monaco Monaco +San-Marino San-Marino +Vatican-City Vatican-City +Kosovo Pristina +Montenegro Podgorica +North-Macedonia Skopje +Estonia Tallinn +Latvia Riga +Lithuania Vilnius +Iceland Reykjavik +Slovenia Ljubljana +Albania Tirana +Moldova Chisinau +Bosnia-and-Herzegovina Sarajevo +Cyprus Nicosia diff --git a/Finished_Memory_Mouse.py b/Finished_Memory_Mouse.py new file mode 100755 index 0000000..7a86a54 --- /dev/null +++ b/Finished_Memory_Mouse.py @@ -0,0 +1,327 @@ +import pygame +import random +import sys +import os + +# ------------------------------- +# Country–Capital 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("Country–Capital 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() + diff --git a/Nord-Amerika.txt b/Nord-Amerika.txt new file mode 100755 index 0000000..7d66bf0 --- /dev/null +++ b/Nord-Amerika.txt @@ -0,0 +1,23 @@ +Kanada Ottawa +USA Washington +Mexiko Mexiko-Stadt +Bahamas Nassau +Kuba Havanna +Jamaika Kingston +Haiti Port-au-Prince +Dominikanische-Republik Santa-Domingo + + +Nervige Inseln: +St.Kitts-und-Nevis Basseterre +Antigua-und-Barbuda Saint-John´s +Dominica Roseau +St.Lucia Castries +Barbados Bridgetown +Grenada St.George´s +Trinidad-und-Tobago Port-of-Spain +Saint-Vincent-und-die-Grenadinen Kingstown +Anguilla The-Valley +Bermuda Hamilton + + \ No newline at end of file diff --git a/North-America-Dependent.txt b/North-America-Dependent.txt new file mode 100755 index 0000000..b88b78e --- /dev/null +++ b/North-America-Dependent.txt @@ -0,0 +1,14 @@ +Puerto-Rico San-Juan +Greenland Nuuk +Bermuda Hamilton +Groenland Nuuk +Cayman-Islands George-Town +Aruba Oranjestad +Curacao Willemstad +Saint-Martin Marigot +Sint-Maarten Philipsburg +Turks-and-Caicos-Islands Cockburn-Town +British-Virgin-Islands Road-Town +US-Virgin-Islands Charlotte-Amalie +Anguilla The-Valley +Montserrat Plymouth diff --git a/North-America-Major.txt b/North-America-Major.txt new file mode 100755 index 0000000..ac24ffb --- /dev/null +++ b/North-America-Major.txt @@ -0,0 +1,16 @@ +Canada Ottawa +United-States Washington-D.C. +Mexico Mexico-City +Guatemala Guatemala-City +Belize Belmopan +El-Salvador San-Salvador +Honduras Tegucigalpa +Nicaragua Managua +Costa-Rica San-Jose +Panama Panama-City +Cuba Havana +Dominican-Republic Santo-Domingo +Haiti Port-au-Prince +Jamaica Kingston +Bahamas Nassau +Trinidad-and-Tobago Port-of-Spain \ No newline at end of file diff --git a/North-America-Small.txt b/North-America-Small.txt new file mode 100755 index 0000000..9c07d82 --- /dev/null +++ b/North-America-Small.txt @@ -0,0 +1,8 @@ +Antigua-and-Barbuda Saint-John's +Barbados Bridgetown +Dominica Roseau +Grenada St.-George's +Saint-Kitts-and-Nevis Basseterre +Saint-Lucia Castries +Saint-Vincent-and-the-Grenadines Kingstown +Barbuda Codrington \ No newline at end of file diff --git a/Oceania-Dependent.txt b/Oceania-Dependent.txt new file mode 100755 index 0000000..3d4e5ff --- /dev/null +++ b/Oceania-Dependent.txt @@ -0,0 +1,11 @@ +American-Samoa Pago-Pago +Cook-Islands Avarua +French-Polynesia Papeete +Guam Hagåtña +New-Caledonia Nouméa +Niue Alofi +Norfolk-Island Kingston +Northern-Mariana-Islands Saipan +Pitcairn-Islands Adamstown +Tokelau Atafu +Wallis-and-Futuna Mata-Utu diff --git a/Oceania-Major.txt b/Oceania-Major.txt new file mode 100755 index 0000000..07e79bc --- /dev/null +++ b/Oceania-Major.txt @@ -0,0 +1,8 @@ +Australia Canberra +New-Zealand Wellington +Papua-New-Guinea Port-Moresby +Fiji Suva +Solomon-Islands Honiara +Vanuatu Port-Vila +Samoa Apia +Tonga Nuku'alofa diff --git a/Oceania-Minor.txt b/Oceania-Minor.txt new file mode 100755 index 0000000..f77c4ad --- /dev/null +++ b/Oceania-Minor.txt @@ -0,0 +1,6 @@ +Kiribati Tarawa +Marshall-Islands Majuro +Micronesia Palikir +Nauru Yaren +Palau Ngerulmud +Tuvalu Funafuti diff --git a/Ozeanien.txt b/Ozeanien.txt new file mode 100755 index 0000000..e69de29 diff --git a/South-America-Dependent.txt b/South-America-Dependent.txt new file mode 100755 index 0000000..4133181 --- /dev/null +++ b/South-America-Dependent.txt @@ -0,0 +1,2 @@ +French-Guiana Cayenne +Falkland-Islands Stanley diff --git a/South-America-Major.txt b/South-America-Major.txt new file mode 100755 index 0000000..72b08b8 --- /dev/null +++ b/South-America-Major.txt @@ -0,0 +1,12 @@ +Argentina Buenos-Aires +Bolivia Sucre +Brazil Brasilia +Chile Santiago +Colombia Bogota +Ecuador Quito +Guyana Georgetown +Paraguay Asuncion +Peru Lima +Suriname Paramaribo +Uruguay Montevideo +Venezuela Caracas diff --git a/South-America-Small.txt b/South-America-Small.txt new file mode 100755 index 0000000..3ca41f1 --- /dev/null +++ b/South-America-Small.txt @@ -0,0 +1,3 @@ +Suriname Paramaribo +Guyana Georgetown +Uruguay Montevideo diff --git a/global_match_memory.py b/global_match_memory.py new file mode 100644 index 0000000..0c2a2d6 --- /dev/null +++ b/global_match_memory.py @@ -0,0 +1,334 @@ +import pygame +import sys +import random +import os +from typing import List, Tuple + +# ---------------------------------------------------------- +# Design / Layout +# ---------------------------------------------------------- +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) + +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") + ], +} + +# ---------------------------------------------------------- +# Helpers +# ---------------------------------------------------------- +def load_logo_scaled(size: Tuple[int, int]) -> pygame.Surface: + """Lädt LogoSpiel.png und skaliert mit 10% Rand. Fallback: dunkles GM-Pattern.""" + w, h = size + surf = pygame.Surface((w, h), pygame.SRCALPHA) + # weiße Karte + pygame.draw.rect(surf, CARD_FACE, (0, 0, w, h), border_radius=CARD_RADIUS) + pygame.draw.rect(surf, CARD_BORDER, (0, 0, w, h), width=2, border_radius=CARD_RADIUS) + + inner_pad = int(min(w, h) * 0.12) + logo_rect = pygame.Rect(inner_pad, inner_pad, w - 2*inner_pad, h - 2*inner_pad) + + if os.path.exists(LOGO_FILE): + try: + img = pygame.image.load(LOGO_FILE).convert_alpha() + img = scale_to_fit(img, logo_rect.size) + surf.blit(img, ( + logo_rect.centerx - img.get_width() // 2, + logo_rect.centery - img.get_height() // 2 + )) + return surf + except Exception: + pass + + # Fallback: Text "GLOBAL MATCH" + font = pygame.font.SysFont(None, int(h * 0.16), bold=True) + t1 = font.render("GLOBAL", True, (10, 80, 110)) + t2 = font.render("MATCH", True, (240, 180, 60)) + surf.blit(t1, (w//2 - t1.get_width()//2, h//2 - t1.get_height())) + surf.blit(t2, (w//2 - t2.get_width()//2, h//2 + 4)) + return surf + +def scale_to_fit(img: pygame.Surface, target_size: Tuple[int, int]) -> pygame.Surface: + tw, th = target_size + iw, ih = img.get_width(), img.get_height() + 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]: + words = text.split() + lines, line = [], "" + 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]: + pool = DATA[level][:] if level in DATA else DATA["Europa"][:] + random.shuffle(pool) + chosen = pool[:n_pairs] + payloads = [] + pid = 0 + for land, cap in chosen: + payloads.append({"pair": pid, "label": land, "kind": "country"}) + payloads.append({"pair": pid, "label": cap, "kind": "capital"}) + pid += 1 + random.shuffle(payloads) + return payloads + +# ---------------------------------------------------------- +# Card +# ---------------------------------------------------------- +class Card: + def __init__(self, rect: pygame.Rect, payload: dict, fonts, back_img: pygame.Surface): + self.rect = rect + 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): + w, h = self.rect.w, self.rect.h + # weiße Karte + Rand + pygame.draw.rect(self.front, CARD_FACE, (0, 0, w, h), border_radius=CARD_RADIUS) + pygame.draw.rect(self.front, CARD_BORDER, (0, 0, w, h), width=2, border_radius=CARD_RADIUS) + + # Badge + badge = "Land" if self.payload["kind"] == "country" else "Hauptstadt" + bsurf = self.small.render(badge, True, BADGE_TEXT) + bw, bh = bsurf.get_size() + 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) + + # HUD + pygame.draw.rect(screen, (7, 42, 70), (0, 0, WINDOW_W, HUD_BAR_H)) + title = ui_font.render(f"Global Match – {level}", True, (255, 255, 255)) + screen.blit(title, (PADDING, HUD_BAR_H//2 - title.get_height()//2)) + + if mode == "single": + tsec = (time_left // 1000) if time_left is not None else 0 + 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() + +# ---------------------------------------------------------- +# Direktstart (zu Testzwecken) +# ---------------------------------------------------------- +if __name__ == "__main__": + lvl = "Europa" + md = "single" + if len(sys.argv) >= 2: + lvl = sys.argv[1] + if len(sys.argv) >= 3: + md = sys.argv[2] + run_memory(level=lvl, mode=md) + + diff --git a/images/GlobalHintergrund.png b/images/GlobalHintergrund.png new file mode 100644 index 0000000..5962a68 Binary files /dev/null and b/images/GlobalHintergrund.png differ diff --git a/images/GlobalMatch.png b/images/GlobalMatch.png new file mode 100644 index 0000000..8e712c0 Binary files /dev/null and b/images/GlobalMatch.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..b34b6c9 --- /dev/null +++ b/index.html @@ -0,0 +1,183 @@ +from global_match_memory import run_memory + + + + + + + Global Match – Start + + + + + + +
+
+
+ +
+
+
+ + +

Finde Länder & Hauptstädte – allein oder im Duell!

+
+ +
+
+ + + + +
+ +
+
+
+ + +
+
+
+
+
+
+ + + + + +