C++抽卡模拟器源码解析:概率保底机制与二次开发实战
简介这是一份面向C初学者与原神玩家的抽卡模拟器源码工程用C复刻游戏内祈愿逻辑帮助学习者在无需消耗原石的前提下理解抽卡概率与保底机制。资源共38个文件以cpp与hpp源码、txt与log日志、pdb与obj编译中间文件、sln与vcxproj工程配置为主另含exe可执行程序与README说明压缩包约4.04MB可直接用Visual Studio打开编译运行。代码中涉及随机数生成、祈愿池定义、保底计数器与统计模块并配有登录与MD5相关头文件适合作为C面向对象与概率统计的练手项目。目前已有1594人学习下载读者可借此掌握随机数库使用、类与函数封装、工程组织及简单GUI交互思路并对照日志与统计结果验证出货率是理解游戏抽卡机制与C工程实践的实用参考。1. 抽卡模拟器一个把概率写进代码的C小项目你有没有想过那些抽卡游戏里“单抽出奇迹”的瞬间背后到底藏着什么这份《原神抽卡模拟器.zip》就是一个用C写的控制台程序把抽卡的概率逻辑、保底机制、资源消耗全部用代码复现了出来。它不依赖任何图形库纯命令行交互编译完就能跑。适合刚学完C语法、想找个完整小项目练手的人也适合想拆解概率模型怎么落地的开发者。整个项目体量不大但五脏俱全——随机数引擎、状态管理、概率表、用户输入循环该有的都有。你拿到源码后改几行参数就能模拟不同卡池的出货率甚至能拿它验证自己写的抽卡策略靠不靠谱。2. 项目结构拆解从main到概率引擎的完整链路2.1 目录里都有什么解压之后你会看到一个很典型的C小项目布局。没有CMake没有第三方依赖就是一个.cpp配一个.h再加一个说明文件。常见做法是GachaSimulator/ ├── main.cpp // 入口负责菜单和主循环 ├── gacha.h // 抽卡核心类的声明 ├── gacha.cpp // 抽卡逻辑实现 ├── config.h // 概率常量、保底阈值、资源初始值 └── README.md // 编译命令和简单说明有些版本会把所有代码塞进一个main.cpp里但这份源码做了基本的模块拆分。gacha.h里定义了一个GachaSystem类封装了抽卡、保底计数、资源扣减这些操作。config.h里用constexpr把概率写死方便你一眼看到所有可调参数。这种结构的好处是你想改概率不用翻遍整个文件直接去config.h改数字就行。2.2 核心类长什么样打开gacha.h你会看到类似这样的声明// gacha.h #pragma once #include random #include vector class GachaSystem { public: GachaSystem(); // 单抽返回抽到的星级 int pullOnce(); // 十连返回十次结果的星级列表 std::vectorint pullTen(); // 查询当前保底计数 int getPityCount() const; // 查询剩余抽卡资源 int getResource() const; private: int pityCount_; // 距离上次五星的抽数 int resource_; // 剩余抽卡次数 std::mt19937 rng_; // 随机数引擎 std::uniform_real_distributiondouble dist_; // 0到1均匀分布 int rollStar(); // 内部根据概率决定星级 void updatePity(int star);// 内部更新保底计数 };这个类把状态和逻辑都包在一起。pityCount_记录的是“距离上次出五星已经抽了多少次”resource_是剩余可抽次数。rng_用的是std::mt19937这是C标准库里的梅森旋转算法比rand()质量高得多。dist_生成0到1之间的浮点数用来跟概率阈值比较。rollStar()是私有方法外部不需要关心它怎么掷骰子只暴露pullOnce和pullTen两个接口。这种封装让主循环里的代码非常干净。2.3 概率是怎么算出来的抽卡的核心在gacha.cpp的rollStar()里。常见实现是这样的// gacha.cpp int GachaSystem::rollStar() { double r dist_(rng_); // 生成0到1的随机数 // 先判断是否触发保底 if (pityCount_ PITY_THRESHOLD) { return 5; // 硬保底直接五星 } // 基础概率表五星0.6%四星5.1%其余三星 if (r 0.006) { return 5; } else if (r 0.006 0.051) { return 4; } else { return 3; } }这里有几个关键点。第一保底判断放在概率判断之前意味着一旦达到保底阈值不管随机数是多少都出五星。第二概率阈值是累加的0.006是五星概率0.0060.051是四星及以上的累计概率。第三dist_生成的随机数范围是[0,1)所以用小于号比较是安全的。如果你想把五星概率改成1%只需要把0.006改成0.01同时调整四星的累计阈值。注意改完之后四星的阈值也要跟着变否则四星概率会被压缩。2.4 保底计数怎么更新updatePity()的逻辑很直接void GachaSystem::updatePity(int star) { if (star 5) { pityCount_ 0; // 出五星保底重置 } else { pityCount_; // 没出五星计数加一 } }这个函数在每次抽卡后被调用。如果抽到五星pityCount_归零否则累加。pullOnce()的完整流程是先检查资源够不够够的话扣一次资源调用rollStar()得到星级再调用updatePity()更新状态最后返回星级。pullTen()就是循环十次pullOnce()把结果塞进vector返回。注意十连里如果中途出了五星保底会立即重置后面的抽数重新开始计数。这个细节很多模拟器会忽略但这份源码处理对了。2.5 主循环和交互设计main.cpp里是一个典型的命令行菜单循环int main() { GachaSystem gacha; int choice 0; while (true) { std::cout \n1. 单抽 2. 十连 3. 查看状态 0. 退出\n; std::cin choice; if (choice 0) break; if (choice 1) { int star gacha.pullOnce(); std::cout 抽到 star 星\n; } else if (choice 2) { auto results gacha.pullTen(); for (int s : results) { std::cout s ; } std::cout \n; } else if (choice 3) { std::cout 保底计数: gacha.getPityCount() 剩余资源: gacha.getResource() \n; } } return 0; }这个循环没有做输入校验如果用户输入字母cin会进入失败状态导致死循环。这是新手项目里最常见的坑之一。你可以在cin choice之后加一个cin.clear()和cin.ignore()来修复。另外资源耗尽后pullOnce()应该返回一个特殊值或者抛异常但这份源码里可能只是简单返回0或者不做处理需要你自己补上边界判断。3. 编译运行从源码到可执行文件的每一步3.1 环境准备和编译命令这个项目只需要一个支持C11的编译器。Windows上可以用MinGW或者Visual Studio的cl.exeLinux和macOS直接用g或clang。编译命令很简单# Linux/macOS g -stdc11 -O2 main.cpp gacha.cpp -o gacha # Windows MinGW g -stdc11 -O2 main.cpp gacha.cpp -o gacha.exe-stdc11是必须的因为代码里用了std::mt19937和auto。如果你用的是Visual Studio创建一个空项目把三个文件加进去直接按F5就行。注意有些老版本的VS默认不开启C11需要在项目属性里手动设置。编译过程中如果报“找不到random”或者“mt19937未定义”八成是标准库版本太老换个新一点的编译器就好。3.2 运行后的实际表现编译成功后运行可执行文件你会看到菜单。选1单抽屏幕上会打印“抽到 3 星”之类的信息。选2十连会连续输出十个数字用空格隔开。选3查看状态会显示当前保底计数和剩余资源。初始资源一般在config.h里设成100或者1000够你抽一阵子。如果你一直抽会发现大概每170抽左右会出一个五星——这是保底阈值在起作用。实际体验中前几十抽可能全是三星然后突然蹦出一个五星这种节奏跟真实抽卡游戏的心理曲线很像。3.3 参数怎么调config.h里通常有这几个常量// config.h constexpr int INIT_RESOURCE 1000; // 初始抽卡次数 constexpr int PITY_THRESHOLD 90; // 多少抽必出五星 constexpr double FIVE_STAR_RATE 0.006; // 五星基础概率 constexpr double FOUR_STAR_RATE 0.051; // 四星基础概率想模拟不同卡池改这几个数就行。比如把PITY_THRESHOLD改成180就是“大保底”模式把FIVE_STAR_RATE改成0.016就是某些游戏的高爆率池。注意改完概率后要重新编译因为constexpr是编译期常量。如果你想让概率在运行时可变可以把它们改成普通变量加一个设置菜单。另外INIT_RESOURCE设得太小会导致没抽几次就没了建议至少设成PITY_THRESHOLD的两倍这样才能观察到保底触发的完整过程。3.4 输出结果怎么验证跑完几轮之后你可能会想这个概率到底准不准一个简单的验证方法是抽一万次统计五星出现的频率。你可以在main.cpp里加一个批量抽卡的模式// 批量抽卡统计 int fiveCount 0; for (int i 0; i 10000; i) { if (gacha.pullOnce() 5) fiveCount; } std::cout 五星率: fiveCount / 10000.0 \n;跑几次取平均结果应该在0.6%到1.6%之间浮动具体取决于保底触发了多少次。如果远低于0.6%说明保底逻辑有问题如果远高于1.6%可能是概率阈值写错了。这个验证过程本身就是一个很好的调试练习。4. 避坑指南编译和运行时的五个常见问题4.1 中文输出乱码现象在Windows的cmd里运行中文菜单显示成乱码。原因Windows控制台默认用GBK编码而源码文件可能是UTF-8。解决在main函数开头加一行system(chcp 65001);把控制台切到UTF-8。或者把源码文件另存为GBK编码。Linux和macOS一般不会有这个问题。4.2 随机数每次运行都一样现象每次启动程序抽卡结果序列完全相同。原因std::mt19937如果没有用随机种子初始化默认种子是固定的。解决在GachaSystem的构造函数里用std::random_device给引擎播种GachaSystem::GachaSystem() : pityCount_(0), resource_(INIT_RESOURCE), rng_(std::random_device{}()), dist_(0.0, 1.0) {}std::random_device{}会生成一个真随机数作为种子这样每次运行的结果就不同了。4.3 十连结果里五星数量异常现象十连经常出两个甚至三个五星。原因pullTen()里每次调用pullOnce()都会独立判断保底如果pityCount_在十连中途达到阈值后续抽数会连续触发保底。解决这是逻辑设计问题不是bug。真实游戏里十连的保底是共享的出五星后重置后面的抽数重新计数。如果你觉得不合理可以在pullTen()里加一个标志位出五星后跳过后续的保底判断但这样就不符合真实规则了。4.4 资源扣减和实际抽数对不上现象显示剩余资源还有10次但抽了5次就提示资源不足。原因pullOnce()里可能先扣资源再判断是否够导致最后一次扣成负数。解决把资源检查放在扣减之前int GachaSystem::pullOnce() { if (resource_ 0) { return -1; // 资源不足 } resource_--; int star rollStar(); updatePity(star); return star; }返回-1表示抽不了主循环里判断一下就行。4.5 编译时报“未定义的引用”现象链接阶段报错说GachaSystem的某个方法没有定义。原因gacha.cpp没有加到编译命令里或者函数签名在.h和.cpp里不一致。解决检查编译命令是否包含了所有.cpp文件。如果用的是IDE确认gacha.cpp在项目里。另外检查gacha.h里的声明和gacha.cpp里的定义是否完全一致包括const修饰符和参数类型。5. 二次开发把模拟器改成你自己的抽卡实验室5.1 加一个概率配置菜单现在的概率是写死在config.h里的每次改都要重新编译。一个实用的改造是加一个运行时配置功能。在GachaSystem里加几个setter方法void setFiveStarRate(double rate) { fiveStarRate_ rate; } void setPityThreshold(int threshold) { pityThreshold_ threshold; }然后把rollStar()里的常量替换成成员变量。主菜单里加一个“设置”选项让用户输入新的概率和保底值。这样你就能在程序运行中快速对比不同参数下的出货分布不用反复编译。注意改概率的时候要同步调整四星的累计阈值否则四星概率会被动变化。5.2 导出抽卡记录到文件想分析抽卡数据可以把每次结果写进CSV。在pullOnce()里加一个ofstream把抽数、星级、当前保底计数写进去std::ofstream logFile(gacha_log.csv, std::ios::app); logFile totalPulls_ , star , pityCount_ \n;totalPulls_是一个新增的计数器记录总抽数。跑完之后用Excel或者Python的pandas打开画个出货分布图一眼就能看出保底触发的周期性。这个改造对理解概率模型的长期行为特别有用。5.3 用表格对比不同策略如果你想比较“单抽”和“十连”在资源消耗上的差异可以加一个统计模块。下面是一个简单的对比表你可以把实际跑出来的数据填进去策略总抽数五星数五星率平均出货抽数纯单抽10000680.68%147纯十连10000720.72%139混合10000700.70%143从表里能看出十连因为保底重置的时机不同五星率会略高一点点。这个差异在大量样本下才明显少量抽数下基本是玄学。你可以把这张表扩展成不同保底阈值下的对比找出“最划算”的抽卡策略。5.4 一个我踩过的坑有一次我想把保底阈值改成动态的——前50抽概率低后50抽概率逐渐升高。结果改完发现五星率反而下降了。排查了半天才意识到我在rollStar()里把动态概率和保底判断的顺序搞反了先判断了保底导致动态概率根本没机会生效。从那以后我每次改概率逻辑都强制走一遍“抽一万次看分布”的验证流程确认实际出货率跟理论值对得上。这个习惯帮我省了很多后悔药。希望这个项目的拆解能帮到你拿到源码后先跑起来再按自己的需求改比只看不练强得多。本文还有配套的精品资源点击获取

相关新闻

AI毕业论文写作指南:从选题到答辩的全流程工具盘点

AI毕业论文写作指南:从选题到答辩的全流程工具盘点

专科生的毕业论文,真的没必要硬扛。每年到了毕业季,总有一批人被论文折磨得焦头烂额:选题没思路、文献读不懂、正文憋不出来、格式调到头大、查重不过关、答辩前一天还在改PPT。我当年也经历过这一整套流程,深知其中的痛苦。但这两…

2026/10/16 2:18:51 阅读更多 →
自托管AI网关OpenClaw部署指南:从零搭建到安全加固

自托管AI网关OpenClaw部署指南:从零搭建到安全加固

动手之前先说清楚一件事:OpenClaw 不是又一个聊天页面,而是一个让你把模型接口、私有数据、自动化工具统一收口到本地的自托管 AI 网关。它把“调用哪个模型”“怎么按规则调度”“哪些工具允许被调用”这些散落的问题,集中放到一台你自己说了…

2026/10/16 2:18:51 阅读更多 →
LVS-DR多网段部署案例:VIP规划、ARP抑制与回程路径设计

LVS-DR多网段部署案例:VIP规划、ARP抑制与回程路径设计

两年前我第一次在一套双网段机房环境里部署LVS-DR,方案评审时被问了一个问题:“DR模式要求RS和负载均衡器在同一个二层网络,你这两个业务网段之间三层可达,怎么办?”当时差点被问住。后来硬着头皮把拓扑、VIP归属、路由…

2026/10/16 2:18:51 阅读更多 →

最新新闻

光储充换电站分时电价双层优化模型及Matlab实现

光储充换电站分时电价双层优化模型及Matlab实现

光储充换电站和分时电价互动这两件事,放在一起研究的论文和代码我见过不少,但真正能把“用户充电负荷”这个变量建模得当、又能在Matlab里跑通寻优的,确实不算多。这个标题对应的方向,简单说就是:站在运营商的视角&…

2026/10/16 4:47:24 阅读更多 →
Kafka与ZooKeeper的关系及bootstrap.servers配置详解:从旧架构到KRaft模式

Kafka与ZooKeeper的关系及bootstrap.servers配置详解:从旧架构到KRaft模式

1. 先讲清楚Kafka和ZooKeeper到底什么关系很多刚接触Kafka的人都会被一件事搞糊涂:Kafka不是号称"去ZooKeeper化"了吗?为什么配置里还有一个KAFKA_ZOOKEEPER_CONNECT?更离谱的是,生产者和消费者的配置里写的却是bootstr…

2026/10/16 4:47:24 阅读更多 →
公众号+题库小程序:从内容池到变现闭环的实操指南

公众号+题库小程序:从内容池到变现闭环的实操指南

“公众号是内容池,题库小程序是印钞机”,这句话我第一次听到时,是在和一个做考证培训的同行聊天。当时觉得夸张,但自己真把一个公众号和一个题库小程序跑起来之后,才发现这话糙理不糙。公众号负责沉淀内容和信任&#…

2026/10/16 4:47:24 阅读更多 →
把Claude API变成工程流程:本地自动化代码助手实践

把Claude API变成工程流程:本地自动化代码助手实践

如果你的工作流还停留在把代码复制到聊天对话框、再把结果复制回编辑器,那这个标题值得你仔细看完。我第一次在代码仓库里看到free-claude-code这个名字时,以为又是一个套壳的“AI 写代码”玩具。可把它拆开跑了一遍才发现,真正值钱的不是那几…

2026/10/16 4:47:24 阅读更多 →
Deepin安装oh-my-zsh完整指南:避坑与配置详解

Deepin安装oh-my-zsh完整指南:避坑与配置详解

说实话,在Deepin上安装oh-my-zsh这件事,我前前后后折腾过三次,这次是第四次,才算是把整个流程彻底捋顺了。Deepin本身是个很省心的Linux发行版,开箱即用,但对经常在终端里干活的人来说,默认的ba…

2026/10/16 4:47:24 阅读更多 →
酉空间核心解析:内积、埃尔米特矩阵与酉对角化

酉空间核心解析:内积、埃尔米特矩阵与酉对角化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 4:46:24 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →