#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <random>
#include <ctime>
#include <iomanip>
#include <algorithm>
#include <thread>
#include <chrono>
#include <limits>

using namespace std;
using namespace std::this_thread;
using namespace std::chrono;

// 分隔线函数(保留)
void f() {
    cout << "#==============================================#" << endl;
}

// ===== 称号 =====
string getRank(int a) {
    if (a == 1) return "永恒学帝";
    if (a == 2) return "传奇学神";
    if (a == 3) return "宗师学圣";
    if (a == 4) return "大师学宗";
    if (a == 5) return "星耀学尊";
    if (a == 6) return "钻石学君";
    if (a == 7) return "铂金学仙";
    if (a == 8) return "黄金学魁";
    if (a == 9) return "白银学师";
    if (a == 10)return "青铜学士";
    return "无称号";
}

// ===== 游戏记录 =====
struct GameRecord {
    int attempts;
    int range;
    bool usedHint;
    time_t timestamp;
    bool won;
};

// ===== 游戏数据 =====
struct GameData {
    int best = 999;
    int totalGames = 0;
    int totalWins = 0;
    int totalAttempts = 0;
    int hintUsedWins = 0;
    int consecutiveNoHint = 0;
    int credits = 0;
    vector<bool> rankUnlocked;
    vector<bool> achievements;
    vector<GameRecord> history;
    int extraHints = 0;
    int rangeReductions = 0;
    int doubleCreditCards = 0;
    bool doubleCreditActive = false;
    int currentStreak = 0;
    int maxStreak = 0;
    bool dynamicDifficulty = false;
    
    GameData() {
        rankUnlocked = vector<bool>(11, false);
        achievements = vector<bool>(20, false);
    }
};

// ===== 存档 =====
GameData loadData() {
    GameData data;
    ifstream fin("game.sav");
    if (fin.is_open()) {
        fin >> data.best >> data.totalGames >> data.totalWins >> data.totalAttempts;
        fin >> data.hintUsedWins >> data.consecutiveNoHint >> data.credits;
        fin >> data.currentStreak >> data.maxStreak;
        fin >> data.dynamicDifficulty;
        
        data.rankUnlocked.resize(11, false);
        for (int i = 1; i <= 10; i++) {
            int u; fin >> u;
            data.rankUnlocked[i] = (u == 1);
        }
        data.achievements.resize(20, false);
        for (int i = 0; i < 20; i++) {
            int u; fin >> u;
            data.achievements[i] = (u == 1);
        }
        fin >> data.extraHints >> data.rangeReductions >> data.doubleCreditCards;
        int histSize; fin >> histSize;
        data.history.clear();
        for (int i = 0; i < min(histSize, 10); i++) {
            GameRecord r;
            fin >> r.attempts >> r.range >> r.usedHint >> r.timestamp >> r.won;
            data.history.push_back(r);
        }
        fin.close();
    }
    return data;
}

void saveData(const GameData& data) {
    ofstream fout("game.sav");
    if (fout.is_open()) {
        fout << data.best << " " << data.totalGames << " " << data.totalWins << " " << data.totalAttempts;
        fout << " " << data.hintUsedWins << " " << data.consecutiveNoHint << " " << data.credits;
        fout << " " << data.currentStreak << " " << data.maxStreak;
        fout << " " << data.dynamicDifficulty;
        for (int i = 1; i <= 10; i++) {
            fout << " " << (data.rankUnlocked[i] ? 1 : 0);
        }
        for (int i = 0; i < 20; i++) {
            fout << " " << (data.achievements[i] ? 1 : 0);
        }
        fout << " " << data.extraHints << " " << data.rangeReductions << " " << data.doubleCreditCards;
        fout << " " << (int)data.history.size();
        for (auto& r : data.history) {
            fout << " " << r.attempts << " " << r.range << " " << r.usedHint << " " << r.timestamp << " " << r.won;
        }
        fout.close();
    }
}

// ===== 成就 =====
vector<string> getAchievementNames() {
    return {
        "一发入魂", "百折不挠", "奇偶大师", "万局宗师",
        "青铜起步", "学帝降临", "范围征服者", "提示依赖症",
        "冷静分析者", "零失误", "全段位收集", "连胜达人",
        "极限反杀", "道具大师", "欧皇附体", "天选之子",
        "学分富豪", "历史学家", "完美主义者", "自由探索者"
    };
}
vector<string> getAchievementDescs() {
    return {
        "单局 1 次猜中",
        "单局尝试 >=15 次仍不放弃",
        "使用提示后下一次就猜中",
        "累计游玩 100 局",
        "首次获得青铜学士称号(10次)",
        "获得永恒学帝称号(1次)",
        "在困难模式(1-200)下成功猜中",
        "累计 5 次使用提示并获胜",
        "连续 3 局未使用提示且全部猜中",
        "单局所有输入均有效(无无效输入)",
        "获得过全部 10 种称号",
        "连续 5 局胜利",
        "在最后1次机会猜中(如6/6)",
        "累计使用 10 次道具",
        "连续 2 局 1 次猜中",
        "在 1-200 模式下 1 次猜中",
        "累计获得 500 学分",
        "查看过历史记录",
        "在任意模式下 3 次以内猜中且未用提示",
        "完成过简单、普通、困难三种模式各1次"
    };
}

// ===== 高级提示 =====
string getHint(int secret, int range, mt19937& gen) {
    uniform_int_distribution<> dis(1, 3);
    int type = dis(gen);
    
    if (type == 1) {
        int width = max(10, range / 5);
        int low = max(1, secret - width / 2);
        int high = min(range, secret + width / 2);
        return "目标在 [" + to_string(low) + ", " + to_string(high) + "] 之间!";
    } else if (type == 2) {
        if (secret <= range / 2) {
            return "目标在 [1, " + to_string(range/2) + "] 之间!";
        } else {
            return "目标在 [" + to_string(range/2 + 1) + ", " + to_string(range) + "] 之间!";
        }
    } else {
        return "目标数字是" + string((secret % 2 == 0) ? "偶数" : "奇数") + "!";
    }
}

// ===== 道具商店 =====
void visitShop(GameData& data) {
    f();
    cout << "【道具商店】(当前学分: " << data.credits << ")\n";
    cout << "1. 额外提示券(50学分)—— 本局可多用1次提示\n";
    cout << "2. 范围缩减卡(80学分)—— 本局范围缩小20%\n";
    cout << "3. 双倍学分卡(100学分)—— 下一局学分×2\n";
    cout << "0. 返回\n";
    cout << "请选择: ";
    
    int choice;
    cin >> choice;
    if (choice == 1 && data.credits >= 50) {
        data.extraHints++;
        data.credits -= 50;
        cout << "购买成功!额外提示券+1\n";
    } else if (choice == 2 && data.credits >= 80) {
        data.rangeReductions++;
        data.credits -= 80;
        cout << "购买成功!范围缩减卡+1\n";
    } else if (choice == 3 && data.credits >= 100) {
        data.doubleCreditCards++;
        data.credits -= 100;
        cout << "购买成功!双倍学分卡+1\n";
    } else if (choice != 0) {
        cout << "学分不足或选项无效!\n";
    }
    sleep_for(seconds(1));
    saveData(data);
}

// ===== 历史 & 统计(保留 f() 和 ASCII 趋势图)=====
void showHistory(GameData& data) {
    f();
    cout << "【最近10局记录】" << endl;
    if (data.history.empty()) {
        cout << "暂无记录。" << endl;
    } else {
        for (int i = (int)data.history.size() - 1; i >= 0; i--) {
            auto& r = data.history[i];
            char timeBuf[20];
            strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M", localtime(&r.timestamp));
            cout << "第" << (data.history.size() - i) << "局: "
                 << (r.won ? "胜" : "负") << " | "
                 << r.attempts << "次 | 范围1-" << r.range
                 << " | " << (r.usedHint ? "用了提示" : "未用提示")
                 << " | " << timeBuf << endl;
        }
    }

    if (data.history.size() >= 2) {
        cout << "\n【近期表现趋势】(尝试次数)\n";
        int n = min(5, (int)data.history.size());
        vector<int> recent;
        for (int i = 1; i <= n; i++) {
            if (data.history[data.history.size() - i].won) {
                recent.push_back(data.history[data.history.size() - i].attempts);
            }
        }
        if (!recent.empty()) {
            int maxVal = *max_element(recent.begin(), recent.end());
            for (int val : recent) {
                cout << "|";
                for (int j = 0; j < val * 5 / max(1, maxVal); j++) cout << "*";
                cout << " (" << val << ")\n";
            }
        }
    }

    if (data.totalGames > 0) {
        double winRate = (double)data.totalWins / data.totalGames * 100;
        double avg = (double)data.totalAttempts / max(1, data.totalWins);
        cout << "\n【全局统计】" << endl;
        cout << "总胜率: " << fixed << setprecision(1) << winRate << "%" << endl;
        cout << "平均次数: " << fixed << setprecision(1) << avg << endl;
    }
    cout << "\n按回车返回...";
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    cin.get();

    if (!data.achievements[17]) {
        data.achievements[17] = true;
        cout << "\n【成就解锁】历史学家:查看过历史记录!!!\n";
        sleep_for(seconds(1));
    }
}

// ===== 检查全局成就 =====
void checkGlobalAchievements(GameData& data) {
    auto names = getAchievementNames();
    // 万局宗师
    if (data.totalGames >= 100 && !data.achievements[3]) {
        data.achievements[3] = true;
        cout << "\n【成就解锁】" << names[3] << "!!!\n"; sleep_for(seconds(1));
    }
    // 提示依赖症
    if (data.hintUsedWins >= 5 && !data.achievements[7]) {
        data.achievements[7] = true;
        cout << "\n【成就解锁】" << names[7] << "!!!\n"; sleep_for(seconds(1));
    }
    // 冷静分析者
    if (data.consecutiveNoHint >= 3 && !data.achievements[8]) {
        data.achievements[8] = true;
        cout << "\n【成就解锁】" << names[8] << "!!!\n"; sleep_for(seconds(1));
    }
    // 连胜达人
    if (data.currentStreak >= 5 && !data.achievements[11]) {
        data.achievements[11] = true;
        cout << "\n【成就解锁】" << names[11] << "!!!\n"; sleep_for(seconds(1));
    }
    // 道具大师
    int totalItemsUsed = data.extraHints + data.rangeReductions + data.doubleCreditCards;
    if (totalItemsUsed >= 10 && !data.achievements[13]) {
        data.achievements[13] = true;
        cout << "\n【成就解锁】" << names[13] << "!!!\n"; sleep_for(seconds(1));
    }
    // 学分富豪
    if (data.credits >= 500 && !data.achievements[16]) {
        data.achievements[16] = true;
        cout << "\n【成就解锁】" << names[16] << "!!!\n"; sleep_for(seconds(1));
    }
    // 全段位收集
    bool allRanks = true;
    for (int i = 1; i <= 10; i++) {
        if (!data.rankUnlocked[i]) { allRanks = false; break; }
    }
    if (allRanks && !data.achievements[10]) {
        data.achievements[10] = true;
        cout << "\n【成就解锁】" << names[10] << "!!!\n"; sleep_for(seconds(1));
    }
    // 自由探索者
    bool easy = false, normal = false, hard = false;
    for (const auto& rec : data.history) {
        if (rec.won) {
            if (rec.range == 50) easy = true;
            else if (rec.range == 100) normal = true;
            else if (rec.range == 200 || rec.range > 200) hard = true;
        }
    }
    if (easy && normal && hard && !data.achievements[19]) {
        data.achievements[19] = true;
        cout << "\n【成就解锁】" << names[19] << "!!!\n"; sleep_for(seconds(1));
    }
}

// ===== 主函数 =====
int main() {
    random_device rd;
    mt19937 gen(rd());
    GameData data = loadData();

    f();
    cout << "          猜数字游戏 v4.1(强化版)" << endl;
    f();

    if (data.totalGames > 0) {
        double avg = (double)data.totalAttempts / max(1, data.totalWins);
        cout << "历史最佳: " << data.best << " 次 -- " << getRank(data.best) << endl;
        cout << "已玩 " << data.totalGames << " 局,胜 " << data.totalWins << " 局" << endl;
        cout << "平均 " << fixed << setprecision(1) << avg << " 次/胜" << endl;
        cout << "当前学分: " << data.credits << endl;
        sleep_for(seconds(1));
    }

    char mode;
    do {
        f();
        cout << "主菜单:" << endl;
        cout << "1. 经典模式(固定次数)" << endl;
        cout << "2. 策略模式(无限次,计分制)" << endl;
        cout << "3. 成就图鉴" << endl;
        cout << "4. 道具商店" << endl;
        cout << "5. 历史记录" << endl;
        cout << "6. 设置(动态难度: " << (data.dynamicDifficulty ? "开" : "关") << ")" << endl;
        cout << "7. 退出" << endl;
        cout << "请选择: ";
        cin >> mode;

        if (mode == '3') {
            f();
            cout << "成就图鉴(共20项):" << endl;
            auto names = getAchievementNames();
            auto descs = getAchievementDescs();
            for (int i = 0; i < 20; i++) {
                cout << (data.achievements[i] ? "[#] " : "[ ] ")
                     << names[i] << " —— " << descs[i] << endl;
            }
            cout << "\n按回车返回...";
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            cin.get();
            continue;
        }

        if (mode == '4') {
            visitShop(data);
            continue;
        }

        if (mode == '5') {
            showHistory(data);
            saveData(data);
            continue;
        }

        if (mode == '6') {
            cout << "切换动态难度?(y/n): ";
            char c; cin >> c;
            if (c == 'y' || c == 'Y') {
                data.dynamicDifficulty = !data.dynamicDifficulty;
                cout << "动态难度已" << (data.dynamicDifficulty ? "开启" : "关闭") << "。" << endl;
            }
            saveData(data);
            sleep_for(seconds(1));
            continue;
        }

        if (mode == '7') break;
        if (mode != '1' && mode != '2') continue;

        // ===== 选择范围 =====
        int baseRange = 100;
        f();
        cout << "选择范围:" << endl;
        cout << "1. 1-50" << endl;
        cout << "2. 1-100" << endl;
        cout << "3. 1-200" << endl;
        char diff; 
        cin >> diff;
        if (diff == '1') baseRange = 50;
        else if (diff == '3') baseRange = 200;

        // 使用道具?
        bool useRangeReduction = false, useDoubleCredit = false;
        if (data.rangeReductions > 0) {
            cout << "是否使用范围缩减卡?(y/n): ";
            char c; cin >> c;
            if (c == 'y' || c == 'Y') {
                useRangeReduction = true;
                data.rangeReductions--;
            }
        }
        if (data.doubleCreditCards > 0 && !data.doubleCreditActive) {
            cout << "是否使用双倍学分卡?(y/n): ";
            char c; cin >> c;
            if (c == 'y' || c == 'Y') {
                useDoubleCredit = true;
                data.doubleCreditCards--;
                data.doubleCreditActive = true;
            }
        }

        // 动态难度调整
        if (data.dynamicDifficulty && data.totalGames >= 5) {
            double avg = (double)data.totalAttempts / max(1, data.totalWins);
            if (avg <= 4.0) {
                baseRange = min(300, baseRange + 50);
                cout << "【动态难度】检测到高手,范围提升至 1-" << baseRange << "!" << endl;
            } else if (avg >= 8.0) {
                baseRange = max(30, baseRange - 20);
                cout << "【动态难度】范围调整为 1-" << baseRange << "。" << endl;
            }
        }

        // 应用范围缩减
        if (useRangeReduction) {
            baseRange = max(10, (int)(baseRange * 0.8));
            cout << "【道具生效】范围缩减至 1-" << baseRange << "!" << endl;
        }

        uniform_int_distribution<> dis(1, baseRange);
        int n = dis(gen);

        int maxAttempts = (baseRange <= 50 ? 6 : (baseRange <= 100 ? 7 : 8));
        bool infiniteMode = (mode == '2');
        if (infiniteMode) maxAttempts = 999;

        f();
        cout << (infiniteMode ? "策略模式" : "经典模式") << ":范围 1-" << baseRange << endl;
        if (!infiniteMode) cout << "最多 " << maxAttempts << " 次。" << endl;
        cout << "输入 -1 使用提示,quit 退出。" << endl;
        if (data.extraHints > 0) {
            cout << "(你有 " << data.extraHints << " 张额外提示券)" << endl;
        }

        int a = 0;
        bool usedHint = false;
        bool won = false;
        int invalidCount = 0;
        bool justUsedHint = false;
        int maxHints = 1 + (data.extraHints > 0 ? 1 : 0);
        int hintsUsed = 0;

        while ((!infiniteMode && a < maxAttempts) || (infiniteMode && !won)) {
            cout << "猜测: ";
            string input;
            cin >> input;

            if (input == "quit") break;
            if (input == "-1") {
                if (hintsUsed >= maxHints) {
                    cout << "提示次数已用完!" << endl;
                    continue;
                }
                hintsUsed++;
                if (hintsUsed == 2 && data.extraHints > 0) {
                    data.extraHints--;
                }
                string hint = getHint(n, baseRange, gen);
                cout << "提示:" << hint << endl;
                justUsedHint = true;
                continue;
            }

            // 输入校验
            bool valid = true;
            for (char c : input) {
                if (c != '-' && !isdigit(c)) { valid = false; break; }
            }
            if (!valid) {
                cout << "无效输入!" << endl;
                invalidCount++;
                continue;
            }
            int g;
            try {
                g = stoi(input);
            } catch (...) {
                cout << "无效数字!" << endl;
                invalidCount++;
                continue;
            }
            if (g < 1 || g > baseRange) {
                cout << "超出范围(1-" << baseRange << ")!" << endl;
                invalidCount++;
                continue;
            }

            a++;
            bool guessedRightAfterHint = (justUsedHint && g == n);
            justUsedHint = false;

            if (g == n) {
                won = true;
                break;
            } else {
                cout << (g > n ? "太大了!" : "太小了!") << endl;
                if (!infiniteMode && a == maxAttempts - 1) {
                    cout << "?? 最后一次机会!" << endl;
                }
            }
        }

        // ===== 结算 =====
        data.totalGames++;
        if (won) {
            data.totalWins++;
            data.totalAttempts += a;
            if (a < data.best) data.best = a;
            if (a >= 1 && a <= 10) data.rankUnlocked[a] = true;

            data.currentStreak++;
            if (data.currentStreak > data.maxStreak) data.maxStreak = data.currentStreak;

            if (hintsUsed > 0) {
                data.hintUsedWins++;
                data.consecutiveNoHint = 0;
            } else {
                data.consecutiveNoHint++;
            }

            // 学分计算
            int credit = max(5, 20 - a);
            if (baseRange >= 200) credit += 5;
            if (hintsUsed == 0) credit += 3;
            if (infiniteMode) credit = max(1, credit / 2);
            if (data.doubleCreditActive) {
                credit *= 2;
                data.doubleCreditActive = false;
            }
            data.credits += credit;

            cout << "*#你用了 " << a << " 次猜中了!#*" << endl;
            cout << "获得学分: " << credit << "(总计: " << data.credits << ")" << endl;

            // 单局成就
            auto names = getAchievementNames();
            if (a == 1 && !data.achievements[0]) {
                data.achievements[0] = true;
                cout << "\n【成就解锁】" << names[0] << "!!!\n"; sleep_for(seconds(1));
            }
            if (a <= 3 && hintsUsed == 0 && !data.achievements[18]) {
                data.achievements[18] = true;
                cout << "\n【成就解锁】" << names[18] << "!!!\n"; sleep_for(seconds(1));
            }
            if (a >= 15 && !data.achievements[1]) {
                data.achievements[1] = true;
                cout << "\n【成就解锁】" << names[1] << "!!!\n"; sleep_for(seconds(1));
            }
            if (!infiniteMode && a == maxAttempts && !data.achievements[12]) {
                data.achievements[12] = true;
                cout << "\n【成就解锁】" << names[12] << "!!!\n"; sleep_for(seconds(1));
            }
            if (a == 1 && data.totalWins >= 2) {
                bool prevOneShot = false;
                if (!data.history.empty() && data.history.back().won && data.history.back().attempts == 1) {
                    prevOneShot = true;
                }
                if (prevOneShot && !data.achievements[14]) {
                    data.achievements[14] = true;
                    cout << "\n【成就解锁】" << names[14] << "!!!\n"; sleep_for(seconds(1));
                }
            }
            if (baseRange >= 200 && a == 1 && !data.achievements[15]) {
                data.achievements[15] = true;
                cout << "\n【成就解锁】" << names[15] << "!!!\n"; sleep_for(seconds(1));
            }
            if (a == 10 && !data.achievements[4]) {
                data.achievements[4] = true;
                cout << "\n【成就解锁】" << names[4] << "!!!\n"; sleep_for(seconds(1));
            }
            if (a == 1 && !data.achievements[5]) {
                data.achievements[5] = true;
                cout << "\n【成就解锁】" << names[5] << "!!!\n"; sleep_for(seconds(1));
            }
            if (baseRange >= 200 && !data.achievements[6]) {
                data.achievements[6] = true;
                cout << "\n【成就解锁】" << names[6] << "!!!\n"; sleep_for(seconds(1));
            }
        } else {
            data.currentStreak = 0;
            data.consecutiveNoHint = 0;
            cout << "正确答案是: " << n << endl;
        }

        // 记录
        GameRecord rec{a, baseRange, (hintsUsed > 0), time(nullptr), won};
        data.history.push_back(rec);
        if ((int)data.history.size() > 10) data.history.erase(data.history.begin());

        // 检查全局成就
        checkGlobalAchievements(data);

        saveData(data);
        sleep_for(seconds(1));
        f();

    } while (true);

    cout << "\n游戏结束,数据已保存。" << endl;
    return 0;
}

4 comments

  • 1