C# :: Aufgabe #349
3 Lösungen
Ermittlung der Anzahl fairer Würfel
Fortgeschrittener - C#
von hollst
- 03.02.2021 um 13:01 Uhr
Zwei Würfel A und B nennt man fair, wenn im statistischen Mittel Würfel A gegenüber B genauso oft gewinnt wie umgekehrt. Das ist bei den normalen Spielwürfeln, deren sechs Spielflächen jeweils mit den Zahlen von 1 bis 6 belegt sind, in der Regel der Fall, wenn kein Würfel gezinkt ist (sei hier vorausgesetzt).
Wir nehmen jetzt den Fall an, dass die insgesamt zwölf Spielflächen der zwei Würfel nicht zweimal mit jeweils von 1 bis 6, sondern jeweils mit sechs unterschiedlichen Zahlen aus dem Intervall von 1 bis 12 belegt sind. D. h. hat man sich bei Würfel A für sechs verschiedenen Zahlen aus 1 ... 12 entschieden, so wird B mit den verbleibenden sechs Zahlen belegt. Damit gibt es sehr viele Fälle, bei denen keine zwei faire Würfel entstehen würden, bspw. wenn Würfel A mit 1 ... 6 und Würfel B mit 7 ... 12 belegt wären. In diesem Beispiel gewänne Würfel B immer gegen Würfel A. Würde man allerdings Würfel A mit 1, 2, 3, 10, 11, 12 und Würfel B mit 4 ... 9 belegen, so hätte man wieder ein faires Würfelpaar. Neben der gerade genannten zwei Flächenbelegungen gibt es allerdings weitere, die ebenfalls fair sind.
Die Programmieraufgabe bestehe darin, mittels Simulation alle Flächenbelegungen für zwei Würfel mit den Zahlen von 1 bis 12 zu ermitteln, bei denen die Würfel fair sind.
Wir nehmen jetzt den Fall an, dass die insgesamt zwölf Spielflächen der zwei Würfel nicht zweimal mit jeweils von 1 bis 6, sondern jeweils mit sechs unterschiedlichen Zahlen aus dem Intervall von 1 bis 12 belegt sind. D. h. hat man sich bei Würfel A für sechs verschiedenen Zahlen aus 1 ... 12 entschieden, so wird B mit den verbleibenden sechs Zahlen belegt. Damit gibt es sehr viele Fälle, bei denen keine zwei faire Würfel entstehen würden, bspw. wenn Würfel A mit 1 ... 6 und Würfel B mit 7 ... 12 belegt wären. In diesem Beispiel gewänne Würfel B immer gegen Würfel A. Würde man allerdings Würfel A mit 1, 2, 3, 10, 11, 12 und Würfel B mit 4 ... 9 belegen, so hätte man wieder ein faires Würfelpaar. Neben der gerade genannten zwei Flächenbelegungen gibt es allerdings weitere, die ebenfalls fair sind.
Die Programmieraufgabe bestehe darin, mittels Simulation alle Flächenbelegungen für zwei Würfel mit den Zahlen von 1 bis 12 zu ermitteln, bei denen die Würfel fair sind.
Lösungen:
NET 5.x; C# 8.x
Hier eine ineffiziente Simulation durch Zufallswerte.
Der Wert für die Durchläufe (100000) der Schleife hätte auch kleiner gewählt werden können,
da das Ergebnis ab ca. 2000 Durchläufen konstant bleibt.
Hier eine ineffiziente Simulation durch Zufallswerte.
Der Wert für die Durchläufe (100000) der Schleife hätte auch kleiner gewählt werden können,
da das Ergebnis ab ca. 2000 Durchläufen konstant bleibt.
C#-Code
using System; using System.Collections.Generic; using System.Linq; namespace CS_NET5_Aufgabe_349_Anzahl_Fairer_Wuerfel { class Program { static void Main(string[] args) { var counter = 0; var dicUnique = new Dictionary<string, string>(); var lstStringFirstSix = new List<string>(); for (int i = 0; i < 100_000; i++) { var lstAll = Enumerable.Range(1, 12).OrderBy(x => Guid.NewGuid()).ToList(); var lstFirstSix = lstAll.Take(6).OrderBy(x => x); var lstLastSix = lstAll.TakeLast(6).OrderBy(x => x); if (lstFirstSix.Sum() == lstLastSix.Sum()) // == 39 { var stringFirstSix = string.Join("-", lstFirstSix); var stringLastSix = string.Join("-", lstLastSix); if (!dicUnique.ContainsKey(stringFirstSix) && !dicUnique.ContainsValue(stringFirstSix)) { dicUnique.Add(stringFirstSix, stringLastSix); counter++; lstStringFirstSix.Add(stringFirstSix); } } } var lstFirstSixSorted = lstStringFirstSix.OrderBy(x => x); foreach (var l in lstFirstSixSorted) Console.WriteLine($"W1: [{l}]\tW2: [{dicUnique[l]}]"); Console.WriteLine($"\nAnzahl fairer Würfelpaare: {counter}"); } } }
C#-Code
using System; using System.Collections.Generic; namespace FaireWuerfel { class Program { static void Main(string[] args) { List<Combination> list = new List<Combination>(); for (int a = 1; a < 5; a++) { for (int b = 2; b < 6; b++) { for (int c = 3; c < 7; c++) { if (a == b || a == c || b == c || c < b || b < a) continue; list.Add(new Combination(a, b, c)); } } } foreach (Combination combination in list) { Console.WriteLine($"A = {combination.A}, B = {combination.B}, C = {combination.C}"); } Console.WriteLine($"Anzahl der Kombinationen: {list.Count}"); } } public class Combination { public Combination(int a, int b, int c) { this.A = a; this.B = b; this.C = c; } public int A { get; set; } public int B { get; set; } public int C { get; set; } } }
C#-Code
using System; using static System.Console; using System.Diagnostics; using System.Text; using System.Collections.Generic; K_aus_N_Enumeration lte = new K_aus_N_Enumeration(6, 12); $"{lte.Sequences.Count}".Wl(); int counter = 0; Random rand = new(); Stopwatch sw = new(); sw.Start(); for (var i = 0; i < lte.Sequences.Count; i++) { int[] Complementary = lte.Sequences[i].Complementary(); double stat = Stats(lte.Sequences[i], Complementary, rand, (int)1e+6); $"{lte.Sequences[i].ToMyString()} {lte.Sequences[i].Sum()} {Complementary.ToMyString()} {stat.ToString("F2")} ".Wl(); if (Math.Abs(50.0 - stat) < 1.0) $"{++counter}".Wl(); } sw.Stop(); $"counter: {counter} {sw.Elapsed.Dauer()}".Wl(); "ready, press any key".Rk(); static double Stats(int[] a1, int[] a2, Random r, int max_trails) { int counter1 = 0; for(var i = 0; i < max_trails; i++) { int w1 = r.Next(a1.Length); int w2 = r.Next(a2.Length); if (a1[w1] > a2[w2]) counter1++; } return 100.0 * counter1 / max_trails; } static class Extension { public static void Rk(this string s) { WriteLine(s); ReadKey(); } public static void Wl(this string s) => WriteLine(s); public static string ToMyString(this int[] a) { StringBuilder sb = new(); for (var i = 0; i < a.Length; i++) sb.Append($"{a[i],3}"); return sb.ToString(); } public static int Sum(this int[] a) { int result = 0; foreach (int x in a) result += x; return result; } public static int[] Complementary(this int[] a) { List<int> temp = new(); for(var i = 1; i <= 2 * a.Length; i++) if(!Array.Exists(a, element => element == i)) temp.Add(i); return temp.ToArray(); } public static string Dauer(this TimeSpan ts) => //20210105 String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10); } public class K_aus_N_Enumeration { int k, aus; // k = Number of lottery numbers int[] sequence; public List<int[]> Sequences = new(); public K_aus_N_Enumeration(int K, int Aus) { k = K; aus = Aus; sequence = new int[k]; init(); run(); } void init() { for (var i = 0; i < sequence.Length; i++) sequence[i] = i + 1; } void run() { bool bo_nosteps = false; while (!bo_nosteps) { int[] temp = new int[sequence.Length]; sequence.CopyTo(temp, 0); Sequences.Add(temp); int runner = 0; for (var step = sequence.Length - 1; step >= 0; step--) if (sequence[step] < aus - runner) { sequence[step]++; for (var j = 1; j <= runner; j++) sequence[step + j] = sequence[step] + j; break; } else runner++; if (runner == k) bo_nosteps = true; } } }