ai自制原创棋

请注意以下棋类完全由本人原创构思+ai代码构成,简单梳理可玩性后推出【规则封装至程序】

瘸子棋.py

import numpy as np
import os
import sys
from enum import Enum

class GameState(Enum):
    MENU = 1
    PLAYING = 2
    RULES = 3
    GAME_OVER = 4

class LameChessGame:
    def __init__(self, n=17):
        if n % 2 == 0:
            n += 1  # 确保棋盘有中心点
        self.n = n
        self.board = np.full((n, n), ' ', dtype=str)  # 初始化棋盘
        self.center = n // 2
        self.pawn_pos = (self.center, self.center)  # 瘸子初始位置
        self.board[self.center][self.center] = 'P'  # 放置瘸子

        # 设置终点位置
        self.goal_A = (self.center, 0)
        self.goal_B = (self.center, n - 1)
        self.board[self.goal_A] = 'G'  # A终点标记
        self.board[self.goal_B] = 'G'  # B终点标记

        self.current_player = 'A'  # A先手
        self.valves = {'A': [], 'B': []}  # 存储转向阀位置
        self.turn_positions = []  # 记录转动路径
        self.move_count = 0
        self.winner = None
        self.game_state = GameState.MENU
        self.valid_placements = []  # 存储当前可放置位置
        self.preview_dict = {}  # 预览位置字典(位置->数字编号)
        self.consecutive_no_moves = 0  # 连续无移动回合计数

    def clear_screen(self):
        """清屏函数"""
        os.system('cls' if os.name == 'nt' else 'clear')

    def print_header(self):
        """打印游戏标题"""
        print("=" * 60)
        print(f"{'瘸 子 棋 游 戏':^60}")
        print("=" * 60)
        print(f"{'棋盘大小: ' + str(self.n) + 'x' + str(self.n):^60}")
        print("=" * 60)

    def print_board(self, preview_dict=None):
        """打印当前棋盘状态"""
        if preview_dict is None:
            preview_dict = {}

        # 列坐标
        col_header = "     " + " ".join(f"{i:02d}" for i in range(self.n))
        print(col_header)
        print("   ┌" + "──" * self.n + "─┐")

        for r in range(self.n):
            row_str = f"{r:02d} │ "
            for c in range(self.n):
                pos = (r, c)
                cell = self.board[r][c]

                # 显示预览位置数字
                display_char = None
                if pos in preview_dict:
                    num = preview_dict[pos]
                    display_char = f'\033[1;37;44m{num}\033[0m'  # 蓝底白字加粗

                if display_char:
                    row_str += display_char
                elif cell == 'G' and pos == self.goal_A:  # A终点
                    row_str += '\033[91m★\033[0m'
                elif cell == 'G' and pos == self.goal_B:  # B终点
                    row_str += '\033[94m★\033[0m'
                elif cell == 'P':  # 瘸子
                    row_str += '\033[92m♞\033[0m'
                elif cell == 'A':  # A阀门
                    row_str += '\033[91m■\033[0m'
                elif cell == 'B':  # B阀门
                    row_str += '\033[94m■\033[0m'
                elif cell == ' ':  # 空位
                    row_str += '·'
                else:  # 其他
                    row_str += f'{cell}'

                row_str += ' '  # 格子间空格

            row_str += "│"
            print(row_str)

        print("   └" + "──" * self.n + "─┘")
        print(
            f"玩家 \033[91mA\033[0m 目标: ({self.goal_A[0]}, {self.goal_A[1]}) | 玩家 \033[94mB\033[0m 目标: ({self.goal_B[0]}, {self.goal_B[1]})")
        print(f"当前回合: 玩家 \033[{'91' if self.current_player == 'A' else '94'}m{self.current_player}\033[0m")
        print(f"移动次数: {self.move_count}")

    def get_adjacent_positions(self, pos):
        """获取相邻位置"""
        r, c = pos
        positions = []
        for dr, dc in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
            nr, nc = r + dr, c + dc
            if 0 <= nr < self.n and 0 <= nc < self.n:
                positions.append((nr, nc))
        return positions

    def place_valve(self):
        """放置转向阀阶段(强制放置)"""
        self.clear_screen()
        self.print_header()

        adjacent = self.get_adjacent_positions(self.pawn_pos)
        self.valid_placements = [pos for pos in adjacent if self.board[pos] == ' ' or self.board[pos] == 'G']
        self.preview_dict = {}  # 重置预览字典

        # 如果没有可放置位置,直接跳过
        if not self.valid_placements:
            print("\n\033[33m无可放置位置,跳过放置阶段\033[0m")
            input("按Enter继续...")
            return False

        # 创建位置-数字映射
        for i, pos in enumerate(self.valid_placements):
            if i < 9:  # 只显示1-9
                self.preview_dict[pos] = i + 1

        # 打印棋盘并显示预览位置数字
        self.print_board(preview_dict=self.preview_dict)

        print(f"\n\033[92m请选择放置位置:\033[0m")
        for i, pos in enumerate(self.valid_placements):
            # 为每个选项显示数字编号
            num_display = f"[\033[44m{i+1}\033[0m]" if i < 9 else f"[{i+1}]"
            print(f"{num_display}: ({pos[0]}, {pos[1]})")

        while True:
            try:
                choice = input("请输入放置位置编号: ")
                choice = int(choice)
                if 1 <= choice <= len(self.valid_placements):
                    pos = self.valid_placements[choice - 1]
                    r, c = pos

                    # 放置转向阀
                    self.board[r][c] = self.current_player
                    self.valves[self.current_player].append((r, c))
                    print(
                        f"玩家 \033[{'91' if self.current_player == 'A' else '94'}m{self.current_player}\033[0m 在 ({r},{c}) 放置了转向阀")
                    return True
                else:
                    print("\033[33m编号无效,请重新选择\033[0m")
            except:
                print("\033[33m输入无效,请重新选择\033[0m")

    def is_valve_in_straight_line(self, valve_pos):
        """检查阀门是否在瘸子的同一行或同一列(水平或垂直方向)"""
        r1, c1 = self.pawn_pos
        r2, c2 = valve_pos
        return r1 == r2 or c1 == c2

    def check_path_to_valve(self, valve_pos):
        """检查到阀门的路径是否畅通(只检查水平和垂直方向)"""
        r1, c1 = self.pawn_pos
        r2, c2 = valve_pos

        # 首先检查是否在水平或垂直方向
        if not self.is_valve_in_straight_line(valve_pos):
            return False

        # 确定方向向量
        dr = r2 - r1
        dc = c2 - c1

        # 标准化方向
        step_r = 0 if dr == 0 else 1 if dr > 0 else -1
        step_c = 0 if dc == 0 else 1 if dc > 0 else -1

        # 计算步数
        steps = max(abs(dr), abs(dc))

        # 检查路径上的每个格子(不包括起点和终点)
        for i in range(1, steps):
            r = r1 + i * step_r
            c = c1 + i * step_c
            cell = self.board[r][c]

            # 只允许空格、终点或当前玩家的阀门
            if cell == ' ' or cell == 'G' or cell == self.current_player:
                continue
            else:
                return False

        return True

    def calculate_rotation(self, valve_pos):
        """计算旋转后的位置"""
        pr, pc = self.pawn_pos
        vr, vc = valve_pos

        # 计算相对向量
        dr, dc = pr - vr, pc - vc

        # 计算旋转后的位置 (90度)
        clockwise = (vr - dc, vc + dr)  # 顺时针
        counter_clockwise = (vr + dc, vc - dr)  # 逆时针

        valid_positions = []
        for direction, pos in [('顺时针', clockwise), ('逆时针', counter_clockwise)]:
            r, c = pos
            # 检查位置是否在棋盘内
            if not (0 <= r < self.n and 0 <= c < self.n):
                continue

            # 检查落点是否为空或终点(仅允许移动到自己的终点)
            cell = self.board[r][c]
            if cell == ' ':
                pass  # 空位总是允许
            elif cell == 'G':  # 终点位置
                # 玩家A只能移动到A终点,玩家B只能移动到B终点
                if (self.current_player == 'A' and (r, c) != self.goal_A) or \
                        (self.current_player == 'B' and (r, c) != self.goal_B):
                    continue  # 跳过对方终点
            else:
                continue  # 其他情况不允许

            # 检查路径是否畅通
            if not self.check_path_to_valve(valve_pos):
                continue

            # 避免回到原点
            if len(self.turn_positions) > 1 and pos == self.turn_positions[-2]:
                continue

            valid_positions.append((direction, pos))

        return valid_positions

    def rotate_pawn(self):
        """转动瘸子阶段"""
        self.turn_positions = [self.pawn_pos]
        valve_usage = {}  # 本回合阀门使用计数(每回合重置)
        moved = False  # 标记本回合是否进行了移动

        while True:
            self.clear_screen()
            self.print_header()

            available_rotations = []
            self.preview_dict = {}  # 重置预览字典

            # 检查所有可用的转向阀(只考虑水平和垂直方向)
            for valve_pos in self.valves[self.current_player]:
                # 首先检查阀门是否在水平和垂直方向
                if not self.is_valve_in_straight_line(valve_pos):
                    continue

                # 检查使用次数(本回合内)
                if valve_usage.get(valve_pos, 0) < 3:
                    rotations = self.calculate_rotation(valve_pos)
                    for direction, pos in rotations:
                        available_rotations.append((valve_pos, direction, pos))

            # 创建预览位置字典
            for idx, (_, _, pos) in enumerate(available_rotations, start=1):
                if idx <= 9:  # 只显示1-9
                    self.preview_dict[pos] = idx

            # 打印棋盘并显示预览位置数字
            self.print_board(preview_dict=self.preview_dict)

            if not available_rotations:
                if not moved:  # 如果整个回合都没移动过
                    print("\n\033[33m无可用的转动操作\033[0m")
                else:
                    print("\n\033[33m无法继续转动\033[0m")
                input("按Enter结束转动阶段...")
                return moved

            # 显示可用操作
            print("\n\033[92m可用转动操作:\033[0m")
            for i, (valve, direction, pos) in enumerate(available_rotations):
                # 为每个选项使用不同颜色
                direction_color = '\033[96m' if direction == '顺时针' else '\033[95m'
                # 如果位置有预览数字,显示在操作中
                preview_num = self.preview_dict.get(pos, ' ')
                preview_display = f"[\033[44m{preview_num}\033[0m]" if pos in self.preview_dict else "[ ]"
                print(
                    f"{preview_display} {i + 1}: 使用阀({valve[0]},{valve[1]}) {direction_color}{direction}\033[0m → 移动到({pos[0]},{pos[1]})")
            print("\033[48;5;196m 0 \033[0m: 结束转动阶段")

            # 玩家选择
            try:
                choice = input("请选择操作编号: ")
                if choice == '0':
                    break

                choice = int(choice)
                if 1 <= choice <= len(available_rotations):
                    valve_pos, direction, new_pos = available_rotations[choice - 1]

                    # 更新使用次数
                    valve_usage[valve_pos] = valve_usage.get(valve_pos, 0) + 1

                    # 移动瘸子
                    old_r, old_c = self.pawn_pos
                    new_r, new_c = new_pos
                    self.board[old_r][old_c] = ' '
                    self.board[new_r][new_c] = 'P'
                    self.pawn_pos = (new_r, new_c)
                    self.turn_positions.append(new_pos)
                    moved = True  # 标记已移动
                    self.move_count += 1

                    direction_color = '\033[96m' if direction == '顺时针' else '\033[95m'
                    print(
                        f"\n玩家 \033[{'91' if self.current_player == 'A' else '94'}m{self.current_player}\033[0m 使用阀{valve_pos} {direction_color}{direction}\033[0m 移动到 ({new_r},{new_c})")

                    # 检查胜利条件
                    if (self.current_player == 'A' and new_pos == self.goal_A) or \
                            (self.current_player == 'B' and new_pos == self.goal_B):
                        self.winner = self.current_player
                        return True
                else:
                    print("\033[33m编号无效,请重新选择\033[0m")
            except:
                print("\033[33m输入无效,请重新选择\033[0m")

        return moved

    def play_turn(self):
        """执行一个完整回合"""
        # 放置阶段(强制放置)
        placed = self.place_valve()

        # 转动阶段
        moved = self.rotate_pawn()

        # 如果本回合有移动操作,重置无移动计数
        if placed or moved:
            self.consecutive_no_moves = 0
        else:
            self.consecutive_no_moves += 1
            print(f"\n\033[33m玩家 {self.current_player} 本回合无有效操作\033[0m")
            print(f"连续无操作回合: {self.consecutive_no_moves}/2")
            input("按Enter继续...")

        # 检查胜利条件
        if self.winner:
            return True

        # 切换玩家
        self.current_player = 'B' if self.current_player == 'A' else 'A'
        return False

    def show_rules(self):
        """显示游戏规则(更新版)"""
        self.clear_screen()
        self.print_header()
        print("\n\033[93m游戏规则:\033[0m")
        print("1. 在一个n×n的棋盘上,A和B轮流博弈")
        print("2. 棋盘中心有一个♞棋子(瘸子)")
        print("3. 每回合玩家必须:")
        print("   a. 在瘸子相邻的4个方向放置一个转向阀(■)(如有位置)")
        print("   b. 使用自己的转向阀进行90度旋转移动(如有可能)")
        print("4. 关键限制:")
        print("   - 只能使用与瘸子在同一行或同一列(水平或垂直方向)的阀门")
        print("   - 不能使用对角线方向上的阀门")
        print("5. 旋转规则:")
        print("   - 路径上不能有对方阀门")
        print("   - 落点必须是空位(·)或己方终点(★)")
        print("   - 同一阀门一回合最多使用3次")
        print("6. 阀门使用:")
        print("   - 阀门永久有效,可跨回合使用")
        print("7. 胜利条件:")
        print("   - 玩家A将♞移动到左侧终点★(中心行,第0列)")
        print("   - 玩家B将♞移动到右侧终点★(中心行,最后一列)")
        print("8. 平局条件:")
        print("   - 双方连续两回合无法进行任何移动")
        print("\n\033[93m操作说明:\033[0m")
        print("- 放置阶段:棋盘上蓝色数字显示的位置是可选放置位置")
        print("- 放置阶段:选择对应数字编号放置阀门")
        print("- 转动阶段:棋盘上蓝色数字显示的位置是可选目标位置")
        print("- 转动阶段:选择对应数字编号进行转动")
        print("- 转动选项显示方向:\033[96m顺时针\033[0m 或 \033[95m逆时针\033[0m")
        print("\n按Enter返回主菜单...")
        input()

    def show_menu(self):
        """显示主菜单"""
        self.clear_screen()
        self.print_header()
        print("\n\033[93m主菜单:\033[0m")
        print("\033[48;5;40m 1 \033[0m 开始新游戏")
        print("\033[48;5;45m 2 \033[0m 游戏规则")
        print("\033[48;5;196m 3 \033[0m 退出游戏")

        while True:
            choice = input("\n请选择: ")
            if choice == '1':
                self.__init__(self.n)  # 重置游戏
                self.game_state = GameState.PLAYING
                return
            elif choice == '2':
                self.game_state = GameState.RULES
                return
            elif choice == '3':
                sys.exit(0)
            else:
                print("\033[33m无效选择,请重新输入\033[0m")

    def show_game_over(self):
        """显示游戏结束画面"""
        self.clear_screen()
        self.print_header()
        self.print_board()

        if self.winner == 'DRAW':
            print("\n╔════════════════════════╗")
            print("║       \033[93m平 局!\033[0m         ║")
            print("╚════════════════════════╝")
            print("双方连续两回合无法进行任何移动")
        else:
            color = '\033[91m' if self.winner == 'A' else '\033[94m'
            print(f"\n╔════════════════════════╗")
            print(f"║  玩家 {color}{self.winner}\033[0m \033[93m获胜!\033[0m  ║")
            print("╚════════════════════════╝")

        print("\n\033[93m选择:\033[0m")
        print("\033[48;5;40m 1 \033[0m 返回主菜单")
        print("\033[48;5;196m 2 \033[0m 退出游戏")

        while True:
            choice = input("\n请选择: ")
            if choice == '1':
                self.game_state = GameState.MENU
                return
            elif choice == '2':
                sys.exit(0)
            else:
                print("\033[33m无效选择,请重新输入\033[0m")

    def play_game(self):
        """主游戏循环"""
        self.consecutive_no_moves = 0

        while True:
            if self.game_state == GameState.MENU:
                self.show_menu()
            elif self.game_state == GameState.RULES:
                self.show_rules()
                self.game_state = GameState.MENU
            elif self.game_state == GameState.PLAYING:
                game_ended = self.play_turn()

                if self.winner:
                    self.game_state = GameState.GAME_OVER
                    continue

                # 检查平局条件
                if self.consecutive_no_moves >= 2:
                    self.winner = 'DRAW'
                    self.game_state = GameState.GAME_OVER

            elif self.game_state == GameState.GAME_OVER:
                self.show_game_over()


# 启动游戏
if __name__ == "__main__":
    # 检查终端尺寸
    if os.name == 'nt':  # Windows
        os.system('mode con: cols=80 lines=50')

    game = LameChessGame(17)  # 17x17棋盘
    game.play_game()

推推棋.py

import numpy as np
import random
import time
import os


class PushGame:
    def __init__(self, rows=7, cols=5):  # 修改为7行5列
        self.set_board_size(rows, cols)
        self.reset_game()
        
    def set_board_size(self, rows, cols):
        """设置棋盘大小并计算相关参数"""
        self.rows = rows
        self.cols = cols
        self.center = (rows // 2, cols // 2)  # 7//2=3, 5//2=2 -> (3,2)
        self.win_count = 1  # 获胜所需中心点计数

    def reset_game(self):
        """重置游戏状态"""
        # 创建空棋盘
        self.board = np.full((self.rows, self.cols), '.', dtype='U1')
        
        # 初始化中心点计数
        self.center_counts = [0, 0]  # [A的中心点计数, B的中心点计数]

        # 初始化玩家位置 - 底边和顶边全放棋子
        # A (玩家0) 在底部一行(所有列)
        for j in range(self.cols):
            self.board[-1, j] = 'A'
        
        # B (玩家1) 在顶部一行(所有列)
        for j in range(self.cols):
            self.board[0, j] = 'B'

        self.current_player = 0  # 0=A, 1=B
        self.last_positions = []  # 存储最近的位置用于检测僵局
        self.game_history = []  # 存储完整游戏历史
        self.move_count = 0  # 移动计数器
        self.last_push_info = None  # 记录上一步的推动信息

    def get_state_key(self):
        """生成唯一状态标识"""
        return hash(str(self.board) + str(self.current_player) + str(self.center_counts))

    def is_valid_position(self, x, y):
        """检查坐标是否有效"""
        return 0 <= x < self.rows and 0 <= y < self.cols

    def get_adjacent_pieces(self, x, y):
        """获取相邻位置的棋子信息"""
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # 右, 下, 左, 上
        adjacent = []

        for dx, dy in directions:
            nx, ny = x + dx, y + dy
            if self.is_valid_position(nx, ny):
                piece = self.board[nx, ny]
                if piece != '.':  # 忽略空位
                    adjacent.append(((nx, ny), piece, (dx, dy)))
        return adjacent

    def can_push_special(self, x, y, direction):
        """检查特殊推动是否可行"""
        dx, dy = direction
        player_char = 'A' if self.current_player == 0 else 'B'

        # 检查推动方向上的相邻位置
        ax, ay = x + dx, y + dy
        if not self.is_valid_position(ax, ay) or self.board[ax, ay] == '.':
            return False

        # 检查特殊规则条件
        adjacent_piece = self.board[ax, ay]
        if dx == 0:  # 水平推动
            if adjacent_piece != player_char:  # 必须是自己棋子
                return False
        else:  # 垂直推动
            if adjacent_piece == player_char:  # 必须是对手棋子
                return False

        # 检查目标位置是否为空
        tx, ty = ax + dx, ay + dy
        return self.is_valid_position(tx, ty) and self.board[tx, ty] == '.'

    def can_push_normal(self, x, y, direction):
        """检查普通推动是否可行"""
        dx, dy = direction
        cx, cy = x, y

        # 检查第一步是否有效
        nx, ny = cx + dx, cy + dy
        if not self.is_valid_position(nx, ny) or self.board[nx, ny] != '.':
            return False

        return True

    def push_piece(self, x, y, direction, move_type):
        """执行推动操作"""
        dx, dy = direction
        player_char = 'A' if self.current_player == 0 else 'B'

        if move_type == 'special':
            # 特殊推动:移动两个棋子
            ax, ay = x + dx, y + dy
            tx, ty = ax + dx, ay + dy

            # 移动相邻棋子
            self.board[tx, ty] = self.board[ax, ay]
            self.board[ax, ay] = '.'

            # 移动主棋子
            self.board[x + dx, y + dy] = self.board[x, y]
            self.board[x, y] = '.'
            
        elif move_type == 'normal':
            # 普通推动:推动直到遇到障碍
            cx, cy = x, y
            while True:
                nx, ny = cx + dx, cy + dy
                if not self.is_valid_position(nx, ny) or self.board[nx, ny] != '.':
                    break
                cx, cy = nx, ny

            # 移动棋子到最终位置
            self.board[cx, cy] = self.board[x, y]
            self.board[x, y] = '.'

    def find_winner(self):
        """检查胜利条件"""
        if self.center_counts[0] >= self.win_count:
            return 0  # A获胜
        elif self.center_counts[1] >= self.win_count:
            return 1  # B获胜
        return -1  # 无胜者

    def is_draw(self):
        """检查是否平局"""
        # 检查僵局条件(连续3次重复局面)
        if len(self.last_positions) >= 6:
            if (self.last_positions[-1] == self.last_positions[-3] == self.last_positions[-5] and
                    self.last_positions[-2] == self.last_positions[-4] == self.last_positions[-6]):
                return True

        # 检查是否无合法移动
        if not self.get_valid_moves():
            self.current_player = 1 - self.current_player
            if not self.get_valid_moves():
                return True
            self.current_player = 1 - self.current_player

        return False

    def get_valid_moves(self):
        """获取所有合法移动"""
        valid_moves = []
        player_char = 'A' if self.current_player == 0 else 'B'
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # 右, 下, 左, 上

        # 查找所有可能的移动
        for x in range(self.rows):
            for y in range(self.cols):
                if self.board[x, y] == player_char:
                    # 检查特殊推动
                    for direction in directions:
                        if self.can_push_special(x, y, direction):
                            valid_moves.append((x, y, direction, 'special'))

                    # 检查普通推动
                    for direction in directions:
                        if self.can_push_normal(x, y, direction):
                            valid_moves.append((x, y, direction, 'normal'))

        # 禁止反推规则
        if self.last_push_info is not None:
            if self.current_player != self.last_push_info['from_player']:
                pushed_pos = self.last_push_info['pushed_piece_final_pos']
                pushed_dir = self.last_push_info['pushed_direction']
                reverse_dir = (-pushed_dir[0], -pushed_dir[1])

                filtered_moves = []
                for move in valid_moves:
                    x, y, dir, mtype = move
                    if mtype == 'special' and (x, y) == pushed_pos and dir == reverse_dir:
                        continue
                    filtered_moves.append(move)
                valid_moves = filtered_moves

        return valid_moves

    def make_move(self, move=None):
        """执行移动"""
        if move is None:
            valid_moves = self.get_valid_moves()
            if not valid_moves:
                return False
            move = random.choice(valid_moves)

        x, y, direction, move_type = move
        self.push_piece(x, y, direction, move_type)

        # 检查是否有棋子到达中心点
        cx, cy = self.center
        if self.board[cx, cy] != '.':
            if self.board[cx, cy] == 'A':
                self.center_counts[0] += 1
            elif self.board[cx, cy] == 'B':
                self.center_counts[1] += 1
            self.board[cx, cy] = '.'

        # 记录上一步的推动信息(垂直特殊推动)
        self.last_push_info = None
        if move_type == 'special' and direction[0] != 0:
            pushed_piece_final_pos = (x + 2 * direction[0], y + 2 * direction[1])
            self.last_push_info = {
                'pushed_piece_final_pos': pushed_piece_final_pos,
                'pushed_direction': direction,
                'from_player': self.current_player
            }

        # 记录游戏状态
        self.last_positions.append(self.get_state_key())
        self.game_history.append((
            self.current_player,
            (x, y),
            direction,
            move_type,
            np.copy(self.board),
            self.center_counts.copy()
        ))

        # 检查游戏结束条件
        winner = self.find_winner()
        if winner != -1:
            return winner

        if self.is_draw():
            return 2  # 平局

        # 切换到下一个玩家
        self.current_player = 1 - self.current_player
        self.move_count += 1
        return None

    def simulate_game(self, max_moves=1000):
        """模拟完整游戏"""
        self.reset_game()
        result = None

        for _ in range(max_moves):
            result = self.make_move()
            if result is not None:
                break

        if result is None:
            return 2  # 平局
        return result

    def visualize_board(self, piece_colors=None):
        """可视化棋盘"""
        reset_color = '\033[0m'
        center_color = '\033[93m'  # 中心点颜色 (黄色)
        default_color = reset_color

        player_char = 'A' if self.current_player == 0 else 'B'

        # 显示中心点计数
        print(f"中心点计数: A={self.center_counts[0]}/{self.win_count}, B={self.center_counts[1]}/{self.win_count}")

        # 显示棋盘
        for i, row in enumerate(self.board):
            for j, cell in enumerate(row):
                if cell == 'A' or cell == 'B':
                    if piece_colors and (i, j) in piece_colors:
                        color_code = piece_colors[(i, j)]
                    elif piece_colors is None:
                        color_code = '\033[91m' if cell == 'A' else '\033[94m'
                    elif cell == player_char:
                        color_code = '\033[91m' if self.current_player == 0 else '\033[94m'
                    else:
                        color_code = '\033[90m'  # 对手颜色

                    print(f"{color_code}●{reset_color}", end=" ")
                elif (i, j) == self.center:
                    print(f"{center_color}★{reset_color}", end=" ")
                else:
                    print("·", end=" ")
            print()

        player_colors = {
            0: '\033[91mA\033[0m',
            1: '\033[94mB\033[0m'
        }


def show_rules():
    """显示简化后的游戏规则"""
    os.system('cls' if os.name == 'nt' else 'clear')
    print("推推棋游戏规则")
    print("=" * 40)
    print("1. 目标:先将1个棋子送入中心点(★)者获胜")
    print()
    print("2. 棋盘布局:")
    print(f"   - 7行×5列棋盘,底部行是A方(红●),顶部行是B方(蓝●)")  # 修改尺寸说明
    print("   - 中心位置标记为★")
    print()
    print("3. 移动方式:")
    print("   ① 普通推动:向相邻空位推自己的棋,会一直移动到遇障碍为止")
    print("   ② 特殊推动:")
    print("      - 水平推(左/右):只能推相邻的自己的棋,被推棋前进一格")
    print("      - 垂直推(上/下):只能推相邻的对手的棋,被推棋前进一格")
    print()
    print("4. 特殊规则:")
    print("   - 棋子进入中心点后会被移除,同时增加对应玩家计数")
    print("   - 被垂直推动的棋子,下一回合不能被反方向推回")
    print("   - 连续3次重复局面或双方无合法移动均判为平局")
    print("=" * 40)

    # 显示初始棋盘
    print("\n初始棋盘状态:")
    game = PushGame()
    game.visualize_board()

    input("\n按任意键返回主菜单...")


def interactive_game():
    """交互式游戏"""
    game = PushGame()
    direction_symbols = {
        (0, 1): '→',
        (1, 0): '↓',
        (0, -1): '←',
        (-1, 0): '↑'
    }

    # 不同棋子的颜色集合
    piece_colors = [
        '\033[91m', '\033[92m', '\033[93m', '\033[94m', 
        '\033[95m', '\033[96m', '\033[97m', '\033[31m', 
        '\033[32m', '\033[33m'
    ]
    reset_color = '\033[0m'

    print(f"欢迎来到推推棋游戏! 棋盘大小: {game.rows}行×{game.cols}列")
    print("操作说明:")
    print("- 输入移动编号选择要执行的操作")
    print("- 输入 'exit' 可随时退出游戏")
    print("- 移动类型:普通(→↓←↑)、特殊(会标注)")

    # 显示初始棋盘
    print(f"\n{game.rows}行×{game.cols}列棋盘初始状态:")
    game.visualize_board()
    input("\n按回车键开始游戏...")

    while True:  # 外层循环用于多局游戏
        game = PushGame()
        exit_flag = False

        while True:  # 内层循环用于单局游戏
            # 清屏并显示棋盘
            os.system('cls' if os.name == 'nt' else 'clear')
            
            # 显示当前棋盘信息
            print(f"棋盘大小: {game.rows}行×{game.cols}列 | 获胜所需中心点: {game.win_count}")

            # 获取所有合法移动
            valid_moves = game.get_valid_moves()

            # 创建棋子颜色映射字典
            color_map = {}
            if valid_moves:
                piece_positions = set((x, y) for x, y, _, _ in valid_moves)
                sorted_pieces = sorted(piece_positions, key=lambda pos: (pos[0], pos[1]))

                # 为每个可移动棋子分配颜色
                for i, pos in enumerate(sorted_pieces):
                    color_index = i % len(piece_colors)
                    color_map[pos] = piece_colors[color_index]

            # 显示棋盘
            game.visualize_board(piece_colors=color_map)

            if not valid_moves:
                print("无合法移动! 游戏结束")
                break

            # 按棋子分组移动选项
            moves_by_piece = {}
            for move in valid_moves:
                x, y, direction, move_type = move
                piece_key = (x, y)
                if piece_key not in moves_by_piece:
                    moves_by_piece[piece_key] = []
                moves_by_piece[piece_key].append((direction, move_type))

            # 显示合法移动
            print("\n可移动选项:")
            move_counter = 1
            move_map = {}
            color_index = 0

            # 按位置排序棋子
            sorted_pieces = sorted(moves_by_piece.keys(), key=lambda pos: (pos[0], pos[1]))

            for piece in sorted_pieces:
                x, y = piece
                color_code = piece_colors[color_index % len(piece_colors)]
                color_index += 1

                # 打印棋子标题
                print(f"{color_code}棋子 {color_index}{reset_color} 的移动:")

                # 获取并排序该棋子的移动选项
                directions = moves_by_piece[piece]
                sorted_directions = sorted(directions, key=lambda d: d[0])

                # 打印移动选项
                for direction, move_type in sorted_directions:
                    dir_symbol = direction_symbols[direction]
                    move_type_str = "特殊" if move_type == 'special' else "普通"
                    move_map[move_counter] = (x, y, direction, move_type)

                    print(f"  {color_code}{move_counter}. {dir_symbol} {move_type_str}{reset_color}")
                    move_counter += 1
                print()  # 添加空行分隔

            # 获取玩家输入
            player_char = 'A' if game.current_player == 0 else 'B'
            player_color = '\033[91m' if game.current_player == 0 else '\033[94m'
            user_input = input(
                f"\n{player_color}玩家 {player_char}{reset_color} 的回合 (输入编号): ").strip().lower()

            if user_input == 'exit':
                exit_flag = True
                break

            # 处理输入
            if user_input.isdigit():
                move_index = int(user_input)
                if move_index in move_map:
                    move = move_map[move_index]
                else:
                    print(f"无效编号: {move_index}!")
                    time.sleep(1)
                    continue
            else:
                print("请输入有效编号!")
                time.sleep(1)
                continue

            # 执行移动
            result = game.make_move(move)

            if result == 0:
                os.system('cls' if os.name == 'nt' else 'clear')
                game.visualize_board()
                print("\033[91m玩家 A 获胜!\033[0m")
                break
            elif result == 1:
                os.system('cls' if os.name == 'nt' else 'clear')
                game.visualize_board()
                print("\033[94m玩家 B 获胜!\033[0m")
                break
            elif result == 2:
                os.system('cls' if os.name == 'nt' else 'clear')
                game.visualize_board()
                print("平局!")
                break

        if exit_flag:
            break  # 完全退出游戏

        # 询问是否再来一局
        replay = input("\n再来一局? (y/n): ").strip().lower()
        if replay != 'y':
            break


if __name__ == "__main__":
    while True:
        os.system('cls' if os.name == 'nt' else 'clear')
        print("推推棋游戏")
        print("1. 开始游戏")
        print("2. 游戏规则")
        print("3. 退出")

        choice = input("\n请选择 (1-3): ").strip()

        if choice == '1':
            interactive_game()
        elif choice == '2':
            show_rules()
        elif choice == '3':
            print("退出程序")
            break
        else:
            print("无效选择,请重新输入")
            time.sleep(1)

哈基米'棋'?.html

严格来说不是棋,一时兴起之作,属实是哈基米视频看多了想搞个电子哈基米来哈基哈基一下。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>哈基米棋</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Arial Rounded MT Bold', 'Arial', sans-serif;
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            color: #333;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
        }
        
        .header {
            text-align: center;
            margin-bottom: 20px;
            width: 100%;
        }
        
        h1 {
            color: #ff6b6b;
            font-size: 2.8rem;
            margin-bottom: 10px;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
        }
        
        .subtitle {
            color: #4a4a4a;
            font-size: 1.2rem;
            margin-bottom: 20px;
        }
        
        .game-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 20px;
            max-width: 100%;
        }
        
        .board-container {
            position: relative;
            margin-bottom: 20px;
        }
        
        .turn-counter {
            font-size: 1.5rem;
            font-weight: bold;
            color: #5D4037;
            margin-bottom: 15px;
            text-align: center;
            background-color: rgba(255, 255, 255, 0.8);
            padding: 10px 20px;
            border-radius: 50px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }
        
        .record-display {
            font-size: 1.2rem;
            font-weight: bold;
            color: #4CAF50;
            margin-bottom: 15px;
            text-align: center;
            background-color: rgba(255, 255, 255, 0.8);
            padding: 8px 16px;
            border-radius: 50px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }
        
        .board {
            display: grid;
            grid-template-columns: repeat(17, 40px);
            grid-template-rows: repeat(17, 40px);
            gap: 1px;
            background-color: #8BC34A;
            border: 3px solid #5D4037;
            border-radius: 5px;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
            overflow: hidden;
            position: relative;
        }
        
        .cell {
            width: 40px;
            height: 40px;
            background-color: #AED581;
            display: flex;
            justify-content: center;
            align-items: center;
            cursor: pointer;
            transition: background-color 0.2s;
            position: relative;
        }
        
        .cell:hover {
            background-color: #9CCC65;
        }
        
        .cell.disabled {
            cursor: not-allowed;
            background-color: #CCCCCC;
        }
        
        .cell.disabled:hover {
            background-color: #CCCCCC;
        }
        
        .cell.valid-cucumber {
            background-color: #C8E6C9;
        }
        
        .cell.valid-cucumber:hover {
            background-color: #A5D6A7;
        }
        
        .cat, .cucumber {
            width: 32px;
            height: 32px;
            border-radius: 50%;
            background-size: contain;
            background-repeat: no-repeat;
            background-position: center;
            transition: all 0.3s ease;
            z-index: 2;
            position: relative;
        }
        
        .cat {
            background-image: url('cat_icon.png');
            background-color: #FFC107;
            box-shadow: 0 0 8px rgba(255, 193, 7, 0.7);
        }
        
        .cat.moving {
            background-image: url('cat_ha.png');
            animation: pulse 0.5s infinite alternate;
        }
        
        .cucumber {
            background-image: url('cucumber_icon.png');
            background-color: #4CAF50;
            box-shadow: 0 0 5px rgba(76, 175, 80, 0.5);
        }
        
        .cucumber.red {
            background-color: #F44336;
            animation: fadeOut 0.5s forwards;
        }
        
        .cucumber.exploding {
            background-color: #FF9800;
            animation: explode 0.5s forwards;
        }
        
        .cucumber.crazy {
            background-image: url('crazy.png');
            background-color: #FF5722;
            animation: crazy 0.8s forwards;
        }
        
        /* 箭头尾迹样式 */
        .trail {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 1;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        
        .trail-arrow {
            width: 0;
            height: 0;
            border-style: solid;
            position: absolute;
        }
        
        .trail-1 {
            opacity: 0.9;
        }
        
        .trail-2 {
            opacity: 0.7;
        }
        
        .trail-3 {
            opacity: 0.5;
        }
        
        .trail-4 {
            opacity: 0.3;
        }
        
        .trail-5 {
            opacity: 0.2;
        }
        
        /* 方向箭头 */
        .arrow-up {
            border-width: 0 8px 12px 8px;
            border-color: transparent transparent #FF9800 transparent;
            top: 5px;
        }
        
        .arrow-down {
            border-width: 12px 8px 0 8px;
            border-color: #FF9800 transparent transparent transparent;
            bottom: 5px;
        }
        
        .arrow-left {
            border-width: 8px 12px 8px 0;
            border-color: transparent #FF9800 transparent transparent;
            left: 5px;
        }
        
        .arrow-right {
            border-width: 8px 0 8px 12px;
            border-color: transparent transparent transparent #FF9800;
            right: 5px;
        }
        
        .arrow-up-left {
            border-width: 0 0 12px 12px;
            border-color: transparent transparent #FF9800 transparent;
            top: 5px;
            left: 5px;
        }
        
        .arrow-up-right {
            border-width: 0 12px 12px 0;
            border-color: transparent transparent #FF9800 transparent;
            top: 5px;
            right: 5px;
        }
        
        .arrow-down-left {
            border-width: 12px 0 0 12px;
            border-color: transparent transparent transparent #FF9800;
            bottom: 5px;
            left: 5px;
        }
        
        .arrow-down-right {
            border-width: 12px 12px 0 0;
            border-color: transparent #FF9800 transparent transparent;
            bottom: 5px;
            right: 5px;
        }
        
        @keyframes fadeOut {
            to {
                opacity: 0;
                transform: scale(0.5);
            }
        }
        
        @keyframes explode {
            0% {
                transform: scale(1);
                opacity: 1;
            }
            50% {
                transform: scale(1.5);
                opacity: 0.7;
            }
            100% {
                transform: scale(0.5);
                opacity: 0;
            }
        }
        
        @keyframes crazy {
            0% {
                transform: scale(1);
                opacity: 1;
            }
            50% {
                transform: scale(1.5);
                opacity: 0.7;
            }
            100% {
                transform: scale(0.5);
                opacity: 0;
            }
        }
        
        @keyframes pulse {
            from {
                transform: scale(1);
            }
            to {
                transform: scale(1.1);
            }
        }
        
        .controls {
            display: flex;
            gap: 15px;
            margin-bottom: 20px;
            flex-wrap: wrap;
            justify-content: center;
        }
        
        button {
            padding: 12px 25px;
            font-size: 1rem;
            border: none;
            border-radius: 50px;
            cursor: pointer;
            transition: all 0.3s ease;
            font-weight: bold;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }
        
        #start-btn {
            background-color: #4CAF50;
            color: white;
        }
        
        #start-btn:hover {
            background-color: #45a049;
            transform: translateY(-2px);
        }
        
        #start-btn:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
            transform: none;
        }
        
        #end-btn {
            background-color: #f44336;
            color: white;
        }
        
        #end-btn:hover {
            background-color: #d32f2f;
            transform: translateY(-2px);
        }
        
        #rules-btn {
            background-color: #2196F3;
            color: white;
        }
        
        #rules-btn:hover {
            background-color: #0b7dda;
            transform: translateY(-2px);
        }
        
        #record-btn {
            background-color: #9C27B0;
            color: white;
        }
        
        #record-btn:hover {
            background-color: #7B1FA2;
            transform: translateY(-2px);
        }
        
        #reset-record-btn {
            background-color: #FF9800;
            color: white;
        }
        
        #reset-record-btn:hover {
            background-color: #F57C00;
            transform: translateY(-2px);
        }
        
        #trail-toggle-btn {
            background-color: #607D8B;
            color: white;
        }
        
        #trail-toggle-btn:hover {
            background-color: #455A64;
            transform: translateY(-2px);
        }
        
        .rules-modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            z-index: 1000;
            justify-content: center;
            align-items: center;
        }
        
        .rules-content {
            background-color: white;
            padding: 30px;
            border-radius: 15px;
            max-width: 600px;
            width: 90%;
            max-height: 80vh;
            overflow-y: auto;
            box-shadow: 0 5px 25px rgba(0, 0, 0, 0.3);
        }
        
        .rules-content h2 {
            color: #ff6b6b;
            margin-bottom: 20px;
            text-align: center;
            font-size: 1.8rem;
        }
        
        .rules-content h3 {
            color: #4CAF50;
            margin: 15px 0 10px;
        }
        
        .rules-content p, .rules-content ul {
            margin-bottom: 15px;
            line-height: 1.6;
        }
        
        .rules-content ul {
            padding-left: 20px;
        }
        
        .rules-content li {
            margin-bottom: 8px;
        }
        
        .close-btn {
            display: block;
            margin: 20px auto 0;
            padding: 10px 25px;
            background-color: #ff6b6b;
            color: white;
            border: none;
            border-radius: 50px;
            cursor: pointer;
            font-weight: bold;
            transition: background-color 0.3s;
        }
        
        .close-btn:hover {
            background-color: #ff5252;
        }
        
        .cat-message {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: #ff6b6b;
            padding: 5px 10px;
            font-weight: bold;
            font-size: 1.5rem;
            opacity: 0;
            transition: opacity 0.3s;
            z-index: 100;
            text-align: center;
            pointer-events: none;
            text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
            background-color: transparent;
            border-radius: 0;
            box-shadow: none;
        }
        
        .cat-message.show {
            opacity: 1;
        }
        
        .game-over-modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            z-index: 1000;
            justify-content: center;
            align-items: center;
        }
        
        .game-over-content {
            background-color: white;
            padding: 40px;
            border-radius: 15px;
            max-width: 500px;
            width: 90%;
            text-align: center;
            box-shadow: 0 5px 25px rgba(0, 0, 0, 0.3);
        }
        
        .game-over-content h2 {
            color: #ff6b6b;
            margin-bottom: 20px;
            font-size: 2.5rem;
        }
        
        .game-over-content p {
            font-size: 1.5rem;
            margin-bottom: 30px;
            color: #333;
        }
        
        @media (max-width: 700px) {
            .board {
                grid-template-columns: repeat(17, 25px);
                grid-template-rows: repeat(17, 25px);
            }
            
            .cell {
                width: 25px;
                height: 25px;
            }
            
            .cat, .cucumber {
                width: 20px;
                height: 20px;
            }
            
            /* 移动端箭头大小调整 */
            .arrow-up, .arrow-down {
                border-width: 0 5px 8px 5px;
            }
            
            .arrow-left, .arrow-right {
                border-width: 5px 8px 5px 0;
            }
            
            .arrow-up-left, .arrow-up-right, .arrow-down-left, .arrow-down-right {
                border-width: 0 0 8px 8px;
            }
            
            .cat-message {
                font-size: 1.2rem;
                padding: 3px 8px;
            }
            
            .controls {
                flex-direction: column;
                align-items: center;
            }
            
            button {
                width: 200px;
            }
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>哈基米棋</h1>
        <p class="subtitle">挑战你的策略,阻止哈基米到达边界!</p>
    </div>
    
    <div class="game-container">
        <div class="board-container">
            <div class="turn-counter" id="turn-counter">存活回合数: 0</div>
            <div class="record-display" id="record-display">最高纪录: 0 回合</div>
            <div class="cat-message" id="cat-message"></div>
            <div class="board" id="board"></div>
        </div>
        
        <div class="controls">
            <button id="start-btn">开始游戏</button>
            <button id="end-btn">结束游戏</button>
            <button id="rules-btn">游戏规则</button>
            <button id="record-btn">查看纪录</button>
            <button id="reset-record-btn">重置纪录</button>
            <button id="trail-toggle-btn">隐藏尾迹</button>
        </div>
    </div>
    
    <div class="rules-modal" id="rules-modal">
        <div class="rules-content">
            <h2>哈基米棋游戏规则</h2>
            
            <h3>游戏目标</h3>
            <p>阻止哈基米到达棋盘边界,同时尽可能多地保持回合数。</p>
            
            <h3>游戏规则</h3>
            <ul>
                <li>哈基米出生于中央!</li>
                <li>你只能在哈基米周围8格内放置黄瓜!</li>
                <li>如果哈基米周围有黄瓜,哈基米就会拍碎它!
                    <ul>
                        <li>黄瓜被拍散了,但是在两侧生成两个新黄瓜!</li>
                        <li>哈基米应激跑向向黄瓜相反的方向!</li>
                    </ul>
                </li>
                <li>哈基米直接碰到黄瓜,就会吃掉它,然后把周围的黄瓜都炸掉!</li>
                <li>哈基米会持续哈气,直到周围没有一根黄瓜!</li>
                <li>你只能在哈基米停止哈气后,放下一根黄瓜!</li>
            </ul>
            
            <h3>哈基米的特殊哈压库:</h3>
            <ul>
                <li>①连续5次,哈基米仅腾挪1格就碰上黄瓜,触发超哈气!第6次会无视黄瓜移动2格!</li>
                <li>②哈基米连续3回合中,每回合都仅拍了一次黄瓜就停止移动,触发超哈气!下一回合的黄瓜会被直接吃掉!</li>
            </ul>
            
            <button class="close-btn" id="close-rules">关闭</button>
        </div>
    </div>
    
    <div class="game-over-modal" id="game-over-modal">
        <div class="game-over-content">
            <h2>游戏结束</h2>
            <p id="game-over-message">哈基米吃掉了你的叮咚鸡,你共支撑了0回合!</p>
            <button class="close-btn" id="close-game-over">确定</button>
        </div>
    </div>

    <script>
        // 游戏状态变量
        let gameActive = false;
        let catPosition = { x: 8, y: 8 };
        let cucumbers = [];
        let currentTurn = 0;
        let catMoveCount = 0;
        let catSpeed = 500; // 初始移动速度(毫秒)
        let baseSpeed = 500;
        let oneMoveTriggers = 0; // 记录连续移动1格就触发黄瓜判断的次数
        let consecutiveSingleHitTurns = 0; // 记录连续单拍回合数
        let isCatMoving = false; // 标记哈基米是否正在移动
        let catSound = new Audio('catsound.wav');
        let backgroundMusic = new Audio('catmusic.wav');
        backgroundMusic.loop = true;
        let hitCountThisTurn = 0; // 当前回合拍黄瓜的次数
        let isSpecialRule5Active = false; // 标记规则⑤是否激活
        let isForceMove2 = false; // 标记是否强制移动2格
        let highScore = 0; // 最高纪录
        
        // 新增变量:跟踪连续移动1格就触发拍黄瓜的次数
        let consecutiveOneMoveHits = 0;
        
        // 新增变量:尾迹系统
        let catTrail = []; // 存储哈基米移动路径和方向
        let showTrail = true; // 是否显示尾迹
        
        // DOM元素
        const board = document.getElementById('board');
        const turnCounter = document.getElementById('turn-counter');
        const recordDisplay = document.getElementById('record-display');
        const catMessage = document.getElementById('cat-message');
        const startBtn = document.getElementById('start-btn');
        const endBtn = document.getElementById('end-btn');
        const rulesBtn = document.getElementById('rules-btn');
        const recordBtn = document.getElementById('record-btn');
        const resetRecordBtn = document.getElementById('reset-record-btn');
        const trailToggleBtn = document.getElementById('trail-toggle-btn');
        const rulesModal = document.getElementById('rules-modal');
        const closeRules = document.getElementById('close-rules');
        const gameOverModal = document.getElementById('game-over-modal');
        const gameOverMessage = document.getElementById('game-over-message');
        const closeGameOver = document.getElementById('close-game-over');
        
        // 检查位置是否在哈基米周围
        function isInCatAdjacent(x, y) {
            return Math.abs(x - catPosition.x) <= 1 && Math.abs(y - catPosition.y) <= 1;
        }
        
        // 更新可放置黄瓜的格子高亮
        function updateValidCucumberCells() {
            // 清除所有高亮
            document.querySelectorAll('.cell.valid-cucumber').forEach(cell => {
                cell.classList.remove('valid-cucumber');
            });
            
            // 如果不是游戏进行中或哈基米在移动,不显示高亮
            if (!gameActive || isCatMoving) return;
            
            // 高亮显示可放置黄瓜的格子
            for (let y = 0; y < 17; y++) {
                for (let x = 0; x < 17; x++) {
                    if (isInCatAdjacent(x, y) && 
                        !(x === catPosition.x && y === catPosition.y) &&
                        !cucumbers.some(c => c.x === x && c.y === y)) {
                        const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
                        if (cell) {
                            cell.classList.add('valid-cucumber');
                        }
                    }
                }
            }
        }
        
        // 初始化纪录
        function initializeRecord() {
            // 从localStorage加载纪录
            const savedRecord = localStorage.getItem('hacatmiHighScore');
            if (savedRecord !== null) {
                highScore = parseInt(savedRecord);
            }
            updateRecordDisplay();
        }
        
        // 更新纪录显示
        function updateRecordDisplay() {
            recordDisplay.textContent = `最高纪录: ${highScore} 回合`;
        }
        
        // 检查并更新纪录
        function checkAndUpdateRecord() {
            if (currentTurn > highScore) {
                highScore = currentTurn;
                localStorage.setItem('hacatmiHighScore', highScore);
                updateRecordDisplay();
                return true;
            }
            return false;
        }
        
        // 显示纪录信息
        function showRecordInfo() {
            if (highScore === 0) {
                showCatMessage("暂无纪录,加油创造吧!");
            } else {
                showCatMessage(`当前最高纪录: ${highScore} 回合`);
            }
        }
        
        // 重置纪录
        function resetRecord() {
            if (confirm("确定要重置最高纪录吗?")) {
                highScore = 0;
                localStorage.setItem('hacatmiHighScore', highScore);
                updateRecordDisplay();
                showCatMessage("纪录已重置");
            }
        }
        
        // 切换尾迹显示
        function toggleTrail() {
            showTrail = !showTrail;
            trailToggleBtn.textContent = showTrail ? "隐藏尾迹" : "显示尾迹";
            
            if (!showTrail) {
                clearTrail();
            } else {
                updateTrail();
            }
        }
        
        // 添加尾迹
        function addTrail(x, y, direction) {
            if (!showTrail) return;
            
            // 限制尾迹长度为5
            if (catTrail.length >= 5) {
                catTrail.shift();
            }
            
            // 添加新位置和方向到尾迹
            catTrail.push({ x, y, direction });
            
            // 更新尾迹显示
            updateTrail();
        }
        
        // 获取箭头方向类名
        function getArrowClass(dx, dy) {
            if (dx === 0 && dy === -1) return 'arrow-up';
            if (dx === 0 && dy === 1) return 'arrow-down';
            if (dx === -1 && dy === 0) return 'arrow-left';
            if (dx === 1 && dy === 0) return 'arrow-right';
            if (dx === 1 && dy === -1) return 'arrow-up-right';
            if (dx === 1 && dy === 1) return 'arrow-down-right';
            if (dx === -1 && dy === -1) return 'arrow-up-left';
            if (dx === -1 && dy === 1) return 'arrow-down-left';
            return 'arrow-up'; // 默认
        }
        
        // 更新尾迹显示
        function updateTrail() {
            if (!showTrail) return;
            
            // 清除所有尾迹
            document.querySelectorAll('.trail').forEach(trail => {
                trail.remove();
            });
            
            // 添加尾迹
            catTrail.forEach((pos, index) => {
                const cell = document.querySelector(`.cell[data-x="${pos.x}"][data-y="${pos.y}"]`);
                if (cell) {
                    const trail = document.createElement('div');
                    trail.className = `trail trail-${index + 1}`;
                    
                    const arrow = document.createElement('div');
                    arrow.className = `trail-arrow ${getArrowClass(pos.direction.dx, pos.direction.dy)}`;
                    
                    trail.appendChild(arrow);
                    cell.appendChild(trail);
                }
            });
        }
        
        // 清除尾迹
        function clearTrail() {
            catTrail = [];
            document.querySelectorAll('.trail').forEach(trail => {
                trail.remove();
            });
        }
        
        // 初始化棋盘
        function initializeBoard() {
            board.innerHTML = '';
            for (let y = 0; y < 17; y++) {
                for (let x = 0; x < 17; x++) {
                    const cell = document.createElement('div');
                    cell.className = 'cell';
                    cell.dataset.x = x;
                    cell.dataset.y = y;
                    
                    // 放置哈基米
                    if (x === catPosition.x && y === catPosition.y) {
                        const cat = document.createElement('div');
                        cat.className = 'cat';
                        cell.appendChild(cat);
                    }
                    
                    cell.addEventListener('click', () => placeCucumber(x, y));
                    board.appendChild(cell);
                }
            }
            
            // 更新可放置黄瓜的格子
            updateValidCucumberCells();
        }
        
        // 放置黄瓜
        function placeCucumber(x, y) {
            if (!gameActive || isCatMoving) return;
            
            // 检查是否在哈基米周围
            if (!isInCatAdjacent(x, y)) {
                showCatMessage("只能放在哈基米周围!");
                return;
            }
            
            // 检查位置是否有效
            if (x === catPosition.x && y === catPosition.y) {
                showCatMessage("不能放在哈基米的位置!");
                return;
            }
            
            // 检查是否已有黄瓜
            if (cucumbers.some(c => c.x === x && c.y === y)) {
                showCatMessage("这里已经有黄瓜了!");
                return;
            }
            
            // 清除尾迹
            clearTrail();
            
            // 重置当前回合状态
            hitCountThisTurn = 0;
            
            // 添加黄瓜
            cucumbers.push({ x, y });
            updateBoard();
            
            // 黄瓜回合结束,哈基米行动
            currentTurn++;
            updateTurnCounter();
            
            // 检查黄瓜是否在哈基米周围
            const isAdjacent = Math.abs(x - catPosition.x) <= 1 && Math.abs(y - catPosition.y) <= 1;
            
            // 检查是否触发连续单拍特殊规则(规则⑤)
            if (isAdjacent && consecutiveSingleHitTurns >= 3) {
                // 触发特殊规则:直接吃掉黄瓜
                isSpecialRule5Active = true;
                showCatMessage("别哈把我基米住!");
                playCatSound();
                
                // 移除黄瓜
                cucumbers = cucumbers.filter(c => !(c.x === x && c.y === y));
                updateBoard();
                
                // 吃掉黄瓜,触发规则④
                eatCucumberAndMove(x, y);
                return;
            }
            
            if (isAdjacent) {
                // 黄瓜在哈基米周围
                hitCountThisTurn++;
                showCatMessage("哈!");
                playCatSound();
                
                // 黄瓜变红并消失
                const cucumberCell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"] .cucumber`);
                cucumberCell.classList.add('red');
                
                // 计算分裂方向
                const dx = x - catPosition.x;
                const dy = y - catPosition.y;
                
                // 移除原黄瓜
                setTimeout(() => {
                    cucumbers = cucumbers.filter(c => !(c.x === x && c.y === y));
                    
                    // 计算分裂位置 - 修正分裂逻辑
                    let splitPositions = [];
                    
                    if (dx === 0) {
                        // 垂直方向:分裂到左右
                        splitPositions.push({ x: x - 1, y: y });
                        splitPositions.push({ x: x + 1, y: y });
                    } else if (dy === 0) {
                        // 水平方向:分裂到上下
                        splitPositions.push({ x: x, y: y - 1 });
                        splitPositions.push({ x: x, y: y + 1 });
                    } else {
                        // 对角线方向:分裂到垂直两侧
                        splitPositions.push({ x: x - dy, y: y + dx });
                        splitPositions.push({ x: x + dy, y: y - dx });
                    }
                    
                    // 添加分裂的黄瓜(如果在棋盘内且没有其他黄瓜)
                    splitPositions.forEach(pos => {
                        if (isValidPosition(pos.x, pos.y) && !cucumbers.some(c => c.x === pos.x && c.y === pos.y)) {
                            cucumbers.push(pos);
                        }
                    });
                    
                    // 检查是否触发特殊规则①
                    if (consecutiveOneMoveHits >= 5) {
                        // 触发特殊规则①:强制移动2格
                        showCatMessage("别哈把我基米住!");
                        isForceMove2 = true;
                        consecutiveOneMoveHits = 0;
                        
                        // 强制移动2格,一格一格移动
                        moveCat(-dx, -dy, 2, true);
                    } else {
                        // 正常移动 - 向相反方向移动2格
                        moveCat(-dx, -dy, 2);
                    }
                    
                    updateBoard();
                }, 500);
            } else {
                // 黄瓜不在哈基米周围,哈基米向最近边界移动
                moveToNearestBoundary();
            }
        }
        
        // 吃掉黄瓜并炸掉周围的黄瓜(修改后的规则)
        function eatCucumberAndMove(x, y) {
            isCatMoving = true;
            disableBoard();
            
            // 显示爆炸消息
            showCatMessage("轰!黄瓜爆炸了!");
            
            // 收集要炸掉的黄瓜(包括被吃的黄瓜和周围的黄瓜)
            const cucumbersToExplode = [];
            
            // 添加被吃的黄瓜
            cucumbersToExplode.push({ x, y });
            
            // 添加周围8格内的黄瓜
            for (let dx = -1; dx <= 1; dx++) {
                for (let dy = -1; dy <= 1; dy++) {
                    if (dx === 0 && dy === 0) continue; // 跳过自己
                    
                    const nx = x + dx;
                    const ny = y + dy;
                    
                    if (isValidPosition(nx, ny)) {
                        // 检查这个位置是否有黄瓜
                        const cucumber = cucumbers.find(c => c.x === nx && c.y === ny);
                        if (cucumber) {
                            cucumbersToExplode.push(cucumber);
                        }
                    }
                }
            }
            
            // 为每个被炸的黄瓜播放音效和动画
            cucumbersToExplode.forEach((cucumber, index) => {
                setTimeout(() => {
                    // 播放爆炸音效
                    const bombSound = new Audio('bomb.wav');
                    bombSound.play().catch(e => console.log("爆炸音效播放失败:", e));
                    
                    // 替换为crazy图标
                    const cucumberCell = document.querySelector(`.cell[data-x="${cucumber.x}"][data-y="${cucumber.y}"] .cucumber`);
                    if (cucumberCell) {
                        cucumberCell.classList.add('crazy');
                    }
                }, index * 100); // 每个黄瓜间隔100毫秒播放音效和动画
            });
            
            // 移除所有被炸的黄瓜
            setTimeout(() => {
                cucumbers = cucumbers.filter(c => 
                    !cucumbersToExplode.some(explodeCucumber => 
                        explodeCucumber.x === c.x && explodeCucumber.y === c.y
                    )
                );
                
                // 移动哈基米到黄瓜位置
                catPosition.x = x;
                catPosition.y = y;
                updateBoard();
                
                // 强制向最近边界移动2格
                setTimeout(() => {
                    moveToNearestBoundary(true); // true表示这是吃掉黄瓜后的强制移动
                }, 500);
            }, cucumbersToExplode.length * 100 + 300); // 等待所有音效和动画播放完毕
        }
        
        // 检查位置是否有效
        function isValidPosition(x, y) {
            return x >= 0 && x < 17 && y >= 0 && y < 17;
        }
        
        // 哈基米移动 - 修改为每移动一格就进行判定
        function moveCat(dx, dy, steps, isForceMove = false) {
            if (!gameActive) return;
            
            isCatMoving = true;
            disableBoard();
            
            // 设置哈基米为移动状态
            updateCatImage(true);
            
            let remainingSteps = steps;
            let currentStep = 0;
            
            const moveStep = () => {
                if (remainingSteps <= 0) {
                    // 移动完成,检查是否继续行动
                    checkCucumberAfterMove();
                    return;
                }
                
                // 如果是强制移动2格,则进行特殊处理
                if (isForceMove2 && remainingSteps === steps) {
                    // 强制移动2格,每格都进行判定但不中断移动
                    const stepDx = dx;
                    const stepDy = dy;
                    
                    // 第一步移动
                    const newX1 = catPosition.x + stepDx;
                    const newY1 = catPosition.y + stepDy;
                    
                    // 检查第一步是否到达边界
                    if (!isValidPosition(newX1, newY1)) {
                        gameOver("哈基米吃掉了你的叮咚鸡,你共支撑了" + currentTurn + "回合!");
                        return;
                    }
                    
                    // 添加尾迹
                    addTrail(catPosition.x, catPosition.y, { dx: stepDx, dy: stepDy });
                    
                    // 移动哈基米到第一步位置
                    catPosition.x = newX1;
                    catPosition.y = newY1;
                    
                    // 更新棋盘
                    updateBoard();
                    
                    // 检查第一步是否碰到黄瓜
                    const cucumberIndex1 = cucumbers.findIndex(c => c.x === newX1 && c.y === newY1);
                    if (cucumberIndex1 !== -1) {
                        // 吃掉黄瓜并触发爆炸(但不中断移动)
                        const eatenCucumber = cucumbers[cucumberIndex1];
                        
                        // 显示爆炸消息
                        showCatMessage("轰!黄瓜爆炸了!");
                        
                        // 收集要炸掉的黄瓜(包括被吃的黄瓜和周围的黄瓜)
                        const cucumbersToExplode = [];
                        
                        // 添加被吃的黄瓜
                        cucumbersToExplode.push(eatenCucumber);
                        
                        // 添加周围8格内的黄瓜
                        for (let dx = -1; dx <= 1; dx++) {
                            for (let dy = -1; dy <= 1; dy++) {
                                if (dx === 0 && dy === 0) continue; // 跳过自己
                                
                                const nx = eatenCucumber.x + dx;
                                const ny = eatenCucumber.y + dy;
                                
                                if (isValidPosition(nx, ny)) {
                                    // 检查这个位置是否有黄瓜
                                    const cucumber = cucumbers.find(c => c.x === nx && c.y === ny);
                                    if (cucumber) {
                                        cucumbersToExplode.push(cucumber);
                                    }
                                }
                            }
                        }
                        
                        // 为每个被炸的黄瓜播放音效和动画
                        cucumbersToExplode.forEach((cucumber, index) => {
                            setTimeout(() => {
                                // 播放爆炸音效
                                const bombSound = new Audio('bomb.wav');
                                bombSound.play().catch(e => console.log("爆炸音效播放失败:", e));
                                
                                // 替换为crazy图标
                                const cucumberCell = document.querySelector(`.cell[data-x="${cucumber.x}"][data-y="${cucumber.y}"] .cucumber`);
                                if (cucumberCell) {
                                    cucumberCell.classList.add('crazy');
                                }
                            }, index * 100);
                        });
                        
                        // 移除所有被炸的黄瓜
                        setTimeout(() => {
                            cucumbers = cucumbers.filter(c => 
                                !cucumbersToExplode.some(explodeCucumber => 
                                    explodeCucumber.x === c.x && explodeCucumber.y === c.y
                                )
                            );
                            updateBoard();
                        }, cucumbersToExplode.length * 100 + 300);
                    }
                    
                    remainingSteps--;
                    currentStep++;
                    
                    // 第二步移动
                    setTimeout(() => {
                        const newX2 = catPosition.x + stepDx;
                        const newY2 = catPosition.y + stepDy;
                        
                        // 检查第二步是否到达边界
                        if (!isValidPosition(newX2, newY2)) {
                            gameOver("哈基米吃掉了你的叮咚鸡,你共支撑了" + currentTurn + "回合!");
                            return;
                        }
                        
                        // 添加尾迹
                        addTrail(catPosition.x, catPosition.y, { dx: stepDx, dy: stepDy });
                        
                        // 移动哈基米到第二步位置
                        catPosition.x = newX2;
                        catPosition.y = newY2;
                        
                        // 更新棋盘
                        updateBoard();
                        
                        // 检查第二步是否碰到黄瓜
                        const cucumberIndex2 = cucumbers.findIndex(c => c.x === newX2 && c.y === newY2);
                        if (cucumberIndex2 !== -1) {
                            // 吃掉黄瓜并触发爆炸(但不中断移动)
                            const eatenCucumber = cucumbers[cucumberIndex2];
                            
                            // 显示爆炸消息
                            showCatMessage("轰!黄瓜爆炸了!");
                            
                            // 收集要炸掉的黄瓜(包括被吃的黄瓜和周围的黄瓜)
                            const cucumbersToExplode = [];
                            
                            // 添加被吃的黄瓜
                            cucumbersToExplode.push(eatenCucumber);
                            
                            // 添加周围8格内的黄瓜
                            for (let dx = -1; dx <= 1; dx++) {
                                for (let dy = -1; dy <= 1; dy++) {
                                    if (dx === 0 && dy === 0) continue; // 跳过自己
                                    
                                    const nx = eatenCucumber.x + dx;
                                    const ny = eatenCucumber.y + dy;
                                    
                                    if (isValidPosition(nx, ny)) {
                                        // 检查这个位置是否有黄瓜
                                        const cucumber = cucumbers.find(c => c.x === nx && c.y === ny);
                                        if (cucumber) {
                                            cucumbersToExplode.push(cucumber);
                                        }
                                    }
                                }
                            }
                            
                            // 为每个被炸的黄瓜播放音效和动画
                            cucumbersToExplode.forEach((cucumber, index) => {
                                setTimeout(() => {
                                    // 播放爆炸音效
                                    const bombSound = new Audio('bomb.wav');
                                    bombSound.play().catch(e => console.log("爆炸音效播放失败:", e));
                                    
                                    // 替换为crazy图标
                                    const cucumberCell = document.querySelector(`.cell[data-x="${cucumber.x}"][data-y="${cucumber.y}"] .cucumber`);
                                    if (cucumberCell) {
                                        cucumberCell.classList.add('crazy');
                                    }
                                }, index * 100);
                            });
                            
                            // 移除所有被炸的黄瓜
                            setTimeout(() => {
                                cucumbers = cucumbers.filter(c => 
                                    !cucumbersToExplode.some(explodeCucumber => 
                                        explodeCucumber.x === c.x && explodeCucumber.y === c.y
                                    )
                                );
                                updateBoard();
                                
                                // 完成强制移动后,重置标志并检查周围黄瓜
                                isForceMove2 = false;
                                remainingSteps = 0;
                                setTimeout(() => {
                                    checkCucumberAfterMove();
                                }, 500);
                            }, cucumbersToExplode.length * 100 + 300);
                        } else {
                            // 完成强制移动后,重置标志并检查周围黄瓜
                            isForceMove2 = false;
                            remainingSteps = 0;
                            setTimeout(() => {
                                checkCucumberAfterMove();
                            }, catSpeed);
                        }
                    }, catSpeed);
                    
                    return;
                } else {
                    // 正常移动,每移动一格都进行判定
                    const newX = catPosition.x + dx;
                    const newY = catPosition.y + dy;
                    
                    // 检查是否到达边界
                    if (!isValidPosition(newX, newY)) {
                        gameOver("哈基米吃掉了你的叮咚鸡,你共支撑了" + currentTurn + "回合!");
                        return;
                    }
                    
                    // 添加尾迹
                    addTrail(catPosition.x, catPosition.y, { dx, dy });
                    
                    // 移动哈基米
                    catPosition.x = newX;
                    catPosition.y = newY;
                    
                    // 更新棋盘
                    updateBoard();
                    
                    // 检查是否碰到黄瓜(规则④ - 修改为炸掉周围的黄瓜)
                    const cucumberIndex = cucumbers.findIndex(c => c.x === newX && c.y === newY);
                    if (cucumberIndex !== -1) {
                        // 吃掉黄瓜并炸掉周围的黄瓜
                        const eatenCucumber = cucumbers[cucumberIndex];
                        
                        // 显示爆炸消息
                        showCatMessage("轰!黄瓜爆炸了!");
                        
                        // 收集要炸掉的黄瓜(包括被吃的黄瓜和周围的黄瓜)
                        const cucumbersToExplode = [];
                        
                        // 添加被吃的黄瓜
                        cucumbersToExplode.push(eatenCucumber);
                        
                        // 添加周围8格内的黄瓜
                        for (let dx = -1; dx <= 1; dx++) {
                            for (let dy = -1; dy <= 1; dy++) {
                                if (dx === 0 && dy === 0) continue; // 跳过自己
                                
                                const nx = eatenCucumber.x + dx;
                                const ny = eatenCucumber.y + dy;
                                
                                if (isValidPosition(nx, ny)) {
                                    // 检查这个位置是否有黄瓜
                                    const cucumber = cucumbers.find(c => c.x === nx && c.y === ny);
                                    if (cucumber) {
                                        cucumbersToExplode.push(cucumber);
                                    }
                                }
                            }
                        }
                        
                        // 为每个被炸的黄瓜播放音效和动画
                        cucumbersToExplode.forEach((cucumber, index) => {
                            setTimeout(() => {
                                // 播放爆炸音效
                                const bombSound = new Audio('bomb.wav');
                                bombSound.play().catch(e => console.log("爆炸音效播放失败:", e));
                                
                                // 替换为crazy图标
                                const cucumberCell = document.querySelector(`.cell[data-x="${cucumber.x}"][data-y="${cucumber.y}"] .cucumber`);
                                if (cucumberCell) {
                                    cucumberCell.classList.add('crazy');
                                }
                            }, index * 100);
                        });
                        
                        // 移除所有被炸的黄瓜
                        setTimeout(() => {
                            cucumbers = cucumbers.filter(c => 
                                !cucumbersToExplode.some(explodeCucumber => 
                                    explodeCucumber.x === c.x && explodeCucumber.y === c.y
                                )
                            );
                            
                            updateBoard();
                            
                            // 强制向最近边界移动2格
                            moveToNearestBoundary(true);
                        }, cucumbersToExplode.length * 100 + 300);
                        return;
                    }
                    
                    remainingSteps--;
                    currentStep++;
                }
                
                // 调整速度 - 移动越来越快(增强加速效果)
                // 从500ms开始,每步减少80ms,最低50ms
                catSpeed = Math.max(50, baseSpeed - (currentStep * 80));
                
                // 检查是否需要立即判定周围黄瓜
                if (remainingSteps > 0 && !isForceMove2) {
                    // 检查哈基米周围是否有黄瓜
                    const adjacentCucumbers = cucumbers.filter(c => 
                        Math.abs(c.x - catPosition.x) <= 1 && Math.abs(c.y - catPosition.y) <= 1
                    );
                    
                    if (adjacentCucumbers.length > 0) {
                        // 有黄瓜在周围,立即进行拍黄瓜判定
                        const selectedCucumber = selectOptimalCucumber(adjacentCucumbers);
                        
                        if (selectedCucumber) {
                            // 记录连续移动1格就触发拍黄瓜
                            consecutiveOneMoveHits++;
                            
                            hitCountThisTurn++;
                            
                            const dx = selectedCucumber.x - catPosition.x;
                            const dy = selectedCucumber.y - catPosition.y;
                            
                            showCatMessage("哈!");
                            playCatSound();
                            
                            // 黄瓜变红并消失
                            const cucumberCell = document.querySelector(`.cell[data-x="${selectedCucumber.x}"][data-y="${selectedCucumber.y}"] .cucumber`);
                            cucumberCell.classList.add('red');
                            
                            // 移除原黄瓜
                            setTimeout(() => {
                                cucumbers = cucumbers.filter(c => !(c.x === selectedCucumber.x && c.y === selectedCucumber.y));
                                
                                // 计算分裂位置 - 修正分裂逻辑
                                let splitPositions = [];
                                
                                if (dx === 0) {
                                    // 垂直方向:分裂到左右
                                    splitPositions.push({ x: selectedCucumber.x - 1, y: selectedCucumber.y });
                                    splitPositions.push({ x: selectedCucumber.x + 1, y: selectedCucumber.y });
                                } else if (dy === 0) {
                                    // 水平方向:分裂到上下
                                    splitPositions.push({ x: selectedCucumber.x, y: selectedCucumber.y - 1 });
                                    splitPositions.push({ x: selectedCucumber.x, y: selectedCucumber.y + 1 });
                                } else {
                                    // 对角线方向:分裂到垂直两侧
                                    splitPositions.push({ x: selectedCucumber.x - dy, y: selectedCucumber.y + dx });
                                    splitPositions.push({ x: selectedCucumber.x + dy, y: selectedCucumber.y - dx });
                                }
                                
                                // 添加分裂的黄瓜(如果在棋盘内且没有其他黄瓜)
                                splitPositions.forEach(pos => {
                                    if (isValidPosition(pos.x, pos.y) && !cucumbers.some(c => c.x === pos.x && c.y === pos.y)) {
                                        cucumbers.push(pos);
                                    }
                                });
                                
                                // 检查是否触发特殊规则①
                                if (consecutiveOneMoveHits >= 5) {
                                    // 触发特殊规则①:强制移动2格
                                    showCatMessage("别哈把我基米住!");
                                    isForceMove2 = true;
                                    consecutiveOneMoveHits = 0;
                                    
                                    // 强制移动2格,进行特殊处理
                                    moveCat(-dx, -dy, 2, true);
                                } else {
                                    // 哈基米移动
                                    moveCat(-dx, -dy, 2);
                                }
                                
                                updateBoard();
                            }, 500);
                            return;
                        }
                    } else {
                        // 没有触发拍黄瓜,重置连续移动1格计数
                        consecutiveOneMoveHits = 0;
                    }
                }
                
                // 继续移动
                setTimeout(moveStep, catSpeed);
            };
            
            moveStep();
        }
        
        // 向最近边界移动
        function moveToNearestBoundary(isEatingMove = false) {
            // 计算到各边界的距离
            const distances = {
                top: catPosition.y,
                bottom: 16 - catPosition.y,
                left: catPosition.x,
                right: 16 - catPosition.x
            };
            
            // 找到最近边界
            const minDistance = Math.min(...Object.values(distances));
            const nearestBoundaries = Object.keys(distances).filter(b => distances[b] === minDistance);
            
            // 随机选择一个最近边界
            const randomBoundary = nearestBoundaries[Math.floor(Math.random() * nearestBoundaries.length)];
            
            let dx = 0, dy = 0;
            
            switch (randomBoundary) {
                case 'top': dy = -1; break;
                case 'bottom': dy = 1; break;
                case 'left': dx = -1; break;
                case 'right': dx = 1; break;
            }
            
            // 检查特殊规则
            let steps = 2;
            if (isEatingMove) {
                steps = 2; // 规则④:强制移动2格
            }
            
            moveCat(dx, dy, steps, isEatingMove);
        }
        
        // 移动后检查黄瓜
        function checkCucumberAfterMove() {
            // 检查哈基米周围是否有黄瓜
            const adjacentCucumbers = cucumbers.filter(c => 
                Math.abs(c.x - catPosition.x) <= 1 && Math.abs(c.y - catPosition.y) <= 1
            );
            
            if (adjacentCucumbers.length > 0) {
                // 有黄瓜在周围,继续行动
                // 选择最有利于到达边界的黄瓜
                const selectedCucumber = selectOptimalCucumber(adjacentCucumbers);
                
                if (selectedCucumber) {
                    // 记录连续移动1格就触发拍黄瓜
                    consecutiveOneMoveHits++;
                    
                    hitCountThisTurn++;
                    
                    const dx = selectedCucumber.x - catPosition.x;
                    const dy = selectedCucumber.y - catPosition.y;
                    
                    showCatMessage("哈!");
                    playCatSound();
                    
                    // 黄瓜变红并消失
                    const cucumberCell = document.querySelector(`.cell[data-x="${selectedCucumber.x}"][data-y="${selectedCucumber.y}"] .cucumber`);
                    cucumberCell.classList.add('red');
                    
                    // 移除原黄瓜
                    setTimeout(() => {
                        cucumbers = cucumbers.filter(c => !(c.x === selectedCucumber.x && c.y === selectedCucumber.y));
                        
                        // 计算分裂位置 - 修正分裂逻辑
                        let splitPositions = [];
                        
                        if (dx === 0) {
                            // 垂直方向:分裂到左右
                            splitPositions.push({ x: selectedCucumber.x - 1, y: selectedCucumber.y });
                            splitPositions.push({ x: selectedCucumber.x + 1, y: selectedCucumber.y });
                        } else if (dy === 0) {
                            // 水平方向:分裂到上下
                            splitPositions.push({ x: selectedCucumber.x, y: selectedCucumber.y - 1 });
                            splitPositions.push({ x: selectedCucumber.x, y: selectedCucumber.y + 1 });
                        } else {
                            // 对角线方向:分裂到垂直两侧
                            splitPositions.push({ x: selectedCucumber.x - dy, y: selectedCucumber.y + dx });
                            splitPositions.push({ x: selectedCucumber.x + dy, y: selectedCucumber.y - dx });
                        }
                        
                        // 添加分裂的黄瓜(如果在棋盘内且没有其他黄瓜)
                        splitPositions.forEach(pos => {
                            if (isValidPosition(pos.x, pos.y) && !cucumbers.some(c => c.x === pos.x && c.y === pos.y)) {
                                cucumbers.push(pos);
                            }
                        });
                        
                        // 检查是否触发特殊规则①
                        if (consecutiveOneMoveHits >= 5) {
                            // 触发特殊规则①:强制移动2格
                            showCatMessage("别哈把我基米住!");
                            isForceMove2 = true;
                            consecutiveOneMoveHits = 0;
                            
                            // 强制移动2格,一格一格移动
                            moveCat(-dx, -dy, 2, true);
                        } else {
                            // 哈基米移动
                            moveCat(-dx, -dy, 2);
                        }
                        
                        updateBoard();
                    }, 500);
                }
            } else {
                // 周围没有黄瓜,停止行动
                catSpeed = baseSpeed; // 重置速度
                
                // 重置连续移动1格计数
                consecutiveOneMoveHits = 0;
                
                // 更新连续单拍回合计数(规则⑤)
                if (hitCountThisTurn === 1) {
                    consecutiveSingleHitTurns++;
                    
                    if (consecutiveSingleHitTurns >= 3) {
                        showCatMessage("警告:连续单拍3回合!");
                    }
                } else {
                    consecutiveSingleHitTurns = 0;
                }

                // 规则⑤触发后,在停止行动后重置规则⑤状态
                if (isSpecialRule5Active) {
                    isSpecialRule5Active = false;
                    consecutiveSingleHitTurns = 0; // 重置连续单拍计数
                }
                
                // 允许玩家放置黄瓜
                isCatMoving = false;
                
                // 设置哈基米为静止状态
                updateCatImage(false);
                
                enableBoard();
                
                // 更新可放置黄瓜的格子
                updateValidCucumberCells();
                
                // 清除尾迹
                clearTrail();
            }
        }
        
        // 更新哈基米图片
        function updateCatImage(isMoving) {
            const catCell = document.querySelector(`.cell[data-x="${catPosition.x}"][data-y="${catPosition.y}"] .cat`);
            if (catCell) {
                if (isMoving) {
                    catCell.classList.add('moving');
                } else {
                    catCell.classList.remove('moving');
                }
            }
        }
        
        // 选择最有利于到达边界的黄瓜
        function selectOptimalCucumber(adjacentCucumbers) {
            // 简化实现:随机选择一个
            return adjacentCucumbers[Math.floor(Math.random() * adjacentCucumbers.length)];
        }
        
        // 更新棋盘显示
        function updateBoard() {
            // 清除所有单元格内容
            document.querySelectorAll('.cell').forEach(cell => {
                // 保留尾迹元素
                const trails = cell.querySelectorAll('.trail');
                cell.innerHTML = '';
                trails.forEach(trail => cell.appendChild(trail));
            });
            
            // 放置哈基米
            const catCell = document.querySelector(`.cell[data-x="${catPosition.x}"][data-y="${catPosition.y}"]`);
            const cat = document.createElement('div');
            cat.className = 'cat';
            if (isCatMoving) {
                cat.classList.add('moving');
            }
            catCell.appendChild(cat);
            
            // 放置黄瓜
            cucumbers.forEach(cucumber => {
                const cucumberCell = document.querySelector(`.cell[data-x="${cucumber.x}"][data-y="${cucumber.y}"]`);
                const cucumberElement = document.createElement('div');
                cucumberElement.className = 'cucumber';
                cucumberCell.appendChild(cucumberElement);
            });
            
            // 更新可放置黄瓜的格子
            updateValidCucumberCells();
        }
        
        // 更新回合计数器
        function updateTurnCounter() {
            turnCounter.textContent = `存活回合数: ${currentTurn}`;
        }
        
        // 禁用棋盘(哈基米移动时)
        function disableBoard() {
            document.querySelectorAll('.cell').forEach(cell => {
                cell.classList.add('disabled');
                cell.classList.remove('valid-cucumber');
            });
        }
        
        // 启用棋盘(哈基米停止移动时)
        function enableBoard() {
            document.querySelectorAll('.cell').forEach(cell => {
                cell.classList.remove('disabled');
            });
            
            // 更新可放置黄瓜的格子
            updateValidCucumberCells();
        }
        
        // 显示哈基米消息
        function showCatMessage(message) {
            catMessage.textContent = message;
            catMessage.classList.add('show');
            
            setTimeout(() => {
                catMessage.classList.remove('show');
            }, 2000);
        }
        
        // 播放哈基米声音
        function playCatSound() {
            catSound.currentTime = 0;
            catSound.play().catch(e => console.log("音频播放失败:", e));
        }
        
        // 游戏结束
        function gameOver(message) {
            gameActive = false;
            gameOverMessage.textContent = message;
            backgroundMusic.pause();
            showCatMessage("游戏结束!");
            isCatMoving = false;
            
            // 设置哈基米为静止状态
            updateCatImage(false);
            
            disableBoard();
            
            // 检查并更新纪录
            const isNewRecord = checkAndUpdateRecord();
            if (isNewRecord) {
                setTimeout(() => {
                    showCatMessage("恭喜!新纪录诞生!");
                }, 1500);
            }
            
            // 清除尾迹
            clearTrail();
            
            // 显示游戏结束弹窗
            setTimeout(() => {
                gameOverModal.style.display = 'flex';
            }, 1000);
        }
        
        // 开始游戏
        function startGame() {
            if (gameActive) return;
            
            // 重置游戏状态
            gameActive = true;
            catPosition = { x: 8, y: 8 };
            cucumbers = [];
            currentTurn = 0;
            catMoveCount = 0;
            catSpeed = baseSpeed;
            oneMoveTriggers = 0;
            consecutiveSingleHitTurns = 0;
            consecutiveOneMoveHits = 0; // 重置连续移动1格计数
            isCatMoving = false;
            hitCountThisTurn = 0;
            isSpecialRule5Active = false;
            isForceMove2 = false;
            
            // 清除尾迹
            clearTrail();
            
            // 初始化棋盘
            initializeBoard();
            updateTurnCounter();
            
            // 播放背景音乐
            backgroundMusic.play().catch(e => console.log("背景音乐播放失败:", e));
            
            showCatMessage("游戏开始!黄瓜先手");
        }
        
        // 结束游戏
        function endGame() {
            gameActive = false;
            backgroundMusic.pause();
            showCatMessage("游戏已结束");
            isCatMoving = false;
            
            // 设置哈基米为静止状态
            updateCatImage(false);
            
            disableBoard();
            
            // 清除尾迹
            clearTrail();
        }
        
        // 显示规则
        function showRules() {
            rulesModal.style.display = 'flex';
        }
        
        // 隐藏规则
        function hideRules() {
            rulesModal.style.display = 'none';
        }
        
        // 隐藏游戏结束弹窗
        function hideGameOver() {
            gameOverModal.style.display = 'none';
        }
        
        // 事件监听
        startBtn.addEventListener('click', startGame);
        endBtn.addEventListener('click', endGame);
        rulesBtn.addEventListener('click', showRules);
        recordBtn.addEventListener('click', showRecordInfo);
        resetRecordBtn.addEventListener('click', resetRecord);
        trailToggleBtn.addEventListener('click', toggleTrail);
        closeRules.addEventListener('click', hideRules);
        closeGameOver.addEventListener('click', hideGameOver);
        
        // 初始化
        initializeBoard();
        initializeRecord();
    </script>
</body>
</html>

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值