Ich erstelle ein Integer-Array und fülle dieses mit zufälligen Zahlen von 1 bis 6.
int[] wuerfel = new int[6];
for (int i = 0; i < 6; i++)
{
wuerfel[i] = zufallszahlen.Next(1, 7);
}
Wie sähe der Code aus, um zu überprüfen, ob eine 1, eine 5 oder 3 Mal die gleiche Zahl enthalten ist?
Contains kann scheinbar nur mit Strings umgehen?
Kann mir da jemand helfen?
Contains ist generisch, das kann mit jedem Typ umgehen, den Du da hast.
Wenn es nur string kann, hast Du also irgendetwas anderes falsch gemacht.
Zum Lernen solltest Du es selber schreiben, ein Dictionary hilft dabei.
Damit kannst Du dann die Zahl als Key und deinen Zähler als Wert behandeln.
Oder in kurz, ohne viel Lerneffekt:
foreach (var group in wuerfel.GroupBy(x => x))
Console.WriteLine($"{group.Key} => {group.Count()}");
Zumindest wenn ich deine Frage richtig verstanden habe
NuGet Packages im Code auslesen
lock Alternative für async/await
Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.
Ich habe jetzt das hier probiert:
bool containsNumber = wuerfel.Contains(1 | 5);
if (containsNumber == false)
Also wenn im Array nicht mindestens eine 1 oder eine 5 enthalten ist, dann soll die if Anweisung greifen.
Machen wir erstmal das, bevor ich mehr Bedingungen habe.
Ich verstehe nicht, was ich in die Klammer hinter Contain schreiben soll.
Was Du da geschrieben hast, ist ein binäres Oder.
Das Contains sucht also nicht 1 oder 5, sondern nur 5.
Richtig ist:
bool containsNumber = wuerfel.Contains(1) || wuerfel.Contains(5);
NuGet Packages im Code auslesen
lock Alternative für async/await
Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.
Ja super. Das funktioniert jetzt. Vielen Dank!
Und wie sähe der Code aus, wenn ich zusätzlich noch prüfen möchte, ob 3 gleiche Zahlen auftreten?
Also entweder eine 1 oder eine 5 oder beispielsweise 3 x die 2, oder 3 x die 3.
Ich versuche mich gerade an dem Spiel "Farkle".
Wenn man würfelt und es ist keine 1, 5 oder 3 gleiche oder 5 aufeinanderfolgende Zahlen (1,2,3,4,5) bzw. (2,3,4,5,6) dabei, dann ist der nächste Spieler dran.
So wie schon geschrieben, mit einem Dictionary oder aber als Lerneffekt für dich, erzeuge eine Methode, welche für jede Zahl (1-6) zählt, wieviele davon in dem Array vorkommen und wenn es mindestens 3 sind, dann gebe true
zurück (Tipp: verschachtelte Schleifen).
Und für die aufeinanderfolgende Zahlen kannst du ähnlich vorgehen und schauen, ob jede Zahl mindestens 1x vorkommt (einmal für 1-5 und einmal für 2-6).
PS:
Bezogen auf dein anderes Thema solltest du UI (WPF) und Logik trennen, d.h. die Spiellogik (+ Spieldaten) in eine eigene Klasse packen.
Mein Ansatz:
internal class Program
{
private static Dictionary<int, int> dice;
private static readonly Random random = new();
static void Main()
{
bool result;
do
{
Init();
Dice();
Print();
result = Analyze();
if (result)
{
Console.WriteLine("Is valid");
}
else
{
Console.WriteLine("Is not valid");
}
} while (result);
Console.ReadKey();
}
private static void Init()
{
dice = [];
for (int i = 1; i < 7; i++)
{
dice.Add(i, 0);
}
}
private static void Dice()
{
for (int i = 1; i < 7; i++)
{
dice[random.Next(1, 7)]++;
}
}
private static bool Analyze()
{
bool isValid = dice[1] > 0 || dice[5] > 0;
if (!isValid)
{
for (int i = 1; i < 7; i++)
{
if (dice[i] > 2)
{
isValid = true;
break;
}
}
}
return isValid;
}
private static void Print()
{
Console.Write($"[ 1:{dice[1]}, 2:{dice[2]}, 3:{dice[3]}, 4:{dice[4]}, 5:{dice[5]}, 6:{dice[6]} ]: ");
}
}
Ah super. Vielen Dank für die Antworten.
Ich wollte nur sicher gehen, dass es keinen vorgefertigtren Ausdruck dafür in C# gibt.
Wie gesagt, dass ist immer mein Problem.
Ich habe auch noch mehr allgemeine Fragen, aber die Stelle ich in gesonderten Themen.
Also: Vielen Dank für eure Hilfe!
Hier ist mal mein einfachess Beispiel:
int[] wuerfel = new int[6];
int[] wuerfelCheck = new int[6];
bool check = false;
Random random = new Random();
for (int i = 0; i < wuerfel.Length; i++)
wuerfel[i] = random.Next(1, 7);
Console.WriteLine("Gewürfelte Zahlen:");
foreach (int i in wuerfel)
{
Console.WriteLine(i);
}
Console.WriteLine();
Console.WriteLine("Zahlen im Checker:");
foreach (int i in wuerfelCheck)
{
Console.WriteLine(i);
}
for (int i = 0; i < wuerfel.Length; i++)
{
for (int j = 1; j < wuerfelCheck.Length+1; j++)
{
if (wuerfel[i] == j)
{
wuerfelCheck[j-1] += 1;
}
}
}
Console.WriteLine();
Array.Sort(wuerfel);
Console.WriteLine("Würfel sortiert:");
foreach (int i in wuerfel)
{
Console.Write($"{i} ");
}
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Zahlen im Checker nach dem Check:");
foreach (int i in wuerfelCheck)
{
Console.WriteLine(i);
}
check = wuerfelCheck.Contains(3);
for (int i = 0; i < wuerfelCheck.Length; i++)
{
if (wuerfelCheck[i] == 3 && check == true)
{
Console.WriteLine();
Console.WriteLine($">>> Die Zahl {i+1} kommt 3 Mal vor! <<<");
}
}
if (check == false)
{
Console.WriteLine();
Console.WriteLine($">>> Es kommt keine Zahl 3 Mal vor! <<<");
}
So funktioniert es.
Man könnte noch ein mehrdimensionales Array benutzen und englische Variablennamen.
Aber zur Veranschaulichung und zum Lernen war es für mich sehr lehrreich.
Deine letzte Schleife überprüft aber nur, ob die Zahl 3 dreimal vorkommt, denn wuerfelCheck.Contains(3)
ermittelt, ob die Zahl 3 im Array enthalten ist und die Abfrage wuerfelCheck[i] == 3 && check == true
kann also dann nur erfüllt werden, wenn i
den Wert 3
hat.
Und somit ist auch die letzte Abfrage nicht das, was du dann ausgibst (sondern eben nur ob die Zahl 3 nicht im Array vorkommt).
PS: Außerdem läßt sich auch das Füllen des Arrays wuerfelCheck
vereinfachen:
for (int i = 0; i < wuerfel.Length; i++)
{
wuerfelCheck[wuerfel[i] - 1] += 1; // bzw. nur ++
}
bzw.
foreach (int w in wuerfel)
{
wuerfelCheck[w - 1] += 1; // bzw. nur ++
}
Zitat von Th69
Deine letzte Schleife überprüft aber nur, ob die Zahl 3 dreimal vorkommt, denn
wuerfelCheck.Contains(3)
ermittelt, ob die Zahl 3 im Array enthalten ist und die AbfragewuerfelCheck[i] == 3 && check == true
kann also dann nur erfüllt werden, wenni
den Wert3
hat.
Ich glaube du verwechselst wuerfelCheck
und wuerfel
. Hat mich aber auch etwas Zeit gekostet das zu verstehen.
In wuerfelCheck
wird die Anzahl wie oft die Zahl (der Index) gewürfelt wurde gespeichert. Mit dem Contains
wird also geprüft, ob irgendein/e Zahl/Index genau 3 mal in wuerfel
vorkommt. Anschließend geht die Schleife wuerfelCheck
durch und sucht den Eintrag, der 3 mal vorgekommen ist.
@danoe hat Recht!
Genau so ist es.
In wuerfelCheck wird die Anzahl der gewürfelt Würfel im Index gespeichert.
Im Index 0 steht wie oft die 1 gewürfelt wurde.
Im Index 1 die 2
usw....
Am Ende überprüfe ich mit Contain, ob irgendeine Zahl 3 Mal vorkommt.
@dannoe: Ja, du hast recht.
Trotzdem ist der Code dann eigenartig, da die check
-Abfrage in
if (wuerfelCheck[i] == 3 && check == true)
dann doppelt (und demnach überflüssig) ist - und deswegen war ich wohl irritiert.
Außerdem wird hiermit ja nur auf "genau drei" und nicht "mindestens drei" geprüft (bezogen auf das Spiel Farkle - bzw. ich kenne es unter dem Namen 10.000, d.h. Zehntausend, welches ich auch selber schon mit C++ umgesetzt habe).
@Th69
Du hast Recht.
Die extra check-Abfrage ist überflüssig. Manchmal neige ich dazu lieber doppelt abzufragen, wenn ich mir nicht sicher bin und in Gedankengängen festhänge.
Wenn man dann noch die Kinder versorgen muss oder wieder irgendwas dazwischen kommt und abgelenkt ist, dann passiert mir das manchmal.
Und ja du hast auch Recht, dass es auch mehr sein können.
Der Code sollte nur als Beispiel für genau 3 sein.
Aber vielen Dank für den Hinweis!
Aktuell habe ich noch Probleme das alles in WPF umzusetzen.
Bisher habe ich ja immer nur Buttons bzw. Klicks abgefragt.
Aber wie kann ich was zur Laufzeit ändern?
Wenn man in einer Runde alle Würfel ausspielt, dann soll man ja 6 neue bekommen.
Aber wenn ich den Button klicke, dann ist das Event schon wieder weg.
Ich glaube dafür benötigt man einen sogenannten dispatcher Timer.
Aber darum soll es hier auch nciht gehen......
Ist nur alle so viel aufeinmal zu lernen.
Vielleicht ist wpf halt auch einfach nicht dafür ausgelegt ein Spiel umzusetzen.....
Aber wie ich ein Array nun abfrage ist mir hier deutlich geworden und darum geht es in diesem Thema ja.
Auch mit WPF (oder WinForms) ist dies umsetzbar (für WinForms habe ich extra ein Framework dafür entwickelt, s. Link in meiner Signatur).
Du solltest nur, wie ich schon geschrieben habe, UI und Logik voneinander trennen. Und eigentlich wäre es für WPF, wie auch schon in deinem anderen Thema geschrieben wurde, besser, dies mittels MVVM umzusetzen (dafür solltest du aber zuerst ein paar Tutorials und Beispielprojekte durcharbeiten).
Ich habe das Spiel so umgesetzt, daß es 2 Buttons "Würfeln" und "Werten" gibt, s. Anhang (einfach alles in einen Ordner entzippen und "Dice.exe" starten).
Aaaaah okay.....
Wenn ich dein Spiel richtig verwendet habe, dann werden die Punkte automatisch gewertet.
Bei meinem Ansatz muss man die Zahlen erst anklicken.
Und kann sie auch wieder abwählen während des Zuges.
Durch das Anklicken ändert sich dann das Würfelimage
Das macht das ganz aufwändiger.
Ich muss dann beispielsweise abfragen, ob der Benutzer die 3 gleichen Zahlen angeklickt hat. Wenn er nur 2 anklickt, dann wird der Punkten und Würfeln Button deaktiviert.
Ich habe das Spiel nach den Regeln von Kingdom Come Deliverance übernommen.
Das kann man auch einfach nur eine 1 oder sogar nur eine 5 nehmen und dann entweder punkten und passen, du hast das "Werten" genannt, oder aber eben punkten und würfeln.
Aber interressant zu sehen, wie dein Spiel aussieht und gespielt wird.
Danke für den Einblick.
Du kannst auch bei meinem Spiel einzelne Würfel mit einem Doppelklick abwählen (nur dann nicht wieder aktivieren).
Du mußt nur dafür sorgen, daß bei jedem Aktivieren/Deaktivieren immer wieder die Berechnungsfunktion aufgerufen wird. In meinem Code habe ich für jeden Würfel ein extra Status Scored
, welcher gesetzt wird (damit nur diese gewertet und zur Seite gelegt werden).
Wenn man in einer Runde alle Würfel ausspielt, dann soll man ja 6 neue bekommen.
Aber wenn ich den Button klicke, dann ist das Event schon wieder weg.
Ich glaube dafür benötigt man einen sogenannten dispatcher Timer.
Dafür zähle ich die Anzahl der gewerteten Würfel und initialisiere dann wieder alle Würfel neu (neuer Zufallswurf mit 6 Würfeln).
if (m_nScoredDice >= MaxDice)
InitDice(false);
Einen Timer benötigt man nur, wenn UI-Aktionen ohne aktive Benutzeraktion wiederholt ausgeführt werden sollen (wie z.B. zeige jede Sekunde die aktuelle Zeit an oder speichere jede Minute den aktuellen Spielstand o.ä.).