C# :: Aufgabe #316

2 Lösungen Lösungen öffentlich

Abschätzung der Gewinnchancen eines KENO-Types

Anfänger - C# von hollst - 08.05.2020 um 22:39 Uhr
Zur Erinnerung, was ist KENO: Aus 70 Zahlen werden 20 Gewinnzahlen per Zufallsgenerator ermittelt.
Es gibt die KENO-Typen 2, 3 ... 10, d. h. man kann 2, 3 ... 10 Zahlen aus den Zahlen 1 ... 70 wählen.

Bei KENO-Typ N können 0, 1 ... N gewählte Zahlen in den 20 gelosten Gewinnzahlen enthalten sein
(je mehr, desto höher natürlich der Gewinn).

Die Programmieraufgabe bestehe darin, mittels stochastischer Simulation die Wahrscheinlichkeit dafür abzuschätzen,
wie hoch die Chance ist, bei KENO-Typ N, 0, 1, 2 ... oder gar N Richtige auf seinem Tippzettel zu haben?

Die exakten Werte könnt ihr u. a. z. B. auf
https://www.sachsenlotto.de/portal/spiele/keno/gewinnquoten.jsp
nachsehen.

Lösungen:

vote_ok
von JKooP (3200 Punkte) - 23.05.2020 um 10:08 Uhr
NET Core 3.x

Quellcode ausblenden C#-Code
using System;
using System.Linq;

namespace CS_Aufgabe_316_Keno
{

    public enum KenoTypen
    {
        Typ2 = 2, Typ3, Typ4, Typ5, Typ6, Typ7, Typ8, Typ9, Typ10,
    }

    class Program
    {
        static void Main(string[] args)
        {
            const int AnzahlZiehungen = 1_000_000;
            const KenoTypen KenoTyp = KenoTypen.Typ8;

            var arrRichtige = Keno(KenoTyp, AnzahlZiehungen);

            Console.WriteLine($"KENO {KenoTyp}:\n");

            for (int i = 0; i < arrRichtige.Length; i++)
            {
                Console.WriteLine($"{i,2}: {100 * arrRichtige[i] / (double)AnzahlZiehungen,8:F5} %");
            }
        }

        static int[] Keno(KenoTypen kenoTyp, int anzahlZiehungen)
        {
            var anzahlGetippteZahlen = (int)kenoTyp;

            var arrRichtige = new int[anzahlGetippteZahlen + 1];

            var listeGewinnzahlen = Enumerable.Range(1, 70).OrderBy(x => Guid.NewGuid()).Take(20);

            var listeGetippteZahlen = Enumerable.Range(1, 70).OrderBy(x => Guid.NewGuid()).Take(anzahlGetippteZahlen).ToList();

            for (var i = 0; i < anzahlZiehungen; i++)
            {
                arrRichtige[listeGewinnzahlen.Intersect(listeGetippteZahlen).Count()]++;
            }
            return arrRichtige;
        }
    }
}
vote_ok
von hollst (12490 Punkte) - 03.06.2020 um 12:17 Uhr
Quellcode ausblenden C#-Code
#define nosimulation

using System;
using System.Linq;
using System.Text;
using static System.Console;
using System.Diagnostics;
using System.Numerics;

namespace KenoConsole
{
    /* 
    Zur Erinnerung, was ist KENO: Aus 70 Zahlen werden 20 Gewinnzahlen per Zufallsgenerator ermittelt.
    Es gibt die KENO-Typen 2, 3 ... 10, d. h. man kann 2, 3 ... 10 Zahlen aus den Zahlen 1 ... 70 wählen.

    Bei KENO-Typ N können 0, 1 ... N gewählte Zahlen in den 20 gelosten Gewinnzahlen enthalten sein
    (je mehr, desto höher natürlich der Gewinn. Interessant ist bei KENO allerdings, dass es ab KENO-Typ 5 
    unwahrscheinlicher ist überhaupt keinen Treffer zu haben als z. B. einen oder zwei.).

    Die Programmieraufgabe bestehe darin, 
    mittels stochastischer Simulation die Wahrscheinlichkeit dafür abzuschätzen,
    wie hoch die Chance ist, bei KENO-Typ N, 0, 1, 2 ... oder gar N Richtige auf 
    seinem Tippzettel zu haben.

    Die exakten Werte könnt ihr u. a. z. B. auf
    https://www.sachsenlotto.de/portal/spiele/keno/gewinnquoten.jsp
    http://mathproblems.info/gam470/games/keno/prob-keno.html etwas anderes KENO, prizniopiell okay
    nachsehen.
    */

    static class Program
    {
        static void Main()
        {
            Int64[][] erwartung // 1 : x laut https oben (0 == ohne Gewinnausschüttung)
                = new Int64[][] {
                    //		  0	   1	2	 3	   4	 5	   6	  7	     8	       9	     10
                new Int64[]   { 0,   4 },
                new Int64[]   { 0,   0,  13 },
                new Int64[]   { 0,   0,   6,  48  },
                new Int64[]   { 0,   0,   4,  16,  189 },
                new Int64[]   { 0,   0,   0,   9,   50,  781 },
                new Int64[]   { 0,   0,   0,   6,   22,  169, 3383 },
                new Int64[]   { 0,   0,   0,   0,   13,   63,  619, 15464 },
                new Int64[]   {18,   0,   0,   0,    8,   31,  199,  2436, 74941 },
                new Int64[]   {26,   0,   0,   0,    0,   18,   86,   685, 10325,   387197 },
                new Int64[]   {39,   0,   0,   0,    0,   12,   44,   261,  2571,    47238,   2147181 }
            };

            Int64[][] gewinn // laut https oben (0 == ohne Gewinnausschüttung)
                = new Int64[][] {
                    //		    0	 1	  2	   3	 4	    5     6     7	   8	     9	      10
                new Int64[]   { 0,   3 },
                new Int64[]   { 0,   0,   6},
                new Int64[]   { 0,   0,   1,  16  },
                new Int64[]   { 0,   0,   1,   2,   22 },
                new Int64[]   { 0,   0,   0,   2,    7,   100 },
                new Int64[]   { 0,   0,   0,   1,    2,    15,  500 },
                new Int64[]   { 0,   0,   0,   0,    1,    12,  100, 1000 },
                new Int64[]   { 1,   0,   0,   0,    1,     2,   15,  100, 10000 },
                new Int64[]   { 2,   0,   0,   0,    0,     2,    5,   20,  1000,    50000},
                new Int64[]   { 2,   0,   0,   0,    0,     2,    5,   15,   100,     1000,    100000 }
            };

#if !nosimulation //für Simulation CODE-ZEILE 1 zum Kommentar machen!

            Int64[][] KenoResults = new Int64[erwartung.Length][];
            for (var i = 0; i < KenoResults.Length; i++)
                KenoResults[i] = new Int64[2 + i];

            Random r = new Random();
            Int64 anzahl = 0, max_anzahl = (Int64)1E+6; //besser (Int64)1E+9, aber Rechenzeit sicher > 1 Tag

            Stopwatch uhr = new Stopwatch();

            "start simulation".MessageKey();
            "simulation runs - have some patience".MessageLine();

            uhr.Start();
            while (anzahl < max_anzahl)
            {
                KenoClass KC = new KenoClass(r);
                for (var j = 0; j < KC.MyKenoResult.Length; j++)
                    KenoResults[j][KC.MyKenoResult[j]] += 1;

                if (anzahl > 0 && anzahl % (Int64)1E+5 == 0)
                {
                    uhr.Stop();
                    uhr.Elapsed.DurationString().MessageLine();
                    $"{anzahl.ToString("n0")} of {max_anzahl.ToString("n0")}".MessageLine();
                    KenoResults.Adjust(erwartung, anzahl, true).ArrayString().MessageLine();
                    KenoResults.Adjust(erwartung, anzahl, false).ArrayString().MessageLine();
                    uhr.Restart();
                }

                anzahl++;
            }
            KenoResults.Adjust(erwartung, anzahl, true).ArrayString().MessageLine();
#endif
            "show exact solution".MessageKey();

            int n = 10, m = 20, g = 70;
            //int n = 6, m = 6, g = 49;
            //int n = 15, m = 20, g = 80;
            NausMausG nmg = new NausMausG(n, m, g);

            nmg.Expectation.ArrayString().MessageLine();

            for (BigInteger N = n; N > 1; N--)
            {
                WriteLine();
                WriteLine($"N: {N,12}");
                WriteLine();
                BigInteger CombinationsSum = 0, ReturnSum = 0;
                for (BigInteger M = N; M >= 0; M--)
                {
                    BigInteger Combinations = nmg.NoverK(m, M) * nmg.NoverK(g - m, N - M);
                    BigInteger Return = 0;

                    if ((N <= gewinn.Length) && (M < gewinn[(int)N - 1].Length))
                        Return = gewinn[(int)N - 1][(int)M];

                    ReturnSum += Return * Combinations;

                    CombinationsSum += Combinations;
                    string s1 = $"{nmg.Expectation[(int)(N - 1)][(int)M].ToString("n0"),15}     ";
                    string s2 = $"{Combinations.ToString("n0"),15} {Return.ToString("n0"),15}  ";
                    WriteLine(s1 + s2);
                }
                string s3 = $"CombinationsSum: {CombinationsSum.ToString("n0"),18}  ";
                string s4 = $"ReturnSum: {ReturnSum.ToString("n0"),15}  ";
                string s5 = $"{nmg.CommercialRounds(100 * ReturnSum, CombinationsSum)} %";
                WriteLine(s3 + s4 + s5);
            }
            WriteLine("ready");
            ReadKey();
        }

        static void MessageLine(this string s) => WriteLine(s);
        static void Message(this string s) => Write(s);

        static void MessageKey(this string s)
        {
            ("by pressing a button " + s).MessageLine();
            ReadKey();
        }

        static string ArrayString(this Int64[][] a)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("stats");
            for (var i = 0; i < a.Length; i++)
            {
                sb.Append($"{i + 1,2}: ");
                for (var j = 0; j < a[i].Length; j++)
                    sb.Append($"{a[i][j],8} ");
                sb.AppendLine();
            }
            sb.AppendLine();
            return sb.ToString();
        }

        static string ArrayString(this BigInteger[][] a)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine();
            for (var i = 0; i < a.Length; i++)
            {
                sb.Append($"{i + 1,2}: ");
                for (var j = 0; j < a[i].Length; j++)
                    sb.Append($"{a[i][j].ToString("n0"),8} ");
                sb.AppendLine();
            }
            sb.AppendLine();
            return sb.ToString();
        }

        static Int64[][] Adjust(this Int64[][] a, Int64[][] ad, Int64 anzahl, bool bo_relativ)
        {

            if (anzahl == 0)
                anzahl = 1;
            Int64[][] result = new Int64[a.Length][];
            for (var i = 0; i < result.Length; i++)
            {
                result[i] = new Int64[a[i].Length];

                for (var j = 0; j < a[i].Length; j++)
                {
                    if (bo_relativ)
                    {
                        if (ad[i][j] != 0)
                            result[i][j] = 100 * ((Int64)Math.Round(1.0 * anzahl / a[i][j])) / ad[i][j];
                    }
                    else
                        if (a[i][j] > 0)
                            result[i][j] = (Int64)Math.Round(1.0 * anzahl / a[i][j]);
                }
            }
            return result;
        }

        public static string DurationString(this TimeSpan ts)
        {
            string h = ts.Hours.ToString(); if (h.Length == 1) h = "0" + h;
            string m = ts.Minutes.ToString(); if (m.Length == 1) m = "0" + m;
            string s = ts.Seconds.ToString(); if (s.Length == 1) s = "0" + s;
            string ms = ts.Milliseconds.ToString();
            while (ms.Length < 3)
                ms = "0" + ms;
            return $"Time elapsed: {h}:{m}:{s}.{ms}";
        }
    }

    public class KenoClass
    {
        Int64[] WinningValues;
        Int64[][] MyKenoValues;
        public Int64[] MyKenoResult { private set; get; }
        Random r;

        public KenoClass(Random r)
        {
            this.r = r;

            this.WinningValues = new Int64[20];
            for (var i = 0; i < WinningValues.Length; i++)
            {
                Int64 n = 0;
                while (n < this.WinningValues.Length)
                {
                    Int64 value = r.Next(1, 71);
                    if (!this.WinningValues.ToArray().Contains(value))
                    {
                        this.WinningValues[n] = value;
                        n++;
                    }
                }
            }
            Array.Sort(this.WinningValues);

            this.MyKenoValues = new Int64[10][];
            this.MyKenoResult = new Int64[this.MyKenoValues.Length];
            for (var i = 0; i < this.MyKenoValues.Length; i++)
            {
                this.MyKenoValues[i] = new Int64[1 + i];
                Int64 n = 0;
                while (n < this.MyKenoValues[i].Length)
                {
                    Int64 value = r.Next(1, 71);
                    if (!this.MyKenoValues[i].ToArray().Contains(value))
                    {
                        this.MyKenoValues[i][n] = value;
                        if (this.WinningValues.ToArray().Contains(value))
                            MyKenoResult[i]++;
                        n++;
                    }
                }
                Array.Sort(this.MyKenoValues[i]);
            }
        }

        public string KenoString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("WinningValues");
            for (var i = 0; i < WinningValues.Length; i++)
                sb.Append($"{WinningValues[i],2} ");
            sb.AppendLine();
            sb.AppendLine("MyKenoVelues");
            for (var i = 0; i < MyKenoValues.Length; i++)
            {
                sb.Append($"{i + 1,2}: ");
                for (var j = 0; j < MyKenoValues[i].Length; j++)
                    sb.Append($"{MyKenoValues[i][j],2} ");
                sb.Append($"  winnings: {this.MyKenoResult[i]}");
                sb.AppendLine();
            }
            sb.AppendLine();
            return sb.ToString();
        }
    }

    //Die exakte Lösung (public class NausMausG ) ist ein Extra
    public class NausMausG //Keno wird mitunter auch bezeichnet als 10aus20aus70 (in EU) oder 15aus20aus80 in US
    {
        int N, M, G;
        public BigInteger[][] Expectation; // 1 zu x

        public NausMausG(int n, int m, int g)
        {
            this.N = n; this.M = m; this.G = g;
            this.Expectation = new BigInteger[n][];
            for (var i = 0; i < this.Expectation.Length; i++)
                this.Expectation[i] = new BigInteger[i + 2];
            run();
        }

        void run()
        {
            for (var i = 0; i < this.Expectation.Length; i++)
                for (var j = 0; j < this.Expectation[i].Length; j++)
                    this.Expectation[i][j] = KenoChance(i + 1, j, G, M);
        }

        BigInteger Fak(BigInteger f)
        {
            BigInteger result = 1;
            for (BigInteger i = 2; i <= f; i++)
                result *= i;
            return result;
        }

        public BigInteger NoverK(BigInteger N, BigInteger K) => (Fak(N) / (Fak(K) * Fak(N - K)));

        BigInteger KenoChance(BigInteger N, BigInteger K, BigInteger All, BigInteger Winner)
        {
            BigInteger Nenner = NoverK(All, Winner);
            BigInteger Zaehler = NoverK(N, K) * NoverK(All - N, Winner - K);
            return CommercialRounds(Nenner, Zaehler);
        }

        //kaufmännische Runden basiert auf DIN-Norm 1333
        public BigInteger CommercialRounds(BigInteger Z, BigInteger N)
        {
            BigInteger result = Z / N;
            if ((10 * (Z % N)) / N >= 5)
                result += 1;
            return result;
        }
    }
}
887198

Du scheinst einen AdBlocker zu nutzen. Ich würde mich freuen, wenn du ihn auf dieser Seite deaktivierst und dich davon überzeugst, dass die Werbung hier nicht störend ist.