第28课:闰年判断器——学习闰年判断逻辑

🎯 本课目标

  • 理解闰年的概念和判断规则
  • 掌握复合条件判断的运用
  • 学会用逻辑运算符组合条件
  • 制作完整的闰年判断程序
  • 扩展制作日期计算工具

🤔 趣味引入:时间的"秘密"

想象一下:为什么有些年份会多出一天?

  • 🌍 地球绕太阳一圈需要365天5小时48分46秒
  • 📅 平年只有365天,每年多出约6小时
  • ⏰ 每4年累积约24小时,所以2月多一天
  • 🎯 但是!整百年份要能被400整除才算闰年

这就是闰年的"秘密"——让日历跟得上地球的脚步!

今天,让我们一起用Python揭开闰年的奥秘!


🔧 第一部分:闰年判断基础

1.1 什么是闰年?

# 闰年基本概念
print("🎯 认识闰年")
print("=" * 50)

print("""
📋 闰年判断规则:

第一条:能被4整除的年份是闰年
    例如:2020 ÷ 4 = 505(整除)→ 闰年 ✅

第二条:但不能被100整除
    例如:1900 ÷ 100 = 19(整除)→ 不是闰年 ❌

第三条:除非能被400整除
    例如:2000 ÷ 400 = 5(整除)→ 是闰年 ✅

总结规则:
    能被4整除 AND(不能被100整除 OR 能被400整除)
""")

# 简单判断示例
def is_leap_year_simple(year):
    """简单判断闰年"""
    if year % 4 == 0:
        if year % 100 == 0:
            if year % 400 == 0:
                return True
            else:
                return False
        else:
            return True
    else:
        return False

# 测试年份
test_years = [1900, 2000, 2020, 2023, 2024, 2100]

print("📋 闰年测试:")
print("-" * 40)
print(f"{'年份':>6} {'判断':>10} {'结果':>10}")
print("-" * 40)

for year in test_years:
    result = is_leap_year_simple(year)
    leap_text = "闰年 ✅" if result else "平年 ❌"
    print(f"{year:>6}年 {leap_text:>14}")

print("-" * 40)

1.2 优化闰年判断

# 优化闰年判断
print("\n📝 优化闰年判断")
print("=" * 50)

def is_leap_year_v1(year):
    """版本1:使用逻辑运算符"""
    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)

def is_leap_year_v2(year):
    """版本2:使用条件表达式"""
    return (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0)

def is_leap_year_v3(year):
    """版本3:使用calendar模块"""
    import calendar
    return calendar.isleap(year)

# 对比不同实现
print("📊 三种实现方式对比:")
print("-" * 50)

for year in [1900, 2000, 2020, 2024]:
    r1 = is_leap_year_v1(year)
    r2 = is_leap_year_v2(year)
    r3 = is_leap_year_v3(year)
    
    print(f"{year}年:v1={r1} v2={r2} v3={r3} 结果一致={r1==r2==r3}")

print("\n💡 推荐使用版本2:")
print("  return (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0)")
print("  既简洁又高效!")

📊 第二部分:闰年判断进阶

2.1 交互式闰年判断器

# 交互式闰年判断器
print("\n🎮 交互式闰年判断器")
print("=" * 50)

def get_leap_year_info(year):
    """获取闰年详细信息"""
    is_leap = is_leap_year_v2(year)
    
    info = {
        "year": year,
        "is_leap": is_leap,
        "days_in_year": 366 if is_leap else 365,
        "days_in_february": 29 if is_leap else 28,
        "next_leap": None,
        "previous_leap": None
    }
    
    # 查找下一个闰年
    next_year = year + 1
    while not is_leap_year_v2(next_year):
        next_year += 1
    info["next_leap"] = next_year
    
    # 查找上一个闰年
    prev_year = year - 1
    while prev_year > 0 and not is_leap_year_v2(prev_year):
        prev_year -= 1
    info["previous_leap"] = prev_year if prev_year > 0 else None
    
    return info

# 交互式查询
print("欢迎使用闰年判断器!")
print("=" * 40)

while True:
    try:
        year_input = input("\n请输入年份(输入0退出):")
        year = int(year_input)
        
        if year == 0:
            print("👋 再见!")
            break
        
        if year < 0:
            print("❌ 请输入公元后的年份!")
            continue
        
        info = get_leap_year_info(year)
        
        print(f"\n{'='*50}")
        print(f"{'📋 闰年分析报告':^50}")
        print(f"{'='*50}")
        
        if info["is_leap"]:
            print(f"\n✅ {year}年是闰年!")
            print(f"  全年有{info['days_in_year']}天")
            print(f"  2月有{info['days_in_february']}天")
        else:
            print(f"\n❌ {year}年是平年")
            print(f"  全年有{info['days_in_year']}天")
            print(f"  2月有{info['days_in_february']}天")
        
        print(f"\n📅 相邻闰年:")
        print(f"  上一个闰年:{info['previous_leap']}")
        print(f"  下一个闰年:{info['next_leap']}")
        
        # 计算间隔
        if info["is_leap"]:
            gap_to_next = info["next_leap"] - year
            gap_from_prev = year - info["previous_leap"]
            print(f"  距上一个闰年:{gap_from_prev}年")
            print(f"  距下一个闰年:{gap_to_next}年")
        
        # 特殊说明
        if year % 100 == 0 and year % 400 != 0:
            print(f"\n⚠️ 特殊说明:{year}是整百年份但不被400整除")
            print(f"  所以虽然是4的倍数,但不是闰年")
        
    except ValueError:
        print("❌ 请输入有效的年份!")

2.2 闰年区间查询

# 闰年区间查询
print("\n📈 闰年区间查询")
print("=" * 50)

def find_leap_years(start_year, end_year):
    """查找指定范围内的所有闰年"""
    leap_years = []
    
    for year in range(start_year, end_year + 1):
        if is_leap_year_v2(year):
            leap_years.append(year)
    
    return leap_years

def count_leap_years(start_year, end_year):
    """统计闰年数量"""
    leap_years = find_leap_years(start_year, end_year)
    return len(leap_years)

def get_leap_year_distribution(start_year, end_year):
    """获取闰年分布统计"""
    leap_years = find_leap_years(start_year, end_year)
    
    distribution = {
        "total_years": end_year - start_year + 1,
        "leap_count": len(leap_years),
        "normal_count": (end_year - start_year + 1) - len(leap_years),
        "leap_ratio": len(leap_years) / (end_year - start_year + 1) * 100,
        "first_leap": leap_years[0] if leap_years else None,
        "last_leap": leap_years[-1] if leap_years else None,
        "century_leaps": [],
        "decades": {}
    }
    
    # 统计整百年闰年
    for year in leap_years:
        if year % 100 == 0:
            distribution["century_leaps"].append(year)
    
    # 按年代统计
    for year in leap_years:
        decade = (year // 10) * 10
        if decade not in distribution["decades"]:
            distribution["decades"][decade] = []
        distribution["decades"][decade].append(year)
    
    return distribution

# 交互式区间查询
print("欢迎使用闰年区间查询系统!")
print("=" * 40)

try:
    start = int(input("起始年份:"))
    end = int(input("结束年份:"))
    
    if start > end:
        print("❌ 起始年份不能大于结束年份!")
    elif start < 0:
        print("❌ 请输入公元后的年份!")
    else:
        distribution = get_leap_year_distribution(start, end)
        
        print(f"\n{'='*60}")
        print(f"{'📊 闰年区间分析报告':^60}")
        print(f"{'='*60}")
        
        print(f"\n📅 统计区间:{start}年 - {end}年")
        print(f"📈 总年数:{distribution['total_years']}年")
        print(f"✅ 闰年数:{distribution['leap_count']}年")
        print(f"❌ 平年数:{distribution['normal_count']}年")
        print(f"📊 闰年占比:{distribution['leap_ratio']:.2f}%")
        
        if distribution['first_leap']:
            print(f"\n🔝 首个闰年:{distribution['first_leap']}年")
            print(f"🔚 末个闰年:{distribution['last_leap']}年")
        
        if distribution['century_leaps']:
            print(f"\n🏛️ 整百年闰年:")
            for year in distribution['century_leaps']:
                print(f"  {year}年(能被400整除的特殊闰年)")
        
        # 显示闰年列表
        leap_years = find_leap_years(start, end)
        if leap_years:
            print(f"\n📋 闰年列表:")
            # 每行显示10个
            for i in range(0, len(leap_years), 10):
                row = leap_years[i:i+10]
                print(f"  {'、'.join(str(y) for y in row)}")
        
        # 按年代显示
        print(f"\n📊 年代分布:")
        for decade in sorted(distribution['decades'].keys()):
            count = len(distribution['decades'][decade])
            bar = "█" * count
            print(f"  {decade}s:{bar} {count}个闰年")

except ValueError:
    print("❌ 请输入有效的年份!")

🎯 第三部分:日期计算应用

3.1 月份天数计算器

# 月份天数计算器
print("\n📅 月份天数计算器")
print("=" * 50)

def get_month_days(year, month):
    """获取某月的天数"""
    if month < 1 or month > 12:
        return None
    
    # 大月(31天)
    if month in [1, 3, 5, 7, 8, 10, 12]:
        return 31
    # 小月(30天)
    elif month in [4, 6, 9, 11]:
        return 30
    # 二月(特殊处理)
    elif month == 2:
        if is_leap_year_v2(year):
            return 29
        else:
            return 28

def get_month_name(month):
    """获取月份名称"""
    month_names = {
        1: "一月", 2: "二月", 3: "三月", 4: "四月",
        5: "五月", 6: "六月", 7: "七月", 8: "八月",
        9: "九月", 10: "十月", 11: "十一月", 12: "十二月"
    }
    return month_names.get(month, "未知月份")

# 交互式查询
print("欢迎使用月份天数计算器!")
print("=" * 40)

while True:
    try:
        year = int(input("\n请输入年份(输入0退出):"))
        if year == 0:
            print("👋 再见!")
            break
        
        month = int(input("请输入月份(1-12):"))
        
        if month < 1 or month > 12:
            print("❌ 月份应在1-12之间!")
            continue
        
        days = get_month_days(year, month)
        month_name = get_month_name(month)
        leap_text = "闰年" if is_leap_year_v2(year) else "平年"
        
        print(f"\n📋 查询结果:")
        print(f"  {year}年({leap_text})")
        print(f"  {month_name}共有{days}天")
        
        # 额外信息
        if month == 2:
            if days == 29:
                print(f"  💡 因为{year}年是闰年,所以2月有29天!")
            else:
                print(f"  💡 因为{year}年是平年,所以2月有28天!")
        
        # 季度信息
        if month <= 3:
            quarter = "第一季度"
        elif month <= 6:
            quarter = "第二季度"
        elif month <= 9:
            quarter = "第三季度"
        else:
            quarter = "第四季度"
        print(f"  📊 属于{quarter}")
        
    except ValueError:
        print("❌ 请输入有效的数字!")

3.2 日期计算器

# 日期计算器
print("\n📆 日期计算器")
print("=" * 50)

class DateCalculator:
    """日期计算器类"""
    
    def __init__(self):
        self.month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    
    def is_valid_date(self, year, month, day):
        """验证日期是否有效"""
        if month < 1 or month > 12:
            return False
        
        max_day = self.get_month_days(year, month)
        if day < 1 or day > max_day:
            return False
        
        return True
    
    def get_month_days(self, year, month):
        """获取某月天数"""
        if month == 2:
            return 29 if is_leap_year_v2(year) else 28
        return self.month_days[month - 1]
    
    def days_in_year(self, year):
        """计算一年的天数"""
        return 366 if is_leap_year_v2(year) else 365
    
    def day_of_year(self, year, month, day):
        """计算某天是当年的第几天"""
        total = 0
        for m in range(1, month):
            total += self.get_month_days(year, m)
        total += day
        return total
    
    def days_between(self, y1, m1, d1, y2, m2, d2):
        """计算两个日期之间的天数"""
        # 确保日期有效
        if not (self.is_valid_date(y1, m1, d1) and self.is_valid_date(y2, m2, d2)):
            return None
        
        # 如果第一个日期更大,交换并返回负值
        if (y1, m1, d1) > (y2, m2, d2):
            return -self.days_between(y2, m2, d2, y1, m1, d1)
        
        total_days = 0
        
        # 计算整年的天数
        for year in range(y1, y2):
            total_days += self.days_in_year(year)
        
        # 减去第一年已过的天数,加上第二年已过的天数
        total_days -= self.day_of_year(y1, m1, d1)
        total_days += self.day_of_year(y2, m2, d2)
        
        return total_days
    
    def get_season(self, month):
        """获取季节"""
        if month in [3, 4, 5]:
            return "春天 🌸"
        elif month in [6, 7, 8]:
            return "夏天 🌞"
        elif month in [9, 10, 11]:
            return "秋天 🍁"
        else:
            return "冬天 ❄️"
    
    def get_weekday_name(self, year, month, day):
        """获取星期几(使用蔡勒公式)"""
        if month < 3:
            month += 12
            year -= 1
        
        K = year % 100
        J = year // 100
        
        h = (day + (13 * (month + 1)) // 5 + K + K // 4 + J // 4 - 2 * J) % 7
        
        weekdays = ["星期六", "星期日", "星期一", "星期二", "星期三", "星期四", "星期五"]
        return weekdays[h]

# 使用日期计算器
calc = DateCalculator()

print("欢迎使用日期计算器!")
print("=" * 40)

while True:
    print("\n请选择功能:")
    print("1. 查询某天是当年第几天")
    print("2. 计算两个日期之间的天数")
    print("3. 查询某天的星期")
    print("4. 退出")
    
    choice = input("\n请选择(1-4):")
    
    if choice == "4":
        print("👋 再见!")
        break
    
    elif choice == "1":
        try:
            year = int(input("年份:"))
            month = int(input("月份:"))
            day = int(input("日期:"))
            
            if calc.is_valid_date(year, month, day):
                day_num = calc.day_of_year(year, month, day)
                total = calc.days_in_year(year)
                remaining = total - day_num
                season = calc.get_season(month)
                
                print(f"\n📋 查询结果:")
                print(f"  {year}年{month}月{day}日")
                print(f"  是当年的第{day_num}天")
                print(f"  当年还剩{remaining}天")
                print(f"  季节:{season}")
            else:
                print("❌ 无效的日期!")
        except ValueError:
            print("❌ 请输入有效的数字!")
    
    elif choice == "2":
        try:
            print("\n📅 第一个日期:")
            y1 = int(input("年份:"))
            m1 = int(input("月份:"))
            d1 = int(input("日期:"))
            
            print("\n📅 第二个日期:")
            y2 = int(input("年份:"))
            m2 = int(input("月份:"))
            d2 = int(input("日期:"))
            
            days = calc.days_between(y1, m1, d1, y2, m2, d2)
            
            if days is not None:
                if days >= 0:
                    print(f"\n📊 从{y1}年{m1}月{d1}日到{y2}年{m2}月{d2}日")
                    print(f"  相隔{days}天")
                    
                    # 换算成年月
                    years = days // 365
                    months = (days % 365) // 30
                    remaining_days = (days % 365) % 30
                    print(f"  约{years}年{months}个月{remaining_days}天")
                else:
                    print(f"\n📊 从{y2}年{m2}月{d2}日到{y1}年{m1}月{d1}日")
                    print(f"  相隔{-days}天")
            else:
                print("❌ 无效的日期!")
        except ValueError:
            print("❌ 请输入有效的数字!")
    
    elif choice == "3":
        try:
            year = int(input("年份:"))
            month = int(input("月份:"))
            day = int(input("日期:"))
            
            if calc.is_valid_date(year, month, day):
                weekday = calc.get_weekday_name(year, month, day)
                season = calc.get_season(month)
                
                print(f"\n📋 查询结果:")
                print(f"  {year}年{month}月{day}日是{weekday}")
                print(f"  季节:{season}")
            else:
                print("❌ 无效的日期!")
        except ValueError:
            print("❌ 请输入有效的数字!")
    
    else:
        print("❌ 请选择1-4!")

🎮 第四部分:闰年知识问答

4.1 闰年知识问答游戏

# 闰年知识问答游戏
print("\n🎮 闰年知识问答")
print("=" * 50)

import random

def create_quiz():
    """创建题库"""
    questions = [
        {
            "question": "地球绕太阳一圈需要多长时间?",
            "options": ["A. 365天", "B. 365天5小时", "C. 366天", "D. 364天"],
            "answer": "B",
            "explanation": "地球公转周期约为365天5小时48分46秒"
        },
        {
            "question": "闰年2月有多少天?",
            "options": ["A. 28天", "B. 29天", "C. 30天", "D. 31天"],
            "answer": "B",
            "explanation": "闰年2月有29天,平年只有28天"
        },
        {
            "question": "以下哪一年是闰年?",
            "options": ["A. 1900年", "B. 2000年", "C. 2100年", "D. 2200年"],
            "answer": "B",
            "explanation": "2000能被400整除,是闰年;其他整百年不能被400整除"
        },
        {
            "question": "为什么要有闰年?",
            "options": [
                "A. 为了让日历和季节同步",
                "B. 为了多放假一天",
                "C. 为了纪念某个事件",
                "D. 为了方便计算"
            ],
            "answer": "A",
            "explanation": "闰年是为了弥补地球公转周期与日历年的差异"
        },
        {
            "question": "闰年全年有多少天?",
            "options": ["A. 364天", "B. 365天", "C. 366天", "D. 367天"],
            "answer": "C",
            "explanation": "闰年有366天,比平年多一天"
        },
        {
            "question": "以下哪项不是闰年的判断条件?",
            "options": [
                "A. 能被4整除",
                "B. 不能被100整除",
                "C. 能被400整除",
                "D. 能被2整除"
            ],
            "answer": "D",
            "explanation": "能被2整除是所有偶数的特征,不是闰年的特殊条件"
        },
        {
            "question": "下一次闰年是什么时候?",
            "options": [
                "A. 2024年",
                "B. 2025年",
                "C. 2026年",
                "D. 2027年"
            ],
            "answer": "A",
            "explanation": "2024能被4整除,是闰年"
        },
        {
            "question": "一个世纪(100年)中有多少个闰年?",
            "options": [
                "A. 24个",
                "B. 25个",
                "C. 20个",
                "D. 26个"
            ],
            "answer": "A",
            "explanation": "一般情况下每4年一个闰年,但整百年除外,所以一个世纪通常有24个闰年"
        }
    ]
    
    return questions

def run_quiz():
    """运行问答游戏"""
    questions = create_quiz()
    random.shuffle(questions)
    
    score = 0
    total = len(questions)
    
    print("欢迎参加闰年知识问答!")
    print(f"共{total}道题,每题10分")
    print("=" * 50)
    
    for i, q in enumerate(questions, 1):
        print(f"\n📝 第{i}题(10分):")
        print(q["question"])
        
        for option in q["options"]:
            print(f"  {option}")
        
        answer = input("\n请选择(A/B/C/D):").upper()
        
        if answer == q["answer"]:
            print("✅ 回答正确!")
            score += 10
        else:
            print(f"❌ 回答错误!")
            print(f"正确答案是:{q['answer']}")
        
        print(f"💡 解释:{q['explanation']}")
        print(f"📊 当前得分:{score}/{i*10}")
    
    # 显示最终结果
    print(f"\n{'='*50}")
    print(f"{'🎯 问答结束!':^50}")
    print(f"{'='*50}")
    
    percentage = (score / (total * 10)) * 100
    
    print(f"\n📊 最终得分:{score}/{total*10}")
    print(f"📈 正确率:{percentage:.0f}%")
    
    if percentage == 100:
        print("🏆 满分!你是闰年专家!")
    elif percentage >= 80:
        print("🌟 优秀!你对闰年很了解!")
    elif percentage >= 60:
        print("👍 不错!继续学习!")
    elif percentage >= 40:
        print("💪 加油!多了解闰年知识!")
    else:
        print("📚 需要多学习哦!")

# 运行问答游戏
run_quiz()

📅 下节课预告

第29课:猜拳游戏V1.0——人机猜拳游戏

下节课你将学习:

  1. 综合运用条件判断和随机数
  2. 制作人机对战猜拳游戏
  3. 实现游戏计分系统
  4. 添加多轮对战功能
  5. 优化游戏交互体验

预习思考

  1. 猜拳游戏的规则是什么?
  2. 如何判断胜负?
  3. 怎么让电脑随机出拳?

💬 给家长的话

亲爱的家长

今天孩子学习了闰年判断,这是编程中复合条件判断的经典案例。通过这个项目,孩子学会了如何用逻辑运算符组合多个条件来解决实际问题。

孩子今天学会了

  1. ✅ 理解闰年的概念和规则
  2. ✅ 掌握复合条件判断
  3. ✅ 制作闰年判断程序
  4. ✅ 计算日期相关问题
  5. ✅ 制作知识问答游戏

闰年判断的教育价值

| 能力 | 在项目中的应用 | 培养价值 |

|------|---------------|---------|

| 逻辑思维 | 复合条件判断 | 条件组合 |

| 数学应用 | 取模运算 | 数学思维 |

| 天文知识 | 闰年原理 | 科学素养 |

| 日期计算 | 天数计算 | 实用技能 |

| 游戏设计 | 知识问答 | 寓教于乐 |

您可以这样做

亲子互动

  1. 天文科普:讲解地球公转和闰年的关系
  2. 日历观察:一起查看日历中的闰年
  3. 生日计算:计算家人的精确年龄
  4. 知识竞赛:进行闰年知识问答比赛

温馨提示

  • 闰年是天文和历法的结合
  • 复合条件判断是重要的编程技能
  • 鼓励孩子探索更多日期相关知识
  • 用游戏的方式学习更有效

🏆 今日成就

完成了今天的学习,你:

📅 掌握了闰年判断

🔢 学会了日期计算

🧠 理解了复合条件

🎮 制作了知识问答

📊 分析了闰年分布

挑战任务

  1. 制作万年历程序
  2. 添加节假日计算
  3. 制作生日倒计时
  4. 实现农历公历转换

🌟 编程心法

时间是流动的河流
闰年是时间的驿站
每四年一次的调整
让日历跟上地球的脚步
用代码判断闰年
用逻辑理解规律
条件组合是工具
天文知识是智慧
学会判断时间
更要珍惜时间
让每一分每一秒
都过得有意义
这是编程的启示
也是生活的真谛

记住:闰年不只是多了一天,更是人类智慧的体现。用编程理解世界的规律,用技术解决实际问题!


第28课结束。你现在已经是闰年判断专家了!

实践任务:

1. 制作万年历程序

2. 添加更多日期功能

3. 设计闰年知识游戏

4. 探索更多历法知识

下节课,让我们制作猜拳游戏,体验人机对战的乐趣!

第29课见!✊✋✌️