修改代码，优化植物、动物的繁殖位置逻辑，让新生植物或动物不再在地图上的随机位置生成，而是在繁殖中的生物位置 3x3 方格范围内生成。
```python
import tkinter as tk
from tkinter import messagebox
import random
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

class Animal:
    def init(self, energy, x, y, age=0):
        self.energy = energy
        self.x = x
        self.y = y
        self.age = age  # 添加年龄属性

    def is_alive(self):
        return self.energy > 0

    def consume_energy(self, amount):
        self.energy -= amount

    def move(self, max_x, max_y):
        new_x = self.x + random.choice([-1, 1])
        new_y = self.y + random.choice([-1, 1])
        self.x = max(0, min(max_x - 1, new_x))
        self.y = max(0, min(max_y - 1, new_y))

    def act(self, targets, max_x, max_y):
        self.move(max_x, max_y)
        if self.energy >= self.breed_energy:
            choice = random.choice(["eat", "breed"])
        else:
            choice = "eat"
        if choice == "eat" and targets:
            self.eat(targets, max_x, max_y)
        elif choice == "breed":
            self.energy -= self.breed_energy
            return self.class(self.breed_energy, self.x, self.y)
        self.consume_energy(self.consume_rate)

    def eat(self, targets, max_x, max_y):
        for dx in [-1, 0, 1]:
            for dy in [-1, 0, 1]:
                nx, ny = (self.x + dx) % max_x, (self.y + dy) % max_y
                for target in targets:
                    if (nx, ny) == (target.x, target.y):
                        self.energy += self.eat_energy
                        targets.remove(target)
                        self.x, self.y = target.x, target.y
                        return

class Herbivore(Animal):
    breed_energy = 5
    eat_energy = 3
    consume_rate = 1

class Carnivore(Animal):
    breed_energy = 10
    eat_energy = 6
    consume_rate = 2

class Plant:
    def init(self, x, y):
        self.x = x
        self.y = y

def show_animal_details(animal):
    details = f"类型: {‘草食动物’ if isinstance(animal, Herbivore) else ‘肉食动物’}\n" <br/>              f"能量: {animal.energy}\n" <br/>              f"年龄: {animal.age}\n" <br/>              f"位置: ({animal.x}, {animal.y})"
    messagebox.showinfo("动物详情", details)

def add_entity(event, plants, herbivores, carnivores, canvas, max_x, max_y):
    cell_size = 20
    x, y = event.x // cell_size, event.y // cell_size

    menu = tk.Menu(root, tearoff=0)
    menu.add_command(label="添加植物", command=lambda: add_plant(x, y, plants, canvas))
    menu.add_command(label="添加草食动物", command=lambda: add_animal(x, y, Herbivore(5, x, y), herbivores, canvas))
    menu.add_command(label="添加肉食动物", command=lambda: add_animal(x, y, Carnivore(10, x, y), carnivores, canvas))
    menu.post(event.x_root, event.y_root)

def add_plant(x, y, plants, canvas):
    plants.append(Plant(x, y))
    draw_map(canvas, plants, [], [], 20, 20)

def add_animal(x, y, animal, animals, canvas):
    animals.append(animal)
    draw_map(canvas, [], animals if isinstance(animal, Herbivore) else [], animals if isinstance(animal, Carnivore) else [], 20, 20)

def simulate_round(herbivores, carnivores, plants, max_x, max_y):
    for animal_list, act_target in [
        (herbivores, plants), (carnivores, herbivores)
    ]:
        for i in range(len(animal_list) - 1, -1, -1):
            baby = animal_list[i].act(act_target, max_x, max_y)
            if baby:
                animal_list.append(baby)
            if not animal_list[i].is_alive():
                del animal_list[i]

def ecosystem_simulation(rounds, num_plants, num_herbivores, num_carnivores, canvas, max_x, max_y, chart_frame, root):
    plants = [Plant(random.randint(0, max_x-1), random.randint(0, max_y-1)) for _ in range(num_plants)]
    herbivores = [Herbivore(5, random.randint(0, max_x-1), random.randint(0, max_y-1)) for _ in range(num_herbivores)]
    carnivores = [Carnivore(10, random.randint(0, max_x-1), random.randint(0, max_y-1)) for _ in range(num_carnivores)]

    herbivores_data = []
    carnivores_data = []
    rounds_data = []

    def simulate_and_update(round):
        if round >= rounds:
            messagebox.showinfo("Simulation", "Simulation ended.")
            return

        simulate_round(herbivores, carnivores, plants, max_x, max_y)
        draw_map(canvas, plants, herbivores, carnivores, max_x, max_y)

        plant_growth = random.randint(3, 5)
        for _ in range(plant_growth):
            plants.append(Plant(random.randint(0, max_x-1), random.randint(0, max_y-1)))

        herbivores_data.append(len(herbivores))
        carnivores_data.append(len(carnivores))
        rounds_data.append(round + 1)

        update_chart(chart_frame, rounds_data, herbivores_data, carnivores_data)

        if not herbivores and not carnivores:
            messagebox.showinfo("Simulation", "All animals died.")
            return

        root.after(250, lambda: simulate_and_update(round + 1))

    simulate_and_update(0)

def draw_map(canvas, plants, herbivores, carnivores, max_x, max_y):
    canvas.delete("plants")
    canvas.delete("herbivores")
    canvas.delete("carnivores")

    cell_size = 20
    for plant in plants:
        x1, y1 = plant.x * cell_size, plant.y * cell_size
        x2, y2 = x1 + cell_size, y1 + cell_size
        canvas.create_rectangle(x1, y1, x2, y2, fill="green", tags="plants")

    for herbivore in herbivores:
        x1, y1 = herbivore.x * cell_size, herbivore.y * cell_size
        x2, y2 = x1 + cell_size, y1 + cell_size
        oval = canvas.create_oval(x1, y1, x2, y2, fill="blue", tags="herbivores")
        text = canvas.create_text(x1 + cell_size / 2, y1 + cell_size / 2, text=str(herbivore.energy), fill="white", tags="herbivores")

        canvas.tag_bind(oval, ‘<Button-1>’, lambda e, h=herbivore: show_animal_details(h))
        canvas.tag_bind(text, ‘<Button-1>’, lambda e, h=herbivore: show_animal_details(h))
    
    for carnivore in carnivores:
        x1, y1 = carnivore.x * cell_size, carnivore.y * cell_size
        x2, y2 = x1 + cell_size, y1 + cell_size
        oval = canvas.create_oval(x1, y1, x2, y2, fill="red", tags="carnivores")
        text = canvas.create_text(x1 + cell_size / 2, y1 + cell_size / 2, text=str(carnivore.energy), fill="white", tags="carnivores")

        canvas.tag_bind(oval, ‘<Button-1>’, lambda e, c=carnivore: show_animal_details©)
        canvas.tag_bind(text, ‘<Button-1>’, lambda e, c=carnivore: show_animal_details©)

    canvas.update()

def update_chart(chart_frame, rounds, herbivores_data, carnivores_data):
    for widget in chart_frame.winfo_children():
        widget.destroy()

    fig, ax = plt.subplots()
    ax.plot(rounds, herbivores_data, label=‘Herbivores’)
    ax.plot(rounds, carnivores_data, label=‘Carnivores’)
    ax.set_xlabel(‘Round’)
    ax.set_ylabel(‘Number of Animals’)
    ax.legend()

    chart = FigureCanvasTkAgg(fig, master=chart_frame)
    chart.draw()
    chart.get_tk_widget().pack()

def start_simulation():
    num_plants = int(plants_entry.get())
    num_herbivores = int(herbivores_entry.get())
    num_carnivores = int(carnivores_entry.get())
    ecosystem_simulation(500, num_plants, num_herbivores, num_carnivores, canvas, 20, 20, chart_frame, root)

root = tk.Tk()
root.title("生态系统模拟")

tk.Label(root, text="初始植物数量（基准值：40）：").grid(row=0, column=0)
plants_entry = tk.Entry(root)
plants_entry.grid(row=0, column=1)

tk.Label(root, text="初始食草动物数量（基准值：12）：").grid(row=1, column=0)
herbivores_entry = tk.Entry(root)
herbivores_entry.grid(row=1, column=1)

tk.Label(root, text="初始食肉动物数量（基准值：7）：").grid(row=2, column=0)
carnivores_entry = tk.Entry(root)
carnivores_entry.grid(row=2, column=1)

start_button = tk.Button(root, text="开始模拟", command=start_simulation)
start_button.grid(row=3, column=0, columnspan=2)

canvas = tk.Canvas(root, width=400, height=400, bg="white")
canvas.grid(row=4, column=0, columnspan=2)

chart_frame = tk.Frame(root)
chart_frame.grid(row=0, column=2, rowspan=5)

root.mainloop()
```