C# は乱数シミュレーターを使用してワールドカップのランキングをシミュレートします (3)

前回の記事からの続きです

C# で乱数シミュレーターを使ってワールドカップランキングをシミュレートする (2) - Sneko's Blog - CSDN Blog

前回の記事では、ゲーム内でワールドカップの国を一致させるために乱数を使用しましたが、

この記事では、乱数と勝率シミュレーターを使用して、ワールドカップの優勝者と準優勝者を決定します。

メインインターフェイスに[チャンピオンが決まるまでゲームを開始する]と[更新して再ランダムに割り当てる]ボタンを追加しました。

パネルパネル: pnlWorldCup

ボタン:[チャンピオンが決まるまでゲームを開始する] btnStart

ボタン: [更新してランダムに再割り当て] btnRefresh

リッチ テキスト コントロール RichTextBox: rtxtDisplay

FormWorldCupRanking のフォームは次の図のように設計されています。

 CountryUtil.cs を更新し、World Cup に参加する 2 か国の勝者側を取得するために使用されるSoccerGameメソッドを追加します。

CountryUtil のソース プログラムは次のとおりです。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WorldCupRankingDemo
{
    internal class CountryUtil
    {
        /// <summary>
        /// 所有参赛的世界杯国家
        /// </summary>
        public static List<Country> ListWorldCup = new List<Country>();
        /// <summary>
        /// 初始化世界杯各个参赛国家
        /// </summary>
        public static void InitCountry() 
        {
            ListWorldCup.Clear();
            AddCountry(new Country()
            {
                CountryName = "法国",
                WinningRatio = 90,
                NationalFlag = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "NationalFlagImage\\法国.png")
            });
            AddCountry(new Country()
            {
                CountryName = "阿根廷",
                WinningRatio = 95,
                NationalFlag = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "NationalFlagImage\\阿根廷.png")
            });
            AddCountry(new Country()
            {
                CountryName = "巴西",
                WinningRatio = 98,
                NationalFlag = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "NationalFlagImage\\巴西.png")
            });
            AddCountry(new Country()
            {
                CountryName = "荷兰",
                WinningRatio = 80,
                NationalFlag = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "NationalFlagImage\\荷兰.png")
            });
            AddCountry(new Country()
            {
                CountryName = "克罗地亚",
                WinningRatio = 70,
                NationalFlag = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "NationalFlagImage\\克罗地亚.png")
            });
            AddCountry(new Country()
            {
                CountryName = "葡萄牙",
                WinningRatio = 75,
                NationalFlag = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "NationalFlagImage\\葡萄牙.png")
            });
            AddCountry(new Country()
            {
                CountryName = "摩洛哥",
                WinningRatio = 65,
                NationalFlag = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "NationalFlagImage\\摩洛哥.png")
            });
            AddCountry(new Country()
            {
                CountryName = "英格兰",
                WinningRatio = 85,
                NationalFlag = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "NationalFlagImage\\英格兰.png")
            });
        }

        /// <summary>
        /// 添加一个国家
        /// </summary>
        /// <param name="country"></param>
        public static void AddCountry(Country country) 
        {
            ListWorldCup.Add(country);
        }

        /// <summary>
        /// 两个匹配的世界杯国家进行比赛,根据胜率,进行随机,返回胜利的国家
        /// 胜利国家算法如下:先随机出一个胜率之和之间的随机数,
        /// 如果随机数小于【最小数的2倍】并且是奇数,则认为 胜率低的国家胜利,否则 胜率高的国家胜利
        /// </summary>
        /// <param name="tuple"></param>
        /// <returns></returns>
        public static Country SoccerGame(Tuple<Country, Country> tuple, out int randomNumber) 
        {
            randomNumber = -1;
            if (tuple == null || tuple.Item1 == null) 
            {
                throw new Exception("世界杯比赛无参赛的国家或者第一个参赛国家不存在");
            }
            if (tuple.Item2 == null) 
            {
                //无第二个世界杯参赛国家,直接躺赢【对奇数个参赛国家的特殊处理】
                return tuple.Item1;
            }
            decimal minWinningRatio = Math.Min(tuple.Item1.WinningRatio, tuple.Item2.WinningRatio);
            Country bigWin = null;//高胜率
            Country smallWin = null;//低胜率
            if (tuple.Item1.WinningRatio < tuple.Item2.WinningRatio)
            {
                bigWin = tuple.Item2;
                smallWin = tuple.Item1;
            }
            else
            {
                bigWin = tuple.Item1;
                smallWin = tuple.Item2;
            }

            int total = (int)(tuple.Item1.WinningRatio + tuple.Item2.WinningRatio);
            Random random = new Random(Guid.NewGuid().GetHashCode());
            //先随机出一个胜率之和之间的随机数
            randomNumber = random.Next(total);
            if (randomNumber < minWinningRatio * 2 && (randomNumber & 1) != 0) 
            {
                //如果随机数小于【最小数的2倍】并且是奇数,则认为 胜率低的国家胜利,否则 胜率高的国家胜利
                return smallWin;
            }
            return bigWin;
        }
    }
}

FormWorldCupRankingのフォーム、ソースプログラムは以下のとおりです。

(デザイナーによって自動生成されたコードは無視してください)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WorldCupRankingDemo
{
    public partial class FormWorldCupRanking : Form
    {
        /// <summary>
        /// 比赛次数
        /// </summary>
        private static int matchCount = 0;
        /// <summary>
        /// 获胜世界杯国家列表,将进入下一轮
        /// </summary>
        private static List<Country> WinCountryList = new List<Country>();
        public FormWorldCupRanking()
        {
            InitializeComponent();
            rtxtDisplay.ReadOnly = true;
        }

        private void FormWorldCupRanking_Load(object sender, EventArgs e)
        {
            CountryUtil.InitCountry();
            LoadMatchCountry(CountryUtil.ListWorldCup);
        }

        /// <summary>
        /// 随机分配参赛国家列表
        /// </summary>
        /// <param name="countryList"></param>
        private void LoadMatchCountry(List<Country> countryList)
        {
            pnlWorldCup.Controls.Clear();
            DisplayMessage($"开始加载世界杯参赛国家.参赛国家[{countryList.Count}]个.参赛国:\n{string.Join(",", countryList.Select(c => c.CountryName))}");
            Application.DoEvents();
            //Thread.Sleep(500);
            int[] indexArray = new int[countryList.Count];
            for (int i = 0; i < indexArray.Length; i++)
            {
                indexArray[i] = i;
            }
            RandomUtil.Init(indexArray);
            int[] destArray = RandomUtil.Shuffle();
            int rowCount = (destArray.Length + 1) / 2;
            matchCount = rowCount;
            string[] matchNations = new string[rowCount];//比赛对战国家
            for (int i = 0; i < rowCount; i++)
            {
                UcCountry ucCountry1 = new UcCountry();
                ucCountry1.Name = $"ucCountry{i * 2 + 1}";
                Country country1 = countryList[destArray[i * 2]];
                ucCountry1.lblCountryName.Text = country1.CountryName;
                ucCountry1.lblWinningRatio.Text = $"胜率:{country1.WinningRatio}";
                ucCountry1.picNationalFlag.BackgroundImage = country1.NationalFlag;
                ucCountry1.Tag = country1;
                ucCountry1.Location = new Point(5, i * 200 + 5);
                pnlWorldCup.Controls.Add(ucCountry1);

                Button button = new Button();
                button.Name = $"button{i + 1}";
                button.Text = "VS";
                button.Font = new Font("宋体", 30, FontStyle.Bold);
                button.Size = new Size(100, 100);
                button.Location = new Point(310, i * 200 + 40);
                button.Enabled = false;//不允许界面交互
                pnlWorldCup.Controls.Add(button);

                Country item2 = null;
                if (i * 2 + 1 < destArray.Length)
                {
                    //对奇数个世界杯比赛国家特殊处理,最后一个国家直接胜利
                    UcCountry ucCountry2 = new UcCountry();
                    ucCountry2.Name = $"ucCountry{i * 2 + 2}";
                    Country country2 = countryList[destArray[i * 2 + 1]];
                    ucCountry2.lblCountryName.Text = country2.CountryName;
                    ucCountry2.lblWinningRatio.Text = $"胜率:{country2.WinningRatio}";
                    ucCountry2.picNationalFlag.BackgroundImage = country2.NationalFlag;
                    ucCountry2.Tag = country2;
                    ucCountry2.Location = new Point(455, i * 200 + 5);
                    pnlWorldCup.Controls.Add(ucCountry2);

                    item2 = country2;
                }
                //对按钮进行数据绑定 对应两个世界杯参赛国家
                button.Tag = Tuple.Create(country1, item2);
                button.Click += Button_Click;

                matchNations[i] = $"【{country1.CountryName} VS {(item2 == null ? "无" : item2.CountryName)}】";
            }
            DisplayMessage($"加载世界杯对战国家匹配完成.对战情况\n{string.Join(",\n", matchNations)}");
        }

        /// <summary>
        /// 淘汰赛,利用胜率获取随机数算法,获取世界杯比赛的胜利一方,并将获胜国家插入胜利列表,以便进行下一次的随机分配
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, EventArgs e)
        {
            Button button = sender as Button;
            if (button == null) 
            {
                return;
            }
            Tuple<Country, Country> tuple = button.Tag as Tuple<Country, Country>;
            if (tuple == null) 
            {
                return;
            }
            int randomNumber;
            Country winCountry = CountryUtil.SoccerGame(tuple, out randomNumber);
            WinCountryList.Add(winCountry);//将获胜国家插入列表
            DisplayMessage($"世界杯参赛国家【{tuple.Item1.CountryName},胜率:{tuple.Item1.WinningRatio}】 VS 【{(tuple.Item2 == null ? "无" : $"{tuple.Item2.CountryName},胜率:{tuple.Item2.WinningRatio}")}】");
            DisplayMessage($"    胜利国家【{winCountry.CountryName}】,模拟随机数【{randomNumber}】");
            UcCountry ucCountry = FindWinCountry(button, winCountry);
            if (ucCountry == null) 
            {
                return;
            }

            Panel panel = new Panel();
            panel.Name = $"panel{button.Name.Substring(6)}";
            panel.Location = new Point(ucCountry.Location.X + 250, ucCountry.Location.Y + 10);
            panel.Size = new Size(100, 100);
            panel.BackgroundImage = null;
            Bitmap bitmap = new Bitmap(panel.Width, panel.Height);
            Graphics graphics = Graphics.FromImage(bitmap);
            graphics.DrawString("胜 利", new Font("华文楷体", 16), Brushes.Red, 10, 10);
            graphics.Dispose();
            panel.BackgroundImage = bitmap;
            pnlWorldCup.Controls.Add(panel);
        }

        /// <summary>
        /// 获取两个世界杯比赛国家胜利一方对应的控件
        /// </summary>
        /// <param name="button"></param>
        /// <param name="winCountry"></param>
        /// <returns></returns>
        private UcCountry FindWinCountry(Button button, Country winCountry) 
        {
            int index = int.Parse(button.Name.Substring(6)) - 1;
            Control[] controls = pnlWorldCup.Controls.Find($"ucCountry{index * 2 + 1}", true);
            Control[] controls2 = pnlWorldCup.Controls.Find($"ucCountry{index * 2 + 2}", true);
            if (controls != null && controls.Length > 0)
            {
                Country cTemp = ((UcCountry)controls[0]).Tag as Country;
                if (cTemp.CountryName == winCountry.CountryName)
                {
                    return (UcCountry)controls[0];
                }
                else
                {
                    if (controls2 != null && controls2.Length > 0)
                    {
                        cTemp = ((UcCountry)controls2[0]).Tag as Country;
                        if (cTemp.CountryName == winCountry.CountryName)
                        {
                            return (UcCountry)controls2[0];
                        }
                    }
                }
            }
            return null;
        }

        private void DisplayMessage(string message) 
        {
            this.BeginInvoke(new Action(() => 
            {
                if (rtxtDisplay.TextLength >= 40960) 
                {
                    rtxtDisplay.Clear();
                }
                rtxtDisplay.AppendText($"{DateTime.Now.ToString("HH:mm:ss")}-->{message}\n");
                rtxtDisplay.ScrollToCaret();
            }));
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            Country[] FinalTwoCountry = new Country[2];//最终决赛的两个国家,分出冠军、亚军
            do
            {
                WinCountryList.Clear();
                for (int i = 0; i < matchCount; i++)
                {
                    Button button = pnlWorldCup.Controls.Find($"button{i + 1}", true)[0] as Button;
                    Button_Click(button, null);
                    Application.DoEvents();
                    Thread.Sleep(2000);
                }
                if (WinCountryList.Count == 1) 
                {
                    //只有最后一个胜利国家,循环终止,找到亚军
                    Country secondPlace = Array.Find(FinalTwoCountry, c => c.CountryName != WinCountryList[0].CountryName);
                    DisplayMessage($"最终胜利国家,冠军【{WinCountryList[0].CountryName}】,亚军【{secondPlace.CountryName}】");
                    MessageBox.Show($"最终胜利国家,冠军【{WinCountryList[0].CountryName}】,亚军【{secondPlace.CountryName}】", "圆满结束");
                    break;
                }
                DisplayMessage($"当前胜利的世界杯国家为【{string.Join(",", WinCountryList.Select(country => country.CountryName))}】");
                Application.DoEvents();
                Thread.Sleep(3000);
                if (WinCountryList.Count == 2) 
                {
                    WinCountryList.CopyTo(FinalTwoCountry);
                    string worldCupBattle = $"世界杯决战即将开始,最终决赛双方:【{WinCountryList[0].CountryName} VS {WinCountryList[1].CountryName}】";
                    DisplayMessage(worldCupBattle);
                    Application.DoEvents();
                    Thread.Sleep(1000);
                    MessageBox.Show(worldCupBattle, "世界杯决战");
                }
                LoadMatchCountry(WinCountryList);
            } while (WinCountryList.Count >= 2);
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            WinCountryList.Clear();
            FormWorldCupRanking_Load(null, null);
        }
    }
}

フォームは次の図のように実行されます。

 最後の4:

 ワールドカップ決勝:

 

おすすめ

転載: blog.csdn.net/ylq1045/article/details/128324667