# 🤖 竞品分析：兰雅·志愿填报计算器

# 🤖 竞品分析：兰雅·志愿填报计算器

> **来源**：第三方工具（兰雅）
> **功能**：2026陕西高考志愿填报计算器
> **语言**：Python（需pandas）
> **文件大小**：17.5K / 499行

---

## 📊 功能分析

### 核心能力
| 功能 | 说明 |
|:----|:------|
| 分数→位次转换 | 基于2025陕西物理/历史类一分一段表，插值估算 |
| 院校推荐 | 8档位次区间推荐（T0-T8） |
| 冲稳保策略 | 冲=位次×0.85 / 稳=当前位次 / 保=位次×1.25 |
| 交互模式 | CLI输入分数→生成分析报告 |

### 与百宾差异对比

| 维度 | 兰雅计算器 | 百宾BookStack |
|:----|:----------|:-------------|
| 数据年份 | 仅2025 | 2023-2025三年 |
| 院校颗粒度 | 8档位次区间 | 逐校数据（4校7,551条） |
| 专业分析 | 无 | 38新专业+选科组分类 |
| 扩招调整 | 仅标注"扩招利好" | 双一流21校扩招总表（4,500+） |
| 强基计划 | 无 | 完整强基决策框架 |
| 特殊招生 | 无 | 国家专项/中外合作/公费师范 |
| 地域分析 | 仅陕西 | 陕西+各省差异 |
| AI抗冲击 | 无 | 人机协作指数评估框架 |
| 人口趋势 | 无 | 2030人口×AI需求四象限 |

---

## 🔧 核心代码

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
2026年陕西省高考志愿填报计算器
================================
功能：输入分数 → 自动估算位次 → 推荐院校区间
数据源：2023-2025年陕西高考录取位次数据
适用：物理类/历史类

使用方法：
1. 直接运行：python 志愿填报计算器.py
2. 或在Python中调用：
   from 志愿填报计算器 import estimate_and_recommend
   result = estimate_and_recommend(550, "physics")
   print(result)
"""

import pandas as pd
import os

# ========================
# 配置
# ========================
OUTPUT_DIR = "/sandbox/workspace/outputs"

# ========================
# 数据定义
# ========================

# 物理类分数-位次映射表（基于2025年陕西一分一段表）
PHYSICS_SCORE_POSITION = [
    (690, 50),
    (680, 120),
    (670, 250),
    (660, 450),
    (650, 750),
    (640, 1150),
    (630, 1700),
    (620, 2500),
    (610, 3600),
    (600, 5200),
    (590, 7200),
    (580, 9800),
    (570, 13000),
    (560, 17000),
    (550, 22000),
    (540, 28500),
    (530, 36000),
    (520, 45000),
    (510, 55000),
    (500, 67000),
    (490, 80000),
    (480, 95000),
    (470, 112000),
    (460, 130000),
    (450, 150000),
    (440, 172000),
    (430, 195000),
    (420, 220000),
    (410, 248000),
    (400, 278000),
    (390, 310000),
    (380, 345000),
    (370, 382000),
    (360, 420000),
]

# 历史类分数-位次映射表（基于2025年陕西一分一段表）
HISTORY_SCORE_POSITION = [
    (690, 10),
    (680, 25),
    (670, 50),
    (660, 90),
    (650, 150),
    (640, 240),
    (630, 370),
    (620, 550),
    (610, 800),
    (600, 1150),
    (590, 1600),
    (580, 2200),
    (570, 3000),
    (560, 4000),
    (550, 5300),
    (540, 6900),
    (530, 8800),
    (520, 11200),
    (510, 14000),
    (500, 17500),
    (490, 21500),
    (480, 26000),
    (470, 31000),
    (460, 36500),
    (450, 42500),
    (440, 49000),
    (430, 56000),
    (420, 63500),
    (410, 71500),
    (400, 80000),
]


def interpolate_position(score, score_pos_list):
    """
    根据分数-位次映射表，使用线性插值估算位次
    """
    if score >= score_pos_list[0][0]:
        return score_pos_list[0][1]
    if score <= score_pos_list[-1][0]:
        return score_pos_list[-1][1]
    
    for i in range(len(score_pos_list) - 1):
        s1, p1 = score_pos_list[i]
        s2, p2 = score_pos_list[i + 1]
        if s1 >= score >= s2:
            # 线性插值
            ratio = (score - s2) / (s1 - s2)
            pos = int(p2 + ratio * (p1 - p2))
            return pos
    return score_pos_list[-1][1]


def estimate_position(score, subject_type):
    """
    估算位次
    
    Args:
        score: 高考分数
        subject_type: "physics" 或 "history"
    
    Returns:
        估算位次（整数）
    """
    if subject_type.lower() == "physics":
        return interpolate_position(score, PHYSICS_SCORE_POSITION)
    elif subject_type.lower() == "history":
        return interpolate_position(score, HISTORY_SCORE_POSITION)
    else:
        raise ValueError("科目类型必须是 'physics' 或 'history'")


def get_school_recommendations(position, subject_type):
    """
    根据位次推荐院校范围
    
    Args:
        position: 估算位次
        subject_type: "physics" 或 "history"
    
    Returns:
        推荐院校列表
    """
    recommendations = []
    
    if subject_type.lower() == "physics":
        if position <= 500:
            recommendations.append({
                "tier": "T0 - 顶尖名校",
                "schools": "清华大学、北京大学、复旦大学、上海交通大学、浙江大学、中国科学技术大学",
                "score_range": "650分以上",
                "strategy": "冲刺/保底皆可"
            })
        elif position <= 2000:
            recommendations.append({
                "tier": "T1 - 顶尖985",
                "schools": "南京大学、中国人民大学、北京航空航天大学、同济大学、哈尔滨工业大学(深圳)",
                "score_range": "620-650分",
                "strategy": "重点冲刺"
            })
        elif position <= 5000:
            recommendations.append({
                "tier": "T2 - 中坚985",
                "schools": "武汉大学、华中科技大学、北京理工大学、东南大学、南开大学、北京师范大学、电子科技大学",
                "score_range": "590-625分",
                "strategy": "重点目标"
            })
        elif position <= 10000:
            recommendations.append({
                "tier": "T3 - 普通985/顶尖211",
                "schools": "四川大学、中山大学、西安交通大学、西北工业大学、天津大学、大连理工大学、华南理工大学",
                "score_range": "560-595分",
                "strategy": "核心目标区间"
            })
        elif position <= 15000:
            recommendations.append({
                "tier": "T4 - 末流985/优质211",
                "schools": "山东大学、中国农业大学、厦门大学、湖南大学、重庆大学、北京交通大学、南京航空航天大学",
                "score_range": "540-570分",
                "strategy": "稳妥选择"
            })
        elif position <= 25000:
            recommendations.append({
                "tier": "T5 - 省属重点211",
                "schools": "苏州大学、武汉理工大学、上海大学、华中师范大学、郑州大学、陕西师范大学",
                "score_range": "510-545分",
                "strategy": "重点考虑"
            })
        elif position <= 40000:
            recommendations.append({
                "tier": "T6 - 一般211",
                "schools": "合肥工业大学、南昌大学、东北师范大学、河北工业大学、长安大学、西北大学",
                "score_range": "480-520分",
                "strategy": "稳妥保底"
            })
        elif position <= 60000:
            recommendations.append({
                "tier": "T7 - 特色一本",
                "schools": "西安电子科技大学、陕西科技大学、西北政法大学、昆明理工大学、杭州电子科技大学",
                "score_range": "450-490分",
                "strategy": "专业优先"
            })
        else:
            recommendations.append({
                "tier": "T8 - 普通本科",
                "schools": "省属本科院校、民办本科",
                "score_range": "450分以下",
                "strategy": "确保有学上"
            })
        
        # 特别标注扩招利好
        if 8000 <= position <= 15000:
            recommendations.append({
                "tier": "⚡ 2026扩招利好",
                "schools": "西安交通大学、西北工业大学、长安大学、西北大学、西安电子科技大学",
                "score_range": "位次8000-15000的考生重点关注",
                "strategy": "这些学校2026年大幅扩招，位次可能下移，是捡漏好机会！"
            })
    
    else:  # history
        if position <= 100:
            recommendations.append({
                "tier": "T0 - 顶尖名校",
                "schools": "清华大学、北京大学、复旦大学、上海交通大学",
                "score_range": "660分以上",
                "strategy": "冲刺/保底皆可"
            })
        elif position <= 500:
            recommendations.append({
                "tier": "T1 - 顶尖985",
                "schools": "中国人民大学、浙江大学、南京大学、武汉大学、北京师范大学",
                "score_range": "620-660分",
                "strategy": "重点冲刺"
            })
        elif position <= 1500:
            recommendations.append({
                "tier": "T2 - 中坚985",
                "schools": "南开大学、同济大学、华东师范大学、北京航空航天大学、中山大学",
                "score_range": "590-630分",
                "strategy": "重点目标"
            })
        elif position <= 3000:
            recommendations.append({
                "tier": "T3 - 普通985/顶尖211",
                "schools": "厦门大学、四川大学、天津大学、西安交通大学、西北工业大学",
                "score_range": "560-595分",
                "strategy": "核心目标区间"
            })
        elif position <= 5000:
            recommendations.append({
                "tier": "T4 - 末流985/优质211",
                "schools": "山东大学、中南大学、吉林大学、重庆大学、北京外国语大学、上海外国语大学",
                "score_range": "530-565分",
                "strategy": "稳妥选择"
            })
        elif position <= 8000:
            recommendations.append({
                "tier": "T5 - 省属重点211",
                "schools": "中央财经大学、西南财经大学、中南财经政法大学、南京师范大学、华中师范大学",
                "score_range": "500-540分",
                "strategy": "重点考虑"
            })
        elif position <= 12000:
            recommendations.append({
                "tier": "T6 - 一般211",
                "schools": "郑州大学、陕西师范大学、西北大学、西南大学、辽宁大学",
                "score_range": "470-510分",
                "strategy": "稳妥保底"
            })
        elif position <= 18000:
            recommendations.append({
                "tier": "T7 - 特色一本",
                "schools": "省属重点本科院校",
                "score_range": "440-480分",
                "strategy": "专业优先"
            })
        else:
            recommendations.append({
                "tier": "T8 - 普通本科",
                "schools": "省属本科院校、民办本科",
                "score_range": "440分以下",
                "strategy": "确保有学上"
            })
    
    return recommendations


def calculate_volunteer_strategy(position, subject_type):
    """
    计算冲稳保志愿策略
    
    Args:
        position: 估算位次
        subject_type: "physics" 或 "history"
    
    Returns:
        冲稳保建议字典
    """
    if subject_type.lower() == "physics":
        # 物理类冲稳保建议
        chase_pos = int(position * 0.85)  # 冲：位次上浮15%
        steady_pos = position  # 稳：匹配当前位次
        protect_pos = int(position * 1.25)  # 保：位次下浮25%
        
        return {
            "冲": {
                "位次范围": f"1-{chase_pos}",
                "建议": "选择位次上限比当前位次要高15%左右的院校",
                "风险": "可能被调剂或滑档"
            },
            "稳": {
                "位次范围": f"{int(position*0.95)}-{int(position*1.05)}",
                "建议": "选择位次与当前水平接近的院校",
                "风险": "录取概率较大"
            },
            "保": {
                "位次范围": f"{steady_pos}-{protect_pos}",
                "建议": "选择位次下限比当前位次要低25%以上的院校",
                "风险": "几乎稳录，但可能屈就"
            }
        }
    else:
        # 历史类冲稳保建议（波动更小）
        chase_pos = int(position * 0.90)
        steady_pos = position
        protect_pos = int(position * 1.20)
        
        return {
            "冲": {
                "位次范围": f"1-{chase_pos}",
                "建议": "选择位次上限比当前位次要高10%左右的院校",
                "风险": "可能被调剂或滑档"
            },
            "稳": {
                "位次范围": f"{int(position*0.95)}-{int(position*1.05)}",
                "建议": "选择位次与当前水平接近的院校",
                "风险": "录取概率较大"
            },
            "保": {
                "位次范围": f"{steady_pos}-{protect_pos}",
                "建议": "选择位次下限比当前位次要低20%以上的院校",
                "risk": "几乎稳录，但可能屈就"
            }
        }


def generate_report(score, subject_type):
    """
    生成完整分析报告
    
    Args:
        score: 高考分数
        subject_type: "physics" 或 "history"
    
    Returns:
        报告字符串
    """
    subject_name = "物理类" if subject_type.lower() == "physics" else "历史类"
    
    # 估算位次
    position = estimate_position(score, subject_type)
    
    # 获取院校推荐
    recommendations = get_school_recommendations(position, subject_type)
    
    # 计算冲稳保
    volunteer_strategy = calculate_volunteer_strategy(position, subject_type)
    
    # 生成报告
    report = []
    report.append("=" * 70)
    report.append(f"  2026年陕西省高考志愿填报分析报告")
    report.append(f"  生成时间：2026年6月17日")
    report.append("=" * 70)
    report.append("")
    report.append(f"📊 基本信息")
    report.append(f"   科目类型：{subject_name}")
    report.append(f"   输入分数：{score}分")
    report.append(f"   估算位次：约 {position:,} 名")
    report.append(f"   ⚠️ 注：位次为估算值，6月25日后请以官方一分一段表为准")
    report.append("")
    
    report.append(f"🎯 院校推荐")
    for rec in recommendations:
        report.append(f"   【{rec['tier']}】")
        report.append(f"   推荐院校：{rec['schools']}")
        if 'score_range' in rec:
            report.append(f"   分数参考：{rec['score_range']}")
        if 'strategy' in rec:
            report.append(f"   填报建议：{rec['strategy']}")
        report.append("")
    
    report.append(f"📋 冲稳保策略")
    for level, info in volunteer_strategy.items():
        report.append(f"   【{level}】")
        report.append(f"   位次范围：{info['位次范围']}")
        report.append(f"   建议：{info['建议']}")
        report.append(f"   风险：{info['风险']}")
        report.append("")
    
    report.append(f"💡 温馨提示")
    report.append(f"   1. 2026年西安交大、西工大、长安大学、西北大学、西电扩招，")
    report.append(f"      位次在8000-15000的物理类考生请重点关注！")
    report.append(f"   2. 估分存在误差，建议分数区间±10分一起分析")
    report.append(f"   3. 6月25日官方成绩公布后，请用一分一段表重新核算")
    report.append(f"   4. 志愿填报请结合个人兴趣、专业前景、城市因素综合考虑")
    report.append("")
    report.append("=" * 70)
    
    return "\n".join(report)


# ========================
# 主程序
# ========================

if __name__ == "__main__":
    print("\n")
    print("╔" + "═" * 68 + "╗")
    print("║" + " " * 15 + "2026年陕西高考志愿填报计算器" + " " * 23 + "║")
    print("╚" + "═" * 68 + "╝")
    print()
    
    # 测试用例
    test_cases = [
        ("physics", 650),
        ("physics", 580),
        ("physics", 520),
        ("physics", 480),
        ("physics", 450),
        ("history", 620),
        ("history", 560),
        ("history", 500),
        ("history", 460),
    ]
    
    for subject, score in test_cases:
        subject_name = "物理类" if subject == "physics" else "历史类"
        print(f"\n{'#' * 70}")
        print(f"# 测试：{subject_name} {score}分")
        print(f"{'#' * 70}")
        
        position = estimate_position(score, subject)
        print(f"  估算位次：{position:,}")
        
        recommendations = get_school_recommendations(position, subject)
        for rec in recommendations:
            print(f"  【{rec['tier']}】{rec['schools'][:50]}...")
    
    # 交互式输入
    print(f"\n{'=' * 70}")
    print(f"  现在您可以输入自己的分数，获取个性化推荐")
    print(f"{'=' * 70}")
    print()
    
    try:
        subject_input = input("请选择科目类型 (1=物理类, 2=历史类): ").strip()
        if subject_input not in ["1", "2"]:
            print("输入无效，使用默认物理类")
            subject_type = "physics"
        else:
            subject_type = "physics" if subject_input == "1" else "history"
        
        score_input = input("请输入估分 (整数): ").strip()
        try:
            score = int(score_input)
            if score < 0 or score > 750:
                print("分数超出范围，使用默认550分")
                score = 550
        except:
            print("输入无效，使用默认550分")
            score = 550
        
        # 生成报告
        report = generate_report(score, subject_type)
        print("\n")
        print(report)
        
        # 保存报告
        subject_name = "物理类" if subject_type == "physics" else "历史类"
        report_file = os.path.join(OUTPUT_DIR, f"志愿填报分析报告_{subject_name}_{score}分.txt")
        with open(report_file, "w", encoding="utf-8") as f:
            f.write(report)
        print(f"\n✅ 报告已保存至: {report_file}")
        
    except KeyboardInterrupt:
        print("\n\n程序已退出")
    except Exception as e:
        print(f"\n程序出现错误: {e}")
        print("请检查输入是否正确")

```