今日突发奇想,能否写一个手游CFM的比赛竞猜计算器,辅助计算投入与收益
这不会绝对的计算出收益最好的情况、但能平均计算出不会亏损的0收益或者少量正收益情况
文章提供测试代码讲解、测试效果图、整体测试工程下载
目录
功能说明:
这是基于cfm穿越火线手游的比赛竞猜设计开发的计算器
比赛规则上可以双压、多压注
但只有俩种情况会获得收益:即压对某队胜以及押对某个比分
主要设计功能如下:
1、可以勾选排除掉不可能的比分或者队伍胜利情况
2、三种算法供选择
程序设计与问题解决:
主要用到的控件有:
button、checkbox、textbox、listview、picturebox等
这里就不一一介绍对应元素组件了
主要用到的知识:
winform日志的添加与使用、C#委托、中小学数学计算、冒泡排序、日志打印拼接的汉字字符串
定义float数组变量:
在定义变量方面,多数使用了float类型,并且定义了GetBools数组来检验该比分情况是否被选中为不可能事件
bool[] GetBools = new bool[7]; //所有事件标记true表示可能,false表示不可能无需考虑
float[] tex = new float[7]; //各个情况胜出的倍率
float[] PUT = new float[7]; //各个情况压注建议
float prophey_coin; //预言币数量
bool calculate_flag = true; //检查数据是否全部能被读取计算的标志
float profit_coin; //盈利
日志打印变量_拼接中文字符串:
在常规使用日志的时候发现,在写委托时我们的日志打印是不支持类似于Console.WriteLine方法那样的可以带变量输出的打印:
addlog写日志委托方法并不支持输出变量:
Console.WriteLine方法能够输出变量:
这时我们只需进行一次中间转换即可在日志输出变量的值:
1、先定义一个 string formattedLogMessage,用于存储字符串
2、调用string.Format方法进行将变量复制进字符串的操作
3、直接将formattedLogMessage提交给myaddlog方法打印
string formattedLogMessage;
// 使用string.Format来创建包含变量值的日志字符串
formattedLogMessage = string.Format("平均每个比分投入{0}预言币", PUTT);
myaddlog(1,formattedLogMessage);
平均分配计算方法:
主要设计步骤如下:
1、sum累加所有没被勾选的 可能发生的比赛情况
2、根据预言币总数与sum的值计算出平均投入PUTT
3、全部遍历并用Switch筛选输出收益计算情况
//平均分配计算 收益与打印:
private void Average_Calculation()
{
int sum; //可投入倍率总数
float PUTT; //平均每个项目投入
string formattedLogMessage;
sum = 0;
profit_coin = 0;
for (int i=1;i<=6;i++)
{
if (GetBools[i]==true)
{sum++;}
}
PUTT = prophey_coin / sum;
// 使用string.Format来创建包含变量值的日志字符串
formattedLogMessage = string.Format("平均每个比分投入{0}预言币", PUTT);
myaddlog(1,formattedLogMessage);
/*数组下标提示
红队胜倍率tex1: 蓝队胜倍率tex2: 红蓝2:0倍率tex3:
红蓝2:1倍率tex4: 红蓝1:2倍率tex5: 红蓝0:2倍率tex6:
*/
for (int i = 1; i <= 6; i++)
{
switch(i)
{
case 1:
if(GetBools[1] == true)
{
profit_coin = PUTT* tex[1];
formattedLogMessage = string.Format("如果压中红队胜,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 2:
if (GetBools[2] == true)
{
profit_coin = PUTT * tex[2];
formattedLogMessage = string.Format("如果压中蓝队胜,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 3:
if (GetBools[3] == true)
{
profit_coin = PUTT * tex[3];
formattedLogMessage = string.Format("如果压中红蓝2:0,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 4:
if (GetBools[4] == true)
{
profit_coin = PUTT * tex[4];
formattedLogMessage = string.Format("如果压中红蓝2:1,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 5:
if (GetBools[5] == true)
{
profit_coin = PUTT * tex[5];
formattedLogMessage = string.Format("如果压中红蓝1:2,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 6:
if (GetBools[6] == true)
{
profit_coin = PUTT * tex[6];
formattedLogMessage = string.Format("如果压中红蓝0:2,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
}
}
}
随机分配计算方法:
这没什么可以讲的,主要是随机数的生成方法的使用:
//随机数生成
//(float)(random.NextDouble() * (max - min) + min); // 生成一个在[min, max)范围内的随机数在写函数时考虑到随机数生成的科学性,也询问过AI得知了“剩余法”或“狄利克雷过程”的变体来生成这些随机数的方法,但并未使用,而是直接简单粗暴地将每次生成随机数的最小值定义为max的1/3,但max会在每次生成随机数之后减去生成过的值
//随机分配计算
private void Random_calculation()
{
string formattedLogMessage;
Random random = new Random();//随机数生成
float max, min;
max = prophey_coin;
min = 10;
int last_flag ; //标记最后一个随机数
myaddlog(1, "随机押注情况如下:");
//随机数生成
//(float)(random.NextDouble() * (max - min) + min); // 生成一个在[min, max)范围内的随机数
for (int i = 1; i <= 6; i++)
{
if (GetBools[i] == true)
{
last_flag = i;
PUT[i] = (float)(random.NextDouble() * (max - min) + min);
max -= PUT[i]; //最大区间减少
min = max / 3; //合理化最小值
switch (i)
{
case 1:
formattedLogMessage = string.Format("红队胜,随机压注{0}预言币", PUT[1]);
myaddlog(1, formattedLogMessage);
break;
case 2:
formattedLogMessage = string.Format("蓝队胜,随机压注{0}预言币", PUT[2]);
myaddlog(1, formattedLogMessage);
break;
case 3:
formattedLogMessage = string.Format("红蓝2:0,随机压注{0}预言币", PUT[3]);
myaddlog(1, formattedLogMessage);
break;
case 4:
profit_coin = PUT[4] * tex[4];
formattedLogMessage = string.Format("红蓝2:1,随机压注{0}预言币", PUT[4]);
myaddlog(1, formattedLogMessage);
break;
case 5:
formattedLogMessage = string.Format("红蓝1:2,随机压注{0}预言币", PUT[5]);
myaddlog(1, formattedLogMessage);
break;
case 6:
formattedLogMessage = string.Format("红蓝0:2,随机压注{0}预言币", PUT[6]);
myaddlog(1, formattedLogMessage);
break;
}
}
}
for (int i = 1; i <= 6; i++)
{
switch (i)
{
case 1:
if (GetBools[1] == true)
{
profit_coin = PUT[1] * tex[1];
formattedLogMessage = string.Format("如果压中红队胜,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 2:
if (GetBools[2] == true)
{
profit_coin = PUT[2] * tex[2];
formattedLogMessage = string.Format("如果压中蓝队胜,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 3:
if (GetBools[3] == true)
{
profit_coin = PUT[3] * tex[3];
formattedLogMessage = string.Format("如果压中红蓝2:0,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 4:
if (GetBools[4] == true)
{
profit_coin = PUT[4] * tex[4];
formattedLogMessage = string.Format("如果压中红蓝2:1,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 5:
if (GetBools[5] == true)
{
profit_coin = PUT[5] * tex[5];
formattedLogMessage = string.Format("如果压中红蓝1:2,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 6:
if (GetBools[6] == true)
{
profit_coin = PUT[6] * tex[6];
formattedLogMessage = string.Format("如果压中红蓝0:2,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
}
}
}
基于倍率分配计算方法:
这个计算方法的原理是根据倍率比例来分配预言币,倍率越大,投注比例就会越小
这需要用到冒泡排序,而且还要剔除掉不可能的比赛情况,处理起来也是有些麻烦:
1、获取所有有可能的比赛情况的倍率存入Foad1_sort中
2、对Foad1_sort进行冒泡排序,排序元素总个数就是foad_cnt的值
3、根据倍率计算投注比例,注意要将Foad1_sort排序的倍率与比赛倍率联系起来,因此我用俩个循环来解决,一个用于遍历排序好的Foad1_sort,一个用于依次校对是哪个比分的倍率,得到那个比分的数组下标x,依据这个下标来进行对应比分投入PUT[x]的计算
4、最后根据GetBools[]标记的不可能情况,进行全部遍历输出结果即可
//基于倍率的计算
private void Foad_Calculation()
{
float[] Foad1_sort = new float[6];//排序收集到的倍率
int foad_cnt; //Foad1_sort数组的下标
float temp; //冒泡排序用
float Foad1_sum; //倍率之和
string formattedLogMessage; //转接字符串用
foad_cnt = 0;
Foad1_sum = 0;
//获取有效的倍率信息
for (int i=0;i<=6;i++)
{
if (GetBools[i]==true)
{
Foad1_sort[foad_cnt] = tex[i];
Foad1_sum += Foad1_sort[foad_cnt];
foad_cnt++;
}
}
//冒泡排序,从小到大排列好倍率:
for (int m = 0; m <= foad_cnt; m++)
for (int n = 0; n < foad_cnt - m - 1; n++)
{
if (Foad1_sort[n] > Foad1_sort[n + 1])
{
temp = Foad1_sort[n];
Foad1_sort[n] = Foad1_sort[n + 1];
Foad1_sort[n + 1] = temp;
}
}
myaddlog(1, "比例押注情况如下(倍率越大、投的比例越小):");
//根据倍率决定投入比例:(倍率越大、投的越小)
//这里遍历的是已经排序好的
for (int L = 0; L <= foad_cnt; L++)
{
for (int k=0;k<=6;k++)
{
if (Foad1_sort[L] == tex[k])
{
PUT[k] = (Foad1_sort[foad_cnt - L] / Foad1_sum)*prophey_coin;
}
}
}
for(int i=0;i<=6;i++)
{
switch (i)
{
case 1:
if (GetBools[1] == true)
{
formattedLogMessage = string.Format("红队胜,倍率压注{0}预言币", PUT[1]);
myaddlog(1, formattedLogMessage);
}
break;
case 2:
if (GetBools[2] == true)
{
formattedLogMessage = string.Format("蓝队胜,倍率压注{0}预言币", PUT[2]);
myaddlog(1, formattedLogMessage);
}
break;
case 3:
if (GetBools[3] == true)
{
formattedLogMessage = string.Format("红蓝2:0,倍率压注{0}预言币", PUT[3]);
myaddlog(1, formattedLogMessage);
}
break;
case 4:
if (GetBools[4] == true)
{
profit_coin = PUT[4] * tex[4];
formattedLogMessage = string.Format("红蓝2:1,倍率压注{0}预言币", PUT[4]);
myaddlog(1, formattedLogMessage);
}
break;
case 5:
if (GetBools[5] == true)
{
formattedLogMessage = string.Format("红蓝1:2,倍率压注{0}预言币", PUT[5]);
myaddlog(1, formattedLogMessage);
}
break;
case 6:
if (GetBools[6] == true)
{
formattedLogMessage = string.Format("红蓝0:2,倍率压注{0}预言币", PUT[6]);
myaddlog(1, formattedLogMessage);
}
break;
}
}
for (int i = 1; i <= 6; i++)
{
switch (i)
{
case 1:
if (GetBools[1] == true)
{
profit_coin = PUT[1] * tex[1];
formattedLogMessage = string.Format("如果压中红队胜,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 2:
if (GetBools[2] == true)
{
profit_coin = PUT[2] * tex[2];
formattedLogMessage = string.Format("如果压中蓝队胜,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 3:
if (GetBools[3] == true)
{
profit_coin = PUT[3] * tex[3];
formattedLogMessage = string.Format("如果压中红蓝2:0,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 4:
if (GetBools[4] == true)
{
profit_coin = PUT[4] * tex[4];
formattedLogMessage = string.Format("如果压中红蓝2:1,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 5:
if (GetBools[5] == true)
{
profit_coin = PUT[5] * tex[5];
formattedLogMessage = string.Format("如果压中红蓝1:2,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
case 6:
if (GetBools[6] == true)
{
profit_coin = PUT[6] * tex[6];
formattedLogMessage = string.Format("如果压中红蓝0:2,将结算{0}预言币", profit_coin);
myaddlog(1, formattedLogMessage);
}
break;
}
}
}
冒泡排序:
这也是我进入编程学习来第一个接触的算法了,十分简单,时间复杂度也不高不低的
也是十分常用的算法了:
float[] Foad1_sort = new float[6];//排序收集到的倍率
int foad_cnt; //Foad1_sort数组的下标
float temp; //冒泡排序用
float Foad1_sum; //倍率之和
string formattedLogMessage; //转接字符串用
foad_cnt = 0;
Foad1_sum = 0;
//获取有效的倍率信息
for (int i=0;i<=6;i++)
{
if (GetBools[i]==true)
{
Foad1_sort[foad_cnt] = tex[i];
Foad1_sum += Foad1_sort[foad_cnt];
foad_cnt++;
}
}
//冒泡排序,从小到大排列好倍率:
for (int m = 0; m <= foad_cnt; m++)
for (int n = 0; n < foad_cnt - m - 1; n++)
{
if (Foad1_sort[n] > Foad1_sort[n + 1])
{
temp = Foad1_sort[n];
Foad1_sort[n] = Foad1_sort[n + 1];
Foad1_sort[n + 1] = temp;
}
}
测试效果图:
各个算法计算结果演示: