import turtle
import math
# Set up the screen
screen = [Link]()
[Link]("black")
[Link]("Lunar Eclipse Simulation")
[Link](800, 600)
[Link](0) # Turn off auto-update for better performance
# Speed control variables
ANIMATION_SPEED = 0.1 # Adjust this value to change speed (1 = slow, 5 = fast)
FRAME_DELAY = 30 // ANIMATION_SPEED # Adjust delay based on speed
# Create turtles
sun = [Link]()
earth = [Link]()
moon = [Link]()
shadow = [Link]()
# Configure all turtles at once
for t in [sun, earth, moon, shadow]:
[Link]("circle")
[Link]()
[Link](0)
# Set individual properties
[Link]("yellow")
[Link](3)
[Link](-200, 0)
[Link]("blue")
[Link](2)
[Link](0, 0)
[Link]("lightgray")
[Link](1.5)
[Link]("black")
[Link](2.2)
[Link](0, 0)
# Create label turtles once (more efficient)
labels = {}
label_turtles = []
def create_label(name, x, y, color="white", font_size=12, bold=True):
"""Create a single label turtle"""
label = [Link]()
[Link](color)
[Link]()
[Link](x, y)
[Link]()
label_turtles.append(label)
labels[name] = label
return label
# Create all labels at once
create_label("sun_label", -200, -50, "white", 12).write("SUN", align="center",
font=("Arial", 12, "bold"))
create_label("earth_label", 0, -40, "white", 12).write("EARTH", align="center",
font=("Arial", 12, "bold"))
create_label("shadow_label", 0, 40, "gray", 10).write("EARTH'S SHADOW",
align="center", font=("Arial", 10, "bold"))
create_label("title", 0, 250, "yellow", 16).write("LUNAR ECLIPSE SIMULATION",
align="center", font=("Arial", 16, "bold"))
create_label("instructions", 0, -280, "lightblue", 10).write(
f"Speed: {ANIMATION_SPEED}x | Watch Moon pass through Earth's shadow → turns
red", align="center", font=("Arial", 10, "normal")
)
# Moon label (will be updated)
moon_label = create_label("moon", 150, 0, "white", 10)
moon_label.write("MOON", align="center", font=("Arial", 10, "bold"))
# Status label (will be updated)
status_label = create_label("status", 0, 220, "white", 14)
# Speed info label
speed_label = create_label("speed_info", 300, 250, "cyan", 10)
speed_label.write(f"Speed: {ANIMATION_SPEED}x", align="center", font=("Arial", 10,
"bold"))
# Draw orbit once
orbit = [Link]()
[Link]("white")
[Link]()
[Link](0, -150)
[Link]()
[Link](150)
[Link]()
# Animation variables
angle = 0
eclipse_occurring = False
eclipse_progress = 0
status_messages = {
"normal": ("Moon Orbiting Normally", "white"),
"started": ("ECLIPSE STARTED!", "orange"),
"total": ("TOTAL LUNAR ECLIPSE", "red"),
"ended": ("ECLIPSE ENDED", "lightgreen")
}
def update_status(status_key):
"""Update status display efficiently"""
message, color = status_messages[status_key]
status_label.clear()
status_label.color(color)
status_label.write(message, align="center", font=("Arial", 14, "bold"))
def update_moon_label(x, y):
"""Update moon label position efficiently"""
moon_label.clear()
moon_label.goto(x, y - 30)
moon_label.write("MOON", align="center", font=("Arial", 10, "bold"))
# Main animation loop
while True:
# Calculate moon position - angle increment based on speed
angle_increment = ANIMATION_SPEED * 1 # Base speed multiplied by our speed
factor
moon_x = 150 * [Link]([Link](angle))
moon_y = 150 * [Link]([Link](angle))
[Link](moon_x, moon_y)
# Update moon label position
update_moon_label(moon_x, moon_y)
# Check for eclipse conditions
if 160 < angle < 200: # Eclipse range
if not eclipse_occurring:
eclipse_occurring = True
eclipse_progress = 0
update_status("started")
# Gradually change moon color - progress based on speed
eclipse_progress += ANIMATION_SPEED
red_value = max(0.1, 1 - (eclipse_progress / 50))
[Link]((red_value, red_value * 0.3, red_value * 0.1))
# Maximum eclipse
if eclipse_progress >= 50:
update_status("total")
else:
if eclipse_occurring:
eclipse_occurring = False
[Link]("lightgray")
update_status("ended")
elif angle % 30 == 0: # Only update status occasionally to reduce CPU
usage
update_status("normal")
# Update angle based on speed
angle = (angle + angle_increment) % 360
# Manual update for better performance
[Link]()
[Link](FRAME_DELAY)
# Keep window open
[Link]()