From 7825e7b43822c1fcf17df2928f69447707e80472 Mon Sep 17 00:00:00 2001 From: hnu202410040514 <3200210348@qq.com> Date: Wed, 21 May 2025 11:49:18 +0800 Subject: [PATCH] ADD file via upload --- gomoku.py | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 gomoku.py diff --git a/gomoku.py b/gomoku.py new file mode 100644 index 0000000..f568d35 --- /dev/null +++ b/gomoku.py @@ -0,0 +1,237 @@ + +import pygame +import sys +import json +import os + +pygame.init() +pygame.mixer.init() + +pygame.mixer.music.load(".\\fodder\\bgm.mp3") +pygame.mixer.music.play(-1) +place_sound = pygame.mixer.Sound("./fodder/sound_click_btn.mp3") + +w, h = 900, 900 +n = 15 +s = w // n +black = (0, 0, 0) +white = (255, 255, 255) +bg = (200, 150, 100) +red = (200, 0, 0) + +scr = pygame.display.set_mode((w, h)) +pygame.display.set_caption("五子棋") + +f_big = pygame.font.SysFont("fangsong", 80) +f_small = pygame.font.SysFont("fangsong", 60) +f_button = pygame.font.SysFont("fangsong", 40) + +ranking_file = "rankings.json" + +def load_rankings(): + if os.path.exists(ranking_file): + with open(ranking_file, "r", encoding="utf-8") as f: + return json.load(f) + return {} + +def save_rankings(data): + with open(ranking_file, "w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=False, indent=2) + +rankings = load_rankings() + +def record_win(name): + if name not in rankings: + rankings[name] = {"wins": 0, "games": 0} + rankings[name]["wins"] += 1 + rankings[name]["games"] += 1 + +def record_loss(name): + if name not in rankings: + rankings[name] = {"wins": 0, "games": 0} + rankings[name]["games"] += 1 + +class TextInputBox: + def __init__(self, x, y, w, h, label): + self.rect = pygame.Rect(x, y, w, h) + self.color = (200, 200, 200) + self.text = '' + self.label = label + self.txt_surface = pygame.font.SysFont("fangsong", 40).render(self.text, True, black) + self.active = False + + def handle_event(self, event): + if event.type == pygame.MOUSEBUTTONDOWN: + self.active = self.rect.collidepoint(event.pos) + elif event.type == pygame.KEYDOWN and self.active: + if event.key == pygame.K_BACKSPACE: + self.text = self.text[:-1] + else: + self.text += event.unicode + self.txt_surface = pygame.font.SysFont("fangsong", 40).render(self.text, True, black) + + def draw(self, screen): + label_surface = pygame.font.SysFont("fangsong", 40).render(self.label, True, black) + screen.blit(label_surface, (self.rect.x, self.rect.y - 30)) + pygame.draw.rect(screen, self.color, self.rect, 2) + screen.blit(self.txt_surface, (self.rect.x + 5, self.rect.y + 8)) + +game_state = "menu" +input_boxes = [ + TextInputBox(w//2 - 150, h//2 - 30, 300, 40, "黑棋玩家:"), + TextInputBox(w//2 - 150, h//2 + 60, 300, 40, "白棋玩家:") +] +player1, player2 = "", "" +p = 1 +b = [[0 for _ in range(n)] for _ in range(n)] +over = False + +def draw_board(): + scr.fill(bg) + for i in range(n): + pygame.draw.line(scr, black, (s // 2, s // 2 + i * s), (w - s // 2, s // 2 + i * s), 1) + pygame.draw.line(scr, black, (s // 2 + i * s, s // 2), (s // 2 + i * s, h - s // 2), 1) + pygame.draw.rect(scr, (230, 180, 150), (w - 160, 20, 140, 40)) + t = f_button.render("返回主菜单", True, black) + scr.blit(t, (w - 150, 25)) + +def draw_chess(): + for y in range(n): + for x in range(n): + cx, cy = x * s + s // 2, y * s + s // 2 + r = s // 2 - 4 + if b[y][x] == 1: + pygame.draw.circle(scr, (30, 30, 30), (cx, cy), r) + pygame.draw.circle(scr, black, (cx - r // 3, cy - r // 3), r // 2) + elif b[y][x] == 2: + pygame.draw.circle(scr, white, (cx, cy), r) + pygame.draw.circle(scr, (200, 200, 200), (cx - r // 3, cy - r // 3), r // 2) + +def check_win(x, y, who): + def count(dx, dy): + c = 1 + for d in [1, -1]: + nx, ny = x, y + while True: + nx += dx * d + ny += dy * d + if 0 <= nx < n and 0 <= ny < n and b[ny][nx] == who: + c += 1 + else: + break + return c + for dx, dy in [(1, 0), (0, 1), (1, 1), (1, -1)]: + if count(dx, dy) >= 5: + return True + return False + +def draw_text_center(text, font, color, y_offset=0): + t = font.render(text, True, color) + r = t.get_rect(center=(w // 2, h // 2 + y_offset)) + scr.blit(t, r) + return r + +def draw_menu(): + scr.fill((240, 220, 180)) + draw_text_center("五子棋小游戏", f_big, black, -150) + start_btn = draw_text_center("开始游戏", f_small, black, -20) + rank_btn = draw_text_center("查看排行榜", f_small, black, 50) + quit_btn = draw_text_center("退出游戏", f_small, red, 120) + return start_btn, rank_btn, quit_btn + +def draw_name_input(): + scr.fill((220, 220, 200)) + draw_text_center("输入玩家姓名", f_big, black, -200) + for box in input_boxes: + box.draw(scr) + draw_text_center("按 Enter 开始游戏", f_button, red, 150) + +def draw_win_message(): + winner = player1 if p == 2 else player2 + draw_text_center(f"{winner} 获胜!点击任意处重新开始", f_small, black) + +def draw_rankings(): + scr.fill((240, 240, 220)) + draw_text_center("排行榜", f_big, black, -300) + y = 150 + for name, data in sorted(rankings.items(), key=lambda x: x[1]["wins"], reverse=True): + win = data["wins"] + games = data["games"] + rate = (win / games * 100) if games else 0 + txt = f"{name}: 胜场 {win} / 对局 {games} - 胜率 {rate:.1f}%" + t = f_small.render(txt, True, black) + scr.blit(t, (100, y)) + y += 50 + draw_text_center("点击任意处返回菜单", f_small, red, 350) + +while True: + scr.fill(bg) + + if game_state == "menu": + start_btn, rank_btn, quit_btn = draw_menu() + elif game_state == "input_name": + draw_name_input() + elif game_state == "play": + draw_board() + draw_chess() + if over: + draw_win_message() + elif game_state == "rank": + draw_rankings() + + pygame.display.flip() + + for e in pygame.event.get(): + if e.type == pygame.QUIT: + pygame.quit() + sys.exit() + if game_state == "menu": + if e.type == pygame.MOUSEBUTTONDOWN: + mx, my = pygame.mouse.get_pos() + if start_btn.collidepoint(mx, my): + game_state = "input_name" + elif rank_btn.collidepoint(mx, my): + game_state = "rank" + elif quit_btn.collidepoint(mx, my): + pygame.quit() + sys.exit() + elif game_state == "input_name": + for box in input_boxes: + box.handle_event(e) + if e.type == pygame.KEYDOWN and e.key == pygame.K_RETURN: + player1 = input_boxes[0].text.strip() or "玩家1" + player2 = input_boxes[1].text.strip() or "玩家2" + b = [[0 for _ in range(n)] for _ in range(n)] + p = 1 + over = False + game_state = "play" + elif game_state == "play": + if e.type == pygame.MOUSEBUTTONDOWN: + mx, my = pygame.mouse.get_pos() + if w - 160 <= mx <= w - 20 and 20 <= my <= 60: + b = [[0 for _ in range(n)] for _ in range(n)] + p = 1 + over = False + game_state = "menu" + elif not over: + gx, gy = mx // s, my // s + if 0 <= gx < n and 0 <= gy < n and b[gy][gx] == 0: + b[gy][gx] = p + if place_sound: + place_sound.play() + if check_win(gx, gy, p): + winner = player1 if p == 1 else player2 + loser = player2 if p == 1 else player1 + record_win(winner) + record_loss(loser) + save_rankings(rankings) + over = True + else: + p = 2 if p == 1 else 1 + elif over: + b = [[0 for _ in range(n)] for _ in range(n)] + p = 1 + over = False + elif game_state == "rank": + if e.type == pygame.MOUSEBUTTONDOWN: + game_state = "menu"