[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"
        #endregion

        private 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下半(魈 八重神子)
             */
            #endregion

            label1.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;
            }
        }
        #endregion

        private 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();
                #endregion

                if (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;//没有文件丢失就是false

            path = "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_Ball
            try
            {
                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_Stone
            try
            {
                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,就说明没有选择,那么值为true
            if ((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"
        #endregion

        private 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;//文件没丢失就是false

            path = "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字

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/386188.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

BUGKU-WEB GET

题目描述 没有提示&#xff0c;就一个get&#xff0c;启动场景看看&#xff1a; 解题思路 显然是PHP语言解读分析代码吧写出你的payload 相关工具 略 解题步骤 进入场景分析代码 $what$_GET[what]; echo $what; if($whatflag) echo flag{****};前两句&#xff1a;使用get…

扩展速度提高了12倍!AWS Lambda 函数重大改进!

Marcia 是 Amazon Web Services 的首席开发倡导者&#xff0c;在软件行业构建和扩展应用程序方面拥有20年的工作经验。她热衷于设计能够充分利用云并拥抱DevOps文化的系统。最近她发表了一篇博文&#xff0c;带来了一个AWS Lambda重大改进&#xff1a;扩展速度提升了 12 倍&…

VUE学习——表单的输入绑定

使用【v-model】。 输入框 <template><h1>表单输入绑定</h1><input type"text" v-model"message"><p>输入的值&#xff1a;{{ message }}</p> </template> <script>export default{data(){return{messa…

Rabbit和Springboot整合(高阶)

在昨天的练习作业中&#xff0c;我们改造了余额支付功能&#xff0c;在支付成功后利用RabbitMQ通知交易服务&#xff0c;更新业务订单状态为已支付。 但是大家思考一下&#xff0c;如果这里MQ通知失败&#xff0c;支付服务中支付流水显示支付成功&#xff0c;而交易服务中的订单…

Python算法题集_LRU 缓存

Python算法题集_LRU 缓存 题146&#xff1a;LRU 缓存1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【队列字典】2) 改进版一【有序字典】3) 改进版二【双向链表字典】 4. 最优算法 本文为Python算法题集之一的代码示例 题146&#xff1a;LRU …

Xubuntu16.04系统中修改系统语言和系统时间

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

力扣hot2--哈希

推荐博客&#xff1a; for(auto i : v)遍历容器元素_for auto 遍历-CSDN博客 字母异位词都有一个特点&#xff1a;也就是对这个词排序之后结果会相同。所以将排序之后的string作为key&#xff0c;将排序之后能变成key的单词组vector<string>作为value。 class Solution …

【Linux】线程概念和线程控制

线程概念 一、理解线程1. Linux中的线程2. 重新定义线程和进程3. 进程地址空间之页表4. 线程和进程切换5. 线程的优点6. 线程的缺点7. 线程异常8. 线程用途9. 线程和进程 二、线程控制1. pthread 线程库&#xff08;1&#xff09;pthread_create()&#xff08;2&#xff09;pth…

点击侧边栏菜单时只切换 <router-view> 中的内容,而不是进行整个页面的路由跳转(动态路由)

解决方法&#xff1a;在 <el-menu> 的 select 事件中调用了 handleMenuSelect 方法来处理菜单项的选择。你可以在 handleMenuSelect 方法中根据菜单项的 index 来执行相应的操作&#xff0c;例如更新组件内的数据或者切换组件。由于整个页面的路由路径并没有改变&#xf…

【教程】MySQL数据库学习笔记(三)——数据定义语言DDL(持续更新)

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【MySQL数据库学习】系列文章 第一章 《认识与环境搭建》 第二章 《数据类型》 第三章 《数据定义语言DDL》 文章目录 【MyS…

智能汽车行业产业研究报告:4D成像毫米波雷达—自动驾驶最佳辅助

今天分享的是智能汽车系列深度研究报告&#xff1a;《智能汽车行业产业研究报告&#xff1a;4D成像毫米波雷达—自动驾驶最佳辅助》。 &#xff08;报告出品方&#xff1a;开源证券&#xff09; 报告共计&#xff1a;43页 视觉感知最佳辅助——4D 成像毫米波雷达 感知是自动…

Excel模板1:彩色甘特图

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

C++PythonC# 三语言OpenCV从零开发(8):图像平滑处理

文章目录 相关链接前言图像资源图像平滑处理图像学知识补充(重点)什么是卷积什么是图像滤波什么是方框滤波和均值滤波 代码PythonCCsharp 总结 相关链接 C&Python&Csharp in OpenCV 专栏 【2022B站最好的OpenCV课程推荐】OpenCV从入门到实战 全套课程&#xff08;附带课…

【C++】内存五大区详解

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

【C语言】指针专项练习 都是一些大厂的笔试真题 附有详细解析,带你深入理解指针

一.sizeof()与strlen() sizeof是一个操作符&#xff0c;而strlen是一个库函数。 数组名代表首元素地址&#xff0c;有两种情况例外&#xff0c;第一种是数组名单独放在sizeof内部&#xff0c;第二种是&数组名&#xff0c;这两种情况下数组名代表的是整个数组。sizeof(arr…

【教程】Kotlin语言学习笔记(一)——认识Kotlin(持续更新)

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【Kotlin语言学习】系列文章 第一章 《认识Kotlin》 文章目录 【Kotlin语言学习】系列文章一、Kotlin介绍二、学习路径 一、…

huggingface学习|用dreambooth和lora对stable diffusion模型进行微调

目录 用dreambooth对stable-diffusion-v1-5模型进行微调&#xff08;一&#xff09;模型下载和环境配置&#xff08;二&#xff09;数据集准备&#xff08;三&#xff09;模型微调&#xff08;四&#xff09;运行微调后的模型 用lora对stable-diffusion-v1-5模型进行微调&#…

在小区门口开什么店比较好?把握商机从这里开始

作为一位资深的鲜奶吧创业者&#xff0c;我已经在这个行业摸爬滚打了五年。这五年的时间里&#xff0c;我见证了社区商业的繁荣与变迁&#xff0c;也深刻体会到了在小区门口开店的商机与挑战。今天&#xff0c;我想和大家分享一些关于在小区门口开店的见解&#xff0c;特别是针…

【Linux】Kali Linux 系统安装详细教程(虚拟机)

目录 1.1 Kali linux简介 1.2 Kali Linux工具 1.3 VMware workstation和ESXi的区别 二、安装步骤 一、Kali概述 1.1 Kali linux简介 Kali Linux是基于Debian的Linux发行版&#xff0c; 设计用于数字取证操作系统。每一季度更新一次。由Offensive Security Ltd维护和资助。最…

【C语言】【力扣】7.整数反转和9.回文数

一、整数反转 1.1 个人思考过程 初解&#xff1a;出现ERROR&#xff0c;数据溢出的情况下应该返回0。&#xff08;错误&#xff09; int reverse(int x){int y0;while(x!0){yy*10x%10;x/10; }return y; } 再解&#xff1a;加上数据溢出判断条件。&#xff08;正确&#…
最新文章