[WinForm开源]概率计算器 - Genshin Impact(V1.0)
创作目的:为方便旅行者估算自己拥有的纠缠之缘能否达到自己的目的,作者使用C#开发了一款小型软件供旅行者参考使用。
创作说明:此软件所涉及到的一切概率与规则完全按照游戏《原神》(V4.4.0)内公示的概率与规则(包括保底机制)进行编写,仅用于计模拟已知纠缠之缘数量对已知抽取五星目标的成功频率(可看作成功率),无任何暗箱操作。
目录
一、软件介绍
1.软件主页面展示
2.软件适用范围
3.软件使用方法
二、获取途径
1.软件获取
2.项目获取
三、项目开源
1.MainForm页面(软件主页面)
2.Form_Poster页面(祈愿海报页面)
3.README页面(说明页面)
4. 应用程序清单文件
四、其他说明
一、软件介绍
1.软件主页面展示
2.软件适用范围
该软件适用范围为:2位UP角色不同卡池但一同保底计数、2把专武在同一卡池且只能定轨一把武器。[说通俗点就是目前能够支持到4.4下半版本,后期如开启混池,作者将会对软件进行更新]
3.软件使用方法
点击顶部「卡池选择」下拉框可切换当前的卡池信息,目前支持4.3与4.4上下半卡池总计4期卡池。
点击顶部「点击查看卡池海报」按钮可以查看选择的当期卡池的海报。
左侧「计划抽取」一栏可以选择旅行者计划抽取的角色、武器的数量,默认为0,角色最大为7,武器最大为5 。当旅行者四栏全部选择为0时,将不被允许进行模拟。
左侧「当前资源」一栏填写旅行者计划投入的纠缠之缘与原石的数量,当填入的资源不足1抽时将不被允许进行模拟,最大支持999抽。
左侧「其他情况」一栏旅行者可以勾选自己对应的情况,若不清楚对于情况,可进入游戏进行查看;旅行者勾选的选项将影响到模拟结果。
中间「用户须知」一栏为简要的用户须知,如页面过小可点击放大到新窗口。旅行者阅读完毕请勾选其下方的“我已认真阅读上述内容”。
点击中间「仅将原石转化为纠缠之缘」按钮,软件将根据用户填入的原石数量,转化为纠缠之缘并将合计的纠缠之缘数量、剩余的原石数量展现给旅行者。
点击中间「开始模拟」按钮,软件将进行10,000次模拟,每次模拟到抽取到目标为止,若有纠缠之缘剩余,则计入剩余总数,最终计算平均剩余数。软件最终将给出「达成预期频率」、「超越预期频率」与「综合成功频率」(后面介绍)。模拟的计算速度取决于旅行者的纠缠之缘数量与计算机的运算速度。
右侧「达成预期频率」一栏将展示软件对旅行者给出的资源数量与目标进行1W次模拟后得到的恰好达到目标的情况的数量与模拟总量的比值。“达成预期”判定标准:在达成所有抽取目标后,纠缠之缘剩余量不小于0时,所获得的所有5星物品(含常驻)与填写的抽取目标完全一致。
右侧「超出预期频率」一栏将展示软件对旅行者给出的资源数量与目标进行1W次模拟后得到的超出预期目标的情况的数量与模拟总量的比值。“超出预期”判定标准:在达成所有抽取目标后,纠缠之缘剩余量不小于0时,所获得的所有5星物品(含常驻)超出填写的抽取目标(常驻默认为0)。
右侧「综合成功频率」一栏将展示软件对旅行者给出的资源数量与目标进行1W次模拟后得到的能够完成给定的抽取目标的情况的数量与模拟总量的比值。该栏为上述两栏之和。
点击右侧「保存为图片」按钮,软件将会把当前页面保存为PNG图片。
二、获取途径
1.软件获取
(1)CSDN站内下载:https://download.csdn.net/download/qq_64516527/88817489
(2)百度网盘下载:https://pan.baidu.com/s/1Uw1mMIONUh9-heMUHRgOOQ?pwd=SLLH 提取码:SLLH
(3)123云盘下载:https://www.123pan.com/s/Il2bVv-CwvQh.html
2.项目获取
(1)CSDN站内下载:https://download.csdn.net/download/qq_64516527/88817874
(2)123云盘下载:https://www.123pan.com/s/Il2bVv-NwvQh.html
三、项目开源
注:接下来的代码主要按页面进行分栏,代码中注释比较全,可直接阅读。
1.MainForm页面(软件主页面)
设计器:
页面代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.Security.Cryptography;
using System.IO;namespace 概率计算器___Genshin_Impact
{public partial class MainForm : Form{public MainForm(){InitializeComponent();}#region 变量的声明public bool Avaluable = true;Thread Thread_Load = null;//淡入淡出的线程Thread Thread_DataDetection = null;//用于检测数据并调控Enable属性的线程Thread T_Imitate = null;//用于进行模拟的线程public int NUM_Ball = 0, NUM_Stone = 0;//纠缠之缘与原石的数量public int[] Success = new int[2] { 0, 0 };//分别表示恰好达到预期与超出预期的次数public int Success_Sum = 0;//表示综合成功次数public bool NextRoleIsBig = false;//表示下次角色池是否为大保底public bool NextWeaponIsUp = false;//表示下次武器池是否为UP武器public int Num_Weapon_Base = 0;//表示武器池定轨数string[,] RoleName = new string[4, 2] {{"娜维娅", "神里绫华" },//4.3上半卡池,卡池编码为0{"雷电将军", "宵宫" },//4.3下半卡池,卡池编码为1{ "闲云", "纳西妲" }, //4.4上半卡池,卡池编码为2{ "魈", "八重神子" }//4.4下半卡池,卡池编码为3};//第一维度为版本编号,第二维度为卡池序号//比如4.4上半对应第一维度,而角色祈愿-2对应第二维度//角色头像图片名称为RoleName[m,n] + "·头像.png"//专武图片名称为RoleName[m,n] + "专武.png"#endregionprivate void MainForm_Load(object sender, EventArgs e){panelMain.BackColor = Color.FromArgb(191, 0, 0, 0);panelMain.Height = 0;Thread_Load = new Thread(() => LoadThread());Thread_Load.Start();Thread_DataDetection = new Thread(() => T_DataDetection());Thread_DataDetection.Start();foreach (Control control in panelMain.Controls)//遍历panel中的所有控件if (!((control is ComboBox) || (control is TextBox) || (control is RichTextBox)))control.BackColor = Color.FromArgb(0, 0, 0, 0);else if (control is ComboBox){ComboBox CB = (ComboBox)control;CB.SelectedIndex = 0;}pictureBox_README.BackColor = Color.FromArgb(64, 0, 0, 0);comboBox_VersionChoose.SelectedIndex = 0;//设置初始选择值#region 关于SelectedIndex的说明/* 0为4.4上半(闲云 纳西妲)* 1为4.4下半(魈 八重神子)*/#endregionlabel1.Text = "还未进行过模拟";}private void T_DataDetection(){bool B = false;//用于判断能否抽卡while(true){if (NUM_Stone >= 160)Invoke(new Action(() => { button_Transport.Enabled = true; }));//跨线程操作else Invoke(new Action(() => { button_Transport.Enabled = false; }));//跨线程操作B = ((NUM_Ball > 0) && (NUM_Stone >= 0)) || ((NUM_Ball == 0) && (NUM_Stone >= 160));if (B && Avaluable)Invoke(new Action(() => { button_Start.Enabled = true; }));//跨线程操作else Invoke(new Action(() => { button_Start.Enabled = false; }));//跨线程操作Thread.Sleep(50);}}//用于检测数据并调控Enable属性的线程private void LoadThread(){do{Invoke(new Action(() =>{panelMain.Height += 20;}));//跨线程操作Thread.Sleep(2);} while (panelMain.Height <= 750);}//黑色半透明下降的动画的线程#region 为获取comboBox控件的SelectedIndex属性而定义的内容// 定义一个委托来执行操作 delegate int GetSelectedIndexDelegate();// 在主线程中执行操作的方法 private int GetCBWNSelectedIndex(){if (comboBox_WeaponN.InvokeRequired){// 如果需要跨线程调用,则使用Invoke return (int)comboBox_WeaponN.Invoke(new GetSelectedIndexDelegate(GetCBWNSelectedIndex));}else{// 直接返回SelectedIndex return comboBox_WeaponN.SelectedIndex;}}#endregionprivate void imitate(int N,int[] Target,CheckBox[] CB, ComboBox comboBox_WN){//Target储存四者的抽取目标double Average_Residue = 0;//平均剩余的粉球for (int i=1;i<=10000;i++){NextRoleIsBig = CB[2].Checked;#region 获取并储存comboBox_WN的SelectedIndex属性值的代码段int CB_WN_SI;//储存comboBox_WN的SelectedIndex属性值CB_WN_SI = GetCBWNSelectedIndex();#endregionif (CB[3].Checked)//定轨不为0/2的情况Num_Weapon_Base = CB_WN_SI + 1;if (CB[3].Checked && CB_WN_SI == 0 && CB[4].Checked)NextWeaponIsUp = true;//定轨0/2歪常驻变成1/2的情况,下次必定是UP武器int N_Ball;if (CB[0].Checked) N_Ball = (int)(N / 0.9);else N_Ball = N;bool[] Process_Role_Weapon = new bool[4] { false, false, false, false };//记录四者的抽取目标达成情况int[] Reality = new int[5] { 0, 0, 0, 0, 0};//记录实际抽取到的数量,第五个表示歪的常驻(包括角色与武器)for (int j = 0; j < 4; j++)if (Target[j] == 0)Process_Role_Weapon[j] = true;//抽取目标为0的直接标记为已达成目标//然后调用方法进行模拟并通过返回值得到消耗的纠缠之缘数量if (!CB[1].Checked){for (int j = 0; j <= 1; j++)if (!Process_Role_Weapon[j])N_Ball -= RolePrayer(Target[j], Reality, Process_Role_Weapon, j);for (int j = 2; j <= 3; j++)if (!Process_Role_Weapon[j])N_Ball -= WeaponPrayer(Target[j], Reality, Process_Role_Weapon, j);}else{//如果勾选了checkBox2,那么优先抽取武器for (int j = 2; j <= 3; j++)if (!Process_Role_Weapon[j])N_Ball -= WeaponPrayer(Target[j], Reality, Process_Role_Weapon, j);for (int j = 0; j <= 1; j++)if (!Process_Role_Weapon[j])N_Ball -= RolePrayer(Target[j], Reality, Process_Role_Weapon, j);}//然后对该次模拟结果进行统计if (i == 1 && N_Ball >= 0) Average_Residue = N_Ball;else if (N_Ball >= 0) Average_Residue = (double)(Average_Residue * (i - 1) + N_Ball) / i;else Average_Residue = (double)(Average_Residue * (i - 1)) / i;//统计平均剩余粉球if (Process_Role_Weapon[0] && Process_Role_Weapon[1] && Process_Role_Weapon[2] && Process_Role_Weapon[3] &&N_Ball>=0){//说明达成目标bool NotOver = true;for (int j = 0; j < 4; j++)NotOver = NotOver && (Reality[j] == Target[j]);NotOver = NotOver && (Reality[4] == 0);if (NotOver) Success[0]++;//这里是恰好达成目标else Success[1]++;//这里是超出预期Success_Sum++;}Invoke(new Action(() =>{if (i != 10000)label1.Text = "已进行" + i.ToString() + "次模拟……";else label1.Text = "已进行10000次模拟,每次模拟投入" + N.ToString() + "纠缠。";label_Succ_1_3.Text = "共计" + Success[0].ToString() + "次出现";label_Succ_2_3.Text = "共计" + Success[1].ToString() + "次出现";label_Succ_3_3.Text = "共计" + Success_Sum.ToString() + "次出现";}));}Avaluable = true;double[] Rate = new double[3] { (double)Success[0] / 10000,(double)Success[1] / 10000,(double)Success_Sum / 10000 };Invoke(new Action(() =>{button_Start.Text = "开始模拟";label_Succ_1_3.Text = "共计" + Success[0].ToString() + "次出现";label_Succ_2_3.Text = "共计" + Success[1].ToString() + "次出现";label_Succ_3_3.Text = "共计" + Success_Sum.ToString() + "次出现";label_Succ_1_2.Text = (Rate[0]*100).ToString() + "%";label_Succ_2_2.Text = (Rate[1]*100).ToString() + "%";label_Succ_3_2.Text = (Rate[2]*100).ToString() + "%";label_Remain.Text = "平均剩余纠缠之缘" + Average_Residue.ToString("F2") + "个";if (Rate[2] >= 0 && Rate[2] <= 0.2)label_Label.Text = "白日做梦";else if (Rate[2] > 0.2 && Rate[2] <= 0.4)label_Label.Text = "考验人品";else if (Rate[2] > 0.4 && Rate[2] <= 0.6)label_Label.Text = "成败参半";else if (Rate[2] > 0.6 && Rate[2] <= 0.8)label_Label.Text = "值得一试";else if (Rate[2] > 0.8 && Rate[2] < 1)label_Label.Text = "十拿九稳";else label_Label.Text = "板上钉钉";label_Remain.Visible = label2.Visible = label_Label.Visible = true;}));//跨线程操作Success[0] = Success[1] = Success_Sum = 0;}//进行抽卡模拟的线程private int RolePrayer(int N,int[] Re, bool[] PRW, int Code){ /* N表示目标抽取数量* Re[5]是储存实际抽到数量的数组* PRW[4]是记录目标达成情况的bool型数组*/int N_Used = 0;//使用的纠缠之缘数量int RandomNumber = 0;int BaoDi = 0;//保底计数器while(Re[Code] < N){RandomNumber = randomNum(1000);BaoDi++;N_Used++;if ((RandomNumber>=1 && RandomNumber<=6)||(BaoDi == 90)){//抽到了5星的情况if (NextRoleIsBig)//如果是大保底{Re[Code]++;NextRoleIsBig = false;}else//小保底但是不确定会不会歪常驻{RandomNumber = randomNum(1000);if (RandomNumber >= 1 && RandomNumber <= 500)//没歪Re[Code]++;else//歪了{Re[4]++;//R[4]表示歪的常驻的数量NextRoleIsBig = true;//下次就是大保底了}}BaoDi = 0;}}PRW[Code] = true;return N_Used;}//角色池祈愿的方法private int WeaponPrayer(int N, int[] Re, bool[] PRW, int Code){ /* N表示目标抽取数量* Re[5]是储存实际抽到数量的数组* PRW[4]是记录目标达成情况的bool型数组*/int N_Used = 0;//使用的纠缠之缘数量int RandomNumber = 0;int BaoDi = 0;//保底计数器if (Code == 3 && Num_Weapon_Base != 0)Num_Weapon_Base = 0;//抽第二把武器的时候更换定轨,归零while (Re[Code] < N){RandomNumber = randomNum(1000);BaoDi++;N_Used++;if ((RandomNumber >= 1 && RandomNumber <= 7) || (BaoDi == 80)){//出金的情况if (Num_Weapon_Base==2)//满定轨的情况{Re[Code]++;//必定出定轨武器Num_Weapon_Base = 0;//定轨归零}else//非满定轨{if (NextWeaponIsUp)//上一次出金歪的常驻{RandomNumber = randomNum(10);//两个UP武器中随机一个出if (RandomNumber>=1 && RandomNumber<=5){//出了定轨武器Re[Code]++;Num_Weapon_Base = 0;}else{//歪了另一把UP武器Num_Weapon_Base++;if (Code == 2) Re[3]++;else Re[2]++;}NextWeaponIsUp = false;}else//上一次没歪常驻,包括定轨0/2时的情况{RandomNumber = randomNum(20);if (RandomNumber >= 1 && RandomNumber <= 15)//75%的概率出UP武器{RandomNumber = randomNum(10);if (RandomNumber >= 1 && RandomNumber <= 5){//没歪Re[Code]++;Num_Weapon_Base = 0;}else{//歪了另一把UP武器Num_Weapon_Base++;if (Code == 2) Re[3]++;else Re[2]++;}}else//25%概率歪常驻了!{NextWeaponIsUp = true;Re[4]++;//获得的常驻数量+1}}}BaoDi = 0;}}PRW[Code] = true;NextWeaponIsUp = false;return N_Used;}//武器池祈愿的方法private int randomNum(int N)//使用RNGCryptoServiceProvider类生成随机数{Random r = new Random();int randomNumber;using (var rng = new RNGCryptoServiceProvider()){// 生成一个随机字节数组 byte[] randomBytes = new byte[4]; // 4 bytes for a uint32 rng.GetBytes(randomBytes);// 将字节数组转换为整数 randomNumber = BitConverter.ToInt32(randomBytes, 0);randomNumber += r.Next();randomNumber = Math.Abs(randomNumber) % N + 1;return randomNumber;}}//生成一个范围在[1,N]的随机数的方法private void comboBox_VersionChoose_SelectedIndexChanged(object sender, EventArgs e){ReTry://如果用户丢失了文件并选择了重试,就跳回这里//label_VersionChoose.Text = comboBox_VersionChoose.SelectedIndex.ToString();//调试用string path;bool FileLose = false;//没有文件丢失就是falsepath = "bins\\" + RoleName[comboBox_VersionChoose.SelectedIndex, 0] + "·头像.png";if (File.Exists(path))PB_Role_1.Image = Image.FromFile(path);else MessageBox.Show("文件丢失:" + path, "文件丢失", MessageBoxButtons.OK, MessageBoxIcon.Error);FileLose = FileLose || (!File.Exists(path));path = "bins\\" + RoleName[comboBox_VersionChoose.SelectedIndex, 1] + "·头像.png";if (File.Exists(path))PB_Role_2.Image = Image.FromFile(path);else MessageBox.Show("文件丢失:" + path, "文件丢失", MessageBoxButtons.OK, MessageBoxIcon.Error);FileLose = FileLose || (!File.Exists(path));path = "bins\\" + RoleName[comboBox_VersionChoose.SelectedIndex, 0] + "专武.png";if (File.Exists(path))PB_Weapon_1.Image = Image.FromFile(path);else MessageBox.Show("文件丢失:" + path, "文件丢失", MessageBoxButtons.OK, MessageBoxIcon.Error);FileLose = FileLose || (!File.Exists(path));path = "bins\\" + RoleName[comboBox_VersionChoose.SelectedIndex, 1] + "专武.png";if (File.Exists(path))PB_Weapon_2.Image = Image.FromFile(path);else MessageBox.Show("文件丢失:" + path, "文件丢失", MessageBoxButtons.OK, MessageBoxIcon.Error);FileLose = FileLose || (!File.Exists(path));if (FileLose){DialogResult DR=MessageBox.Show("文件已丢失,建议旅行者找回丢失资源或尝试卸载并重新安装。", "温馨提示", MessageBoxButtons.RetryCancel, MessageBoxIcon.Information);if (DR == DialogResult.Retry)goto ReTry;else{if (Thread_Load != null)Thread_Load.Abort();if (T_Imitate != null)T_Imitate.Abort();Thread_DataDetection.Abort();Application.Exit();}}foreach (Control C in panelMain.Controls)if ((C is ComboBox) && (C!=comboBox_VersionChoose)){ComboBox CB = (ComboBox)C;CB.SelectedIndex = 0;}}//卡池选择改变时触发private void button_More_Click(object sender, EventArgs e){Form_Poster FP = new Form_Poster(comboBox_VersionChoose.SelectedIndex);FP.Show();}private void panelMain_Paint(object sender, PaintEventArgs e){}private void pictureBox_Exit_Click(object sender, EventArgs e){DialogResult DR = MessageBox.Show("确认退出软件?", "询问", MessageBoxButtons.OKCancel);if (DR == DialogResult.OK){DialogResult Dr = MessageBox.Show("祝屏幕前的旅行者十连多金、小保底不歪!", "诚挚的祝福", MessageBoxButtons.OK);if (Dr==DialogResult.OK){if (Thread_Load != null)Thread_Load.Abort();if (T_Imitate != null)T_Imitate.Abort();Thread_DataDetection.Abort();Application.Exit();}}}private void textBox_Ball_TextChanged(object sender, EventArgs e){if (textBox_Ball.Text == "") textBox_Ball.Text = "0";else if ((textBox_Ball.Text[0]=='0') && (textBox_Ball.Text.Length == 2))//去掉多余的0,包括光标在0右侧时输入的情况textBox_Ball.Text = textBox_Ball.Text[1].ToString();//接下来将Text属性转化为数据并存储入NUM_Balltry{NUM_Ball = int.Parse(textBox_Ball.Text);}catch (FormatException){// 转换失败,用户可能输入了非数字字符 MessageBox.Show("包含非法字符,该输入框已清空,请输入有效的数字以表示拥有的纠缠之缘的数量!", "数据无效",MessageBoxButtons.OK,MessageBoxIcon.Warning);textBox_Ball.Text = "0";NUM_Ball = 0;return;}textBox_Ball.SelectionStart = textBox_Ball.Text.Length;//每次将光标移动到末尾}private void textBox_Stone_TextChanged(object sender, EventArgs e){if (textBox_Stone.Text == "") textBox_Stone.Text = "0";else if ((textBox_Stone.Text[0] == '0') && (textBox_Stone.Text.Length == 2))//去掉多余的0,包括光标在0右侧时输入的情况textBox_Stone.Text = textBox_Stone.Text[1].ToString();//接下来将Text属性转化为数据并存储入NUM_Stonetry{NUM_Stone = int.Parse(textBox_Stone.Text);}catch (FormatException){// 转换失败,用户可能输入了非数字字符 MessageBox.Show("包含非法字符,该输入框已清空,请输入有效的数字以表示拥有的原石的数量!", "数据无效", MessageBoxButtons.OK, MessageBoxIcon.Warning);textBox_Stone.Text = "0";NUM_Stone = 0;return;}textBox_Stone.SelectionStart = textBox_Stone.Text.Length;//每次将光标移动到末尾}private void checkBox4_CheckedChanged(object sender, EventArgs e){if (checkBox4.Checked)comboBox_WeaponN.Enabled = true;else comboBox_WeaponN.Enabled = false;if (checkBox4.Checked && comboBox_WeaponN.SelectedIndex == 0)checkBox5.Enabled = true;else checkBox5.Enabled = false;}private void comboBox_Weapon_1_SelectedIndexChanged(object sender, EventArgs e){if (comboBox_Weapon_1.SelectedIndex + comboBox_Weapon_2.SelectedIndex == 0)checkBox5.Enabled = checkBox4.Enabled = false;else checkBox5.Enabled = checkBox4.Enabled = true;//不计划抽取武器,则无法选取武器池定轨选项if ((comboBox_Weapon_1.SelectedIndex + comboBox_Weapon_2.SelectedIndex == 0) ||(comboBox_Role_1.SelectedIndex + comboBox_Role_2.SelectedIndex == 0))checkBox2.Enabled = false;else checkBox2.Enabled = true;//武器角色二种只抽取一种则无法选取“优先抽取武器”}private void comboBox_Weapon_2_SelectedIndexChanged(object sender, EventArgs e){if (comboBox_Weapon_1.SelectedIndex + comboBox_Weapon_2.SelectedIndex == 0)checkBox5.Enabled = checkBox4.Enabled = false;else checkBox5.Enabled = checkBox4.Enabled = true;//不计划抽取武器,则无法选取武器池定轨选项if ((comboBox_Weapon_1.SelectedIndex + comboBox_Weapon_2.SelectedIndex == 0) ||(comboBox_Role_1.SelectedIndex + comboBox_Role_2.SelectedIndex == 0))checkBox2.Enabled = false;else checkBox2.Enabled = true;//武器角色二种只抽取一种则无法选取“优先抽取武器”}private void comboBox_Role_1_SelectedIndexChanged(object sender, EventArgs e){if ((comboBox_Weapon_1.SelectedIndex + comboBox_Weapon_2.SelectedIndex == 0) ||(comboBox_Role_1.SelectedIndex + comboBox_Role_2.SelectedIndex == 0))checkBox2.Enabled = false;else checkBox2.Enabled = true;//武器角色二种只抽取一种则无法选取“优先抽取武器”if (comboBox_Role_1.SelectedIndex + comboBox_Role_2.SelectedIndex == 0)checkBox1.Enabled = checkBox3.Enabled = false;else checkBox1.Enabled = checkBox3.Enabled = true;//不抽取角色则无法选择“角色卡池为9折”}private void comboBox_Role_2_SelectedIndexChanged(object sender, EventArgs e){if ((comboBox_Weapon_1.SelectedIndex + comboBox_Weapon_2.SelectedIndex == 0) ||(comboBox_Role_1.SelectedIndex + comboBox_Role_2.SelectedIndex == 0))checkBox2.Enabled = false;else checkBox2.Enabled = true;//武器角色二种只抽取一种则无法选取“优先抽取武器”if (comboBox_Role_1.SelectedIndex + comboBox_Role_2.SelectedIndex == 0)checkBox1.Enabled = checkBox3.Enabled = false;else checkBox1.Enabled = checkBox3.Enabled = true;//不抽取角色则无法选择“角色卡池为9折”}private void button_Transport_Click(object sender, EventArgs e){if (NUM_Stone>=160){NUM_Ball += NUM_Stone / 160;NUM_Stone = NUM_Stone - NUM_Stone / 160 * 160;textBox_Ball.Text = NUM_Ball.ToString();textBox_Stone.Text = NUM_Stone.ToString();}}private void button_Start_Click(object sender, EventArgs e){int Ball = NUM_Ball + NUM_Stone / 160;//抽取的次数bool NotSelectedTarget = (comboBox_Role_1.SelectedIndex == 0) && (comboBox_Role_2.SelectedIndex == 0) && (comboBox_Weapon_1.SelectedIndex == 0) && (comboBox_Weapon_2.SelectedIndex == 0);//如果全部为0,就说明没有选择,那么值为trueif ((Ball>0 && Ball<=999)&&(checkBox_Ensure.Checked)&&(!NotSelectedTarget)){//先将数据清空表示所有给出的资源全部用于抽卡NUM_Ball = 0;NUM_Stone -= NUM_Stone / 160 * 160;textBox_Ball.Text = NUM_Ball.ToString();textBox_Stone.Text = NUM_Stone.ToString();label_Succ_1_3.Visible = label_Succ_2_3.Visible = label_Succ_3_3.Visible = true;//接下来调用线程进行模拟int[] Temp = new int[4] {comboBox_Role_1.SelectedIndex,comboBox_Role_2.SelectedIndex,comboBox_Weapon_1.SelectedIndex,comboBox_Weapon_2.SelectedIndex};//简单粗暴地避免跨线程访问问题NextRoleIsBig = checkBox3.Checked;if (checkBox4.Checked)//定轨不为0/2的情况Num_Weapon_Base = comboBox_WeaponN.SelectedIndex + 1;if (checkBox4.Checked && comboBox_WeaponN.SelectedIndex == 0 && checkBox5.Checked)NextWeaponIsUp = true;//定轨0/2歪常驻变成1/2的情况,下次必定是UP武器CheckBox[] CB = new CheckBox[5] { checkBox1, checkBox2, checkBox3, checkBox4, checkBox5 };T_Imitate = new Thread(() => imitate(Ball,Temp, CB, comboBox_WeaponN));T_Imitate.Start();Avaluable = false;button_Start.Text = "正在模拟,请稍等……";}else if (!(checkBox_Ensure.Checked))MessageBox.Show("请仔细阅读用户须知并勾选下方选项!");else{if (NotSelectedTarget)MessageBox.Show("请选择你的抽取目标!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Information);else{MessageBox.Show("填入的已有资源超过允许模拟的最大限度!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);NUM_Ball = NUM_Stone = 0;textBox_Ball.Text = textBox_Stone.Text = "0";}}textBox_Ball.SelectionStart = textBox_Ball.Text.Length;}private void linkLabel_ScreenShot_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e){try{linkLabel_ScreenShot.Visible = false;//接下来开始截图与保存操作Bitmap BM = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);using (Graphics G = Graphics.FromImage(BM)){G.CopyFromScreen(this.PointToScreen(new Point(0, 0)), Point.Empty, this.ClientSize);}DateTime CurruntTime = DateTime.Now;string FileName = "ScreenShot_" + CurruntTime.ToString("yyyyMMddHHmmss") + ".png";BM.Save("bins\\ScreenShot\\" + FileName, System.Drawing.Imaging.ImageFormat.Png);//到此linkLabel_ScreenShot.Visible = true;MessageBox.Show("截图已保存至 安装目录/bins/ScreenShot/" + FileName);}catch(Exception Ex){MessageBox.Show("发生错误:" + Ex.Message);}}private void label_Succ_2_2_Click(object sender, EventArgs e){}private void label_Succ_2_3_Click(object sender, EventArgs e){}private void label_Succ_2_1_Click(object sender, EventArgs e){}private void comboBox_WeaponN_SelectedIndexChanged(object sender, EventArgs e){if (checkBox4.Checked && comboBox_WeaponN.SelectedIndex == 0)checkBox5.Enabled = true;else checkBox5.Enabled = false;}private void checkBox1_CheckedChanged(object sender, EventArgs e){}private void pictureBox_README_Click(object sender, EventArgs e){README RM = new README();RM.Show();}}
}
2.Form_Poster页面(祈愿海报页面)
设计器:
页面代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.IO;namespace 概率计算器___Genshin_Impact
{public partial class Form_Poster : Form{public Form_Poster(int N_Mode){InitializeComponent();Mode = N_Mode;pictureBox_Down.DoubleClick += pictureBox_Down_Click;pictureBox_Up.DoubleClick += pictureBox_Up_Click;}#region 变量的声明public int Mode = 0;Thread TTF = null;public int CurruntPage = 1;string[,] RoleName = new string[4, 2] {{"娜维娅", "神里绫华" },//4.3上半卡池,卡池编码为0{"雷电将军", "宵宫" },//4.3下半卡池,卡池编码为1{ "闲云", "纳西妲" }, //4.4上半卡池,卡池编码为2{ "魈", "八重神子" }//4.4下半卡池,卡池编码为3};//第一维度为版本编号,第二维度为卡池序号//比如4.4上半对应第一维度,而角色祈愿-2对应第二维度//角色池图片名称为RoleName[m,n] + ".png"//武器池图片名称为RoleName[m,0] + "-" + RoleName[m,1] + "-专武.png"#endregionprivate void Form_Poster_Load(object sender, EventArgs e){this.Opacity = 0;TTF = new Thread(() => Thread_TransparencyFade());TTF.Start();foreach (Control Con in this.Controls)Con.BackColor = Color.FromArgb(0, 0, 0, 0);ReTrySearchFile://如果选择ReTry就跳回这里string path;bool FileLose = false;//文件没丢失就是falsepath = "bins\\" + RoleName[Mode, 0] + ".png";if (File.Exists(path))pictureBox_Role_1.Image = Image.FromFile(path);else MessageBox.Show("文件丢失:" + path, "文件丢失", MessageBoxButtons.OK, MessageBoxIcon.Error);FileLose = FileLose || (!File.Exists(path));path = "bins\\" + RoleName[Mode, 1] + ".png";if (File.Exists(path))pictureBox_Role_2.Image = Image.FromFile(path);else MessageBox.Show("文件丢失:" + path, "文件丢失", MessageBoxButtons.OK, MessageBoxIcon.Error);FileLose = FileLose || (!File.Exists(path));path = "bins\\" + RoleName[Mode, 0] + "-" + RoleName[Mode, 1] + "-专武.png";if (File.Exists(path))pictureBox_Weapon.Image = Image.FromFile(path);else MessageBox.Show("文件丢失:" + path, "文件丢失", MessageBoxButtons.OK, MessageBoxIcon.Error);FileLose = FileLose || (!File.Exists(path));if (FileLose){//文件已丢失DialogResult DR = MessageBox.Show("文件已丢失,建议旅行者找回丢失资源或尝试卸载并重新安装。", "温馨提示", MessageBoxButtons.RetryCancel, MessageBoxIcon.Information);if (DR == DialogResult.Retry)goto ReTrySearchFile;else{if (TTF != null)TTF.Abort();Application.Exit();}}pictureBox_Role_2.Location = pictureBox_Weapon.Location = pictureBox_Role_1.Location;pictureBox_Role_2.Visible = pictureBox_Weapon.Visible = false;}private void Thread_TransparencyFade(){int transparency = -5;do{transparency += 5;Invoke(new Action(() =>{this.Opacity = (double)transparency / 100;}));//跨线程操作Thread.Sleep(5);} while (transparency < 100);}//透明淡入的线程private void Thread_Out(){int transparency = 105;do{transparency -= 5;Invoke(new Action(() =>{this.Opacity = (double)transparency / 100;}));//跨线程操作Thread.Sleep(5);} while (transparency > 0);Invoke(new Action(() =>{this.Close();}));//跨线程操作}//透明淡出的线程private void pictureBox_Out_Click(object sender, EventArgs e){if (TTF != null){TTF.Abort();TTF = new Thread(() => Thread_Out());TTF.Start();}}private void pictureBox_Up_Click(object sender, EventArgs e){if (CurruntPage >= 2) CurruntPage--;else CurruntPage = 3;switch(CurruntPage){case 1:pictureBox_Role_2.Visible = false;pictureBox_Role_1.Visible = true;break;case 2:pictureBox_Weapon.Visible = false;pictureBox_Role_2.Visible = true;break;case 3:pictureBox_Role_1.Visible = false;pictureBox_Weapon.Visible = true;break;}}private void pictureBox_Down_Click(object sender, EventArgs e){if (CurruntPage <= 3) CurruntPage++;else CurruntPage = 1;switch (CurruntPage){case 1:pictureBox_Weapon.Visible = false;pictureBox_Role_1.Visible = true;break;case 2:pictureBox_Role_1.Visible = false;pictureBox_Role_2.Visible = true;break;case 3:pictureBox_Role_2.Visible = false;pictureBox_Weapon.Visible = true;break;}}}
}
3.README页面(说明页面)
设计器:
页面代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;namespace 概率计算器___Genshin_Impact
{public partial class README : Form{public README(){InitializeComponent();}private void README_Load(object sender, EventArgs e){}private void label_Link_Click(object sender, EventArgs e){try{Process.Start("http://sherrychou.blog.csdn.net");}catch (Exception E){MessageBox.Show("出现错误:" + E.Message, "出错啦", MessageBoxButtons.OK, MessageBoxIcon.Error);}this.Close();}private void pictureBox1_Click(object sender, EventArgs e){}}
}
4. 应用程序清单文件
将以下代码取消注释。
<application xmlns="urn:schemas-microsoft-com:asm.v3"><windowsSettings><dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware></windowsSettings></application>
四、其他说明
1.本软件不用于盈利,也不允许被用于盈利,如发现用该软件盈利的行为,欢迎举报!
2.本软件内的一切图片素材版权仍归 上海米哈游网络科技股份有限公司 与 上海米哈游天命科技有限公司 所有。
3.使用过程中如发现任何不应该出现的技术问题,欢迎联系作者反馈!
文章字数统计君:22565字
相关文章:

[WinForm开源]概率计算器 - Genshin Impact(V1.0)
创作目的:为方便旅行者估算自己拥有的纠缠之缘能否达到自己的目的,作者使用C#开发了一款小型软件供旅行者参考使用。 创作说明:此软件所涉及到的一切概率与规则完全按照游戏《原神》(V4.4.0)内公示的概率与规则(包括保底机制&…...

vscode 代码调试from IPython import embed
一、讲解 这种代码调试方法非常的好用。 from IPython import embed上面的代码片段是用于Python中嵌入一个交互式IPython shell的方法。这可以在任何Python脚本或程序中实现,允许在执行到该点时暂停程序,并提供一个交互式环境,以便于检查、…...

双活工作关于nacos注册中心的数据迁移
最近在做一个双活的项目,在纠结一个注册中心是在双活机房都准备一个,那主机房的数据如果传过去呢,查了一些资料,最终在官网查到了一个NacosSync 的组件,主要用来做数据传输的,并且支持在线替换注册中心的&a…...

5G NR 信道号计算
一、5G NR的频段 增加带宽是增加容量和传输速率最直接的方法,目前5G最大带宽将会达到400MHz,考虑到目前频率占用情况,5G将不得不使用高频进行通信。 3GPP协议定义了从Sub6G(FR1)到毫米波(FR2)的5G目标频谱。 其中FR1是5G的核心频段࿰…...

01-Spring实现重试和降级机制
主要用于在模块调用中,出现失败、异常情况下,仍需要进行重复调用。并且在最终调用失败时,可以采用降级措施,返回一般结果。 1、重试机制 我们采用spring 提供的retry 插件,其原理采用aop机制,所以需要额外…...

docker部署showdoc
目录 安装 1.拉取镜像 2.创建容器 使用 1.选择语言 2.默认账户/密码:showdoc/123456编辑 3.登陆 4.首页 安装 1.拉取镜像 docker pull star7th/showdoc 2.创建容器 mkdir -p /opt/showdoc/html docker run -d --name showdoc --userroot --privilegedtrue -p 1005…...

2.14作业
1.请编程实现二维数组的杨辉三角。 2.请编程实现二维数组计算每一行的和以及列和。 3.请编程实现二维数组计算第二大值。 4.请使用非函数方法实现系统函数strcat,strcmp,strcpy,strlen. strcat: strcmp: strcpy: strlen:...

01.数据结构篇-链表
1.找出两个链表的交点 160. Intersection of Two Linked Lists (Easy) Leetcode / 力扣 例如以下示例中 A 和 B 两个链表相交于 c1: A: a1 → a2↘c1 → c2 → c3↗ B: b1 → b2 → b3 但是不会出现以下相交的情况,因为每个节点只有一个…...

揭秘产品迭代计划制定:从0到1打造完美迭代策略
产品迭代计划是产品团队确保他们能够交付满足客户需求的产品以及实现其业务目标的重要工具。开发一个成功的产品迭代计划需要仔细考虑产品的目标、客户需求、市场趋势和可用资源。以下是帮助您创建产品迭代计划的一些步骤:建立产品目标、收集客户反馈、分析市场趋势…...

Python进阶--下载想要的格言(基于格言网的Python爬虫程序)
注:由于上篇帖子(Python进阶--爬取下载人生格言(基于格言网的Python3爬虫)-CSDN博客)篇幅长度的限制,此篇帖子对上篇做一个拓展延伸。 目录 一、爬取格言网中想要内容的url 1、找到想要的内容 2、抓包分析,找到想…...

C语言--------数据在内存中的存储
1.整数在内存中的存储 整数在内存是以补码的形式存在的; 整型家族包括char,int ,long long,short类型; 因为char类型是以ASCII值形式存在,所以也是整形家族; 这四种都包括signed,unsigned两种,即有符号和无符号&am…...

【Java】零基础蓝桥杯算法学习——线性动态规划(一维dp)
线性dp——一维动态规划 1、考虑最后一步可以由哪些状态得到,推出转移方程 2、考虑当前状态与哪些参数有关系,定义几维数组来表示当前状态 3、计算时间复杂度,判断是否需要进行优化。 一维动态规划例题:最大上升子序列问题 Java参…...

Excel模板1:彩色甘特图
Excel模板1:彩色甘特图 分享地址 当前效果:只需要填写进度, 其余效果都是自动完成的 。 阿里网盘永久分享:https://www.alipan.com/s/cXhq1PNJfdm 省心。能用公式的绝不使用手动输入。 这个区域以及标题可以手动输入…...

如何重新安装 macOS
你可以使用电脑的内建恢复系统“macOS 恢复”来重新安装 Mac 操作系统。不但简单快捷,而且重新安装后不会移除你的个人数据。 将 Mac 关机 选取苹果菜单 >“关机”,然后等待 Mac 关机。如果你无法将 Mac 关机,请按住它的电源按钮最长 …...

论文阅读-Pegasus:通过网络内一致性目录容忍分布式存储中的偏斜工作负载
论文名称:Pegasus: Tolerating Skewed Workloads in Distributed Storage with In-Network Coherence Directories 摘要 高性能分布式存储系统面临着由于偏斜和动态工作负载引起的负载不平衡的挑战。本文介绍了Pegasus,这是一个利用新一代可编程交换机…...
【PTA|编程题|期末复习】字符串(一)
【C语言/期末复习】字符和字符串函数(附思维导图/例题) 目录 7-1 组织星期信息 输入样例 (repeat3) : 输出样例: 代码 7-2 查找指定字符 输入格式: 输出格式: 输入样例1: 输出样例1: 输入样例2: …...

数据库基本操作2
一.DML(Data Manipulation Language) 用来对数据库中表的数据记录进行更新 关键字:增删改 插入insert 删除delete 更新update 1.数据插入 insert into 表(列名1,列名2,列名3……)values&a…...
BTC破5W+QAQ
比特币突破5万美元 创2021年来最高 比特币在龙年伊始涨超6.8%。在大年初四(2月13日)一度最高涨至5万零383美元。 今年1月,当市场期待已久的现货比特币交易所挂牌基金(ETF)推出后,比特币遭抛售,…...

Xubuntu16.04系统中修改系统语言和系统时间
1.修改系统语言 问题:下图显示系统语言不对 查看系统中可用的所有区域设置的命令 locale -a修改/etc/default/locale文件 修改后如下: # File generated by update-locale LANG"en_US.UTF-8" LANGUAGE"en_US:en"LANG"en_US…...

内网穿透 | 推荐两个免费的内网穿透工具
目录 1、简介 2、Ngrok 2.1、下载安装 2.2、运行 2.3、固定域名 2.4、配置多服务 3、cpolar 3.1、下载安装 3.2、运行 🍃作者介绍:双非本科大三网络工程专业在读,阿里云专家博主,专注于Java领域学习,擅长web应…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...

MyBatis中关于缓存的理解
MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...