none
Würfelsummen RRS feed

  • Frage

  • Hallo,

    ich hatte vor ein kleines Programm über Würfeösummen zu schreiben:

    Zwei Würfel werden geworfen, nun sollen alle Kombinationen errechnet werden, indenen die Summe der Aufenzahlen eine angegebene Nummer ist.

    Da es relativ einfach ist, habe ich es eigentlich schon fertig, es funktioniert aber noch nicht.

    Hier der Code

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Würfel
    {
        class Program
        {
            static void Main(string[] args)
            {
              
                
    
                int targetnumber, cube1, cube2;
                cube1 = 1;
                cube2 = 1;
                List<Combination> results = new List<Combination>();
                var validateinput = int.TryParse(Console.ReadLine(),out targetnumber);
              
                if (validateinput == false)
                {
                    Console.WriteLine("Fehler!");
                    Console.ReadKey();
                    
    
                }
                else
                {
                
    
    
                    for (;cube1 > 6;)
                    {
                        int temp = cube1 + cube2;
                        if (targetnumber == temp)
                        {
                            results.Add(new Combination(cube1, cube2));
                                                                                        
                        }
                        if (cube2 == 6)
                        {
                            cube1 = cube1 + 1;
                            cube2 = 1;
    
                        }
                        else
                        cube2++;
                    }
                 
                    foreach (Combination output in results)
                    {
                     Console.WriteLine(output.ToString());
                        Console.WriteLine();
                    }
                    Console.ReadKey();
                }
            }
              
        }
    }
    

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Würfel
    {
        class Combination
        {
            private int cube1;
    
            public int Cube1
            {
                get { return cube1; }
                set { cube1 = value; }
            }
            private int cube2;
    
            public int Cube2
            {
                get { return cube2; }
                set { cube2 = value; }
            }
    public Combination(int cube1, int cube2)
            {
                this.Cube1 = cube1;
            this.Cube2 = cube2;
                    }
            public override string ToString()
            {
                return "Combination:"+Cube1+","+Cube2;
            }
    
        }
    }
    
    LG
    Samstag, 3. Oktober 2015 19:18

Antworten

  • Hallo,

    ich verstehe ehrlich gesagt dien Vorhaben mit der Schleife nicht so ganz. Eine Möglichkeit wäre alle durchzuraten, bzw. wie in nachfolgender Version einen Rateversuch abzubrechen sobald man eine passende Kombination gefunden hat:

    for (int cube1 = 1; cube1 <= 6; ++cube1)
    {
        for (int cube2 = 1; cube2 <= 6 && cube1 + cube2 <= targetnumber; ++cube2)
        {
            if (cube1 + cube2 == targetnumber)
            {
                results.Add(new Combination(cube1, cube2));
            }
        }
    }

    Viel schöner ist es alle Kombinationen eines Würfels durchzugehen und zu gucken was der 2. Würfel für einen Wert hätte haben müssen:

    for (int cube1 = 1; cube1 <= 6; ++cube1)
    {
        if (targetnumber - cube1 <= 0) break;//Abbrechen da Zahl des 1. Würfels zu groß
        results.Add(new Combination(cube1, targetnumber - cube1));
    }

    Jetzt eine kleine Erweiterung für dich: Filtere die noch doppelten (also beispielsweise 1-6 und 6-1) heraus. Weiterhin empfehle ich dir noch zu gucken ob der Eingabewert nicht zu groß oder zu klein ist.

    Gern kannst du auch nochmals schreiben was du für eine Lösungsstrategie hattest.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert R3turnz Sonntag, 4. Oktober 2015 07:45
    Samstag, 3. Oktober 2015 19:47
    Moderator
  • Hallo,

    zunächst ein Grundsatz: Beim durchlaufen von Listen oder Arrays in einer for-Schleife nutzt man i<Length/Count und nicht <=. Bei <= würde man versuchen ein Element zu viel anzusteuern.

    Weiterhin benutzt du in der inneren Schleife wieder i für das Abbruchkriterium und das Inkrementieren, nicht j. Auch braucht man die innere Schleife erst beim Index der äußeren Starten zu lassen. Ebenfalls wichtig ist Elemente nicht zu entfernen wenn i==j ist. Sonst würde jedes Element entfernt werden.

    Das Ergebnis könnte dann so aussehen:

    for (int i = 0; i < results.Count - 1; i++) //-1 da das letzte Element mit keinem mehr verglichen werden muss
    {
        for (int j = i + 1; j < results.Count; j++)
        {
            if (results[i].Cube1 == results[j].Cube2 && results[i].Cube2 == results[j].Cube1)
            {
                results.RemoveAt(j);
            }
        }
    }
    Die Fehler darin hättest du übrigens heraus gefunden wenn du verstanden hättest was der Algorithmus tun soll und du dann Schrittweise debuggt hättest.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert R3turnz Montag, 5. Oktober 2015 14:53
    Montag, 5. Oktober 2015 13:01
    Moderator

Alle Antworten

  • Hallo,

    ich verstehe ehrlich gesagt dien Vorhaben mit der Schleife nicht so ganz. Eine Möglichkeit wäre alle durchzuraten, bzw. wie in nachfolgender Version einen Rateversuch abzubrechen sobald man eine passende Kombination gefunden hat:

    for (int cube1 = 1; cube1 <= 6; ++cube1)
    {
        for (int cube2 = 1; cube2 <= 6 && cube1 + cube2 <= targetnumber; ++cube2)
        {
            if (cube1 + cube2 == targetnumber)
            {
                results.Add(new Combination(cube1, cube2));
            }
        }
    }

    Viel schöner ist es alle Kombinationen eines Würfels durchzugehen und zu gucken was der 2. Würfel für einen Wert hätte haben müssen:

    for (int cube1 = 1; cube1 <= 6; ++cube1)
    {
        if (targetnumber - cube1 <= 0) break;//Abbrechen da Zahl des 1. Würfels zu groß
        results.Add(new Combination(cube1, targetnumber - cube1));
    }

    Jetzt eine kleine Erweiterung für dich: Filtere die noch doppelten (also beispielsweise 1-6 und 6-1) heraus. Weiterhin empfehle ich dir noch zu gucken ob der Eingabewert nicht zu groß oder zu klein ist.

    Gern kannst du auch nochmals schreiben was du für eine Lösungsstrategie hattest.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert R3turnz Sonntag, 4. Oktober 2015 07:45
    Samstag, 3. Oktober 2015 19:47
    Moderator
  • Hallo, 

    ich habe die Eingabewertfilterung fertig, bei der dubletten suche habe ich mir folgendes überlegt:

                    List<Combination> todelete = new List<Combination>();
                    List<Combination> dublettenlist = new List<Combination>();
                    foreach (Combination dubletten in results)
                    {
                       foreach(Combination dubletten2 in results)
                        {
                            if (dubletten.Cube1 == dubletten2.Cube2 && dubletten.Cube2 == dubletten2.Cube1)
                            {
                                dublettenlist.Add(dubletten2);
                                todelete.Add(dubletten2);
                               
                            }
    
                                    }
    
                    }
                    foreach (Combination dublettendelete in todelete)
                    {
                        results.Remove(dublettendelete);
                    }
    
                    foreach (Combination output in results)
                    {
                     Console.WriteLine(output.ToString());
                        Console.WriteLine("Dubletten:");
                        
                    }
                    foreach (Combination dublettenoutput in dublettenlist)
                    {
                        Console.WriteLine(dublettenoutput.ToString());
                    }
                
                    Console.ReadKey();

    Es wird aber kein Ergebnis mehr herausgegeben, ich habe auch durch debuggen den Grund gefunden:

    Wenn z.B. targetnumber = 3 ist, gibt es ja folgende möglichkeiten:

    12,21

    Eigentlich klappt auch alles, alles wird richtig in die Listen eingetragen....

    Das Szenario ist: dubellten 1 = 12 und dubletten 2 = 21.

    Dann springt aber dubletten 1 auf = 21 und dublleten 2 = 12, so werden automatisch alle Einträge gelöscht.

    Wo muss ich hier ein break setzen, oder wie lässt sich es lösen?

    Sonntag, 4. Oktober 2015 08:18
  • Hallo,

    in deiner verschachtelten foreach-Schleife fügst du jeweils beide Paare zu den Listen hinzu, weswegen das hinzufügen und entfernen nicht so richtig funktioniert.

    Versuche mal ohne den extra Listen auszukommen. Versuche mal durch die Liste durchzugehen, aber mit einer for-Schleife. Dort drin gehst du dann wieder alle Elemente von 0 bis zum Index der äußeren Schleife durch. Wenn du in der inneren Schleife nun ein Duplikat des Elements findest das die äußere Schleife gerade angesteuert hat (also items[i] <-> items[j]), dann entfernst du das in der inneren Schleife gefundene Element. Wichtig dabei ist, dass du for-Schleifen nutzt, da foreach mit der Bearbeitung der Liste nicht klar kommen würde.

    Alternativ kannst du natürlich auch den Code zum generieren abändern.

    Auch hier würde ich dir gern mit deiner Lösungsidee helfen, aber ich weiß nicht wie du das meinst. Das wichtigste bei solchen Algorithmen ist einen ganz genauen Plan zu haben was wann passiert. Wenn man en hat kann man auch einfach beim Debuggen die Zeilen durchgehen und gucken was nicht funktioniert.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Sonntag, 4. Oktober 2015 11:47
    Moderator
  •     for(int i = 0;i <= results.Count;i++)
                    {
                        for(int j = 0; i <= results.Count; i++)
                        {
                            if (results[i].Cube1 == results[j].Cube2)
                                results.RemoveAt(j);
                                    }
                                }

    Eigentlich müsste sie jetzt doch funktionieren, tut sie aber nicht.

    Zu meinem Algorithmus muss ich sagen, dass ich einfach nicht mehr genug über Schleifen wusste, im Ansatz war sie identisch mit deiner.

    LG

    Montag, 5. Oktober 2015 12:53
  • Hallo,

    zunächst ein Grundsatz: Beim durchlaufen von Listen oder Arrays in einer for-Schleife nutzt man i<Length/Count und nicht <=. Bei <= würde man versuchen ein Element zu viel anzusteuern.

    Weiterhin benutzt du in der inneren Schleife wieder i für das Abbruchkriterium und das Inkrementieren, nicht j. Auch braucht man die innere Schleife erst beim Index der äußeren Starten zu lassen. Ebenfalls wichtig ist Elemente nicht zu entfernen wenn i==j ist. Sonst würde jedes Element entfernt werden.

    Das Ergebnis könnte dann so aussehen:

    for (int i = 0; i < results.Count - 1; i++) //-1 da das letzte Element mit keinem mehr verglichen werden muss
    {
        for (int j = i + 1; j < results.Count; j++)
        {
            if (results[i].Cube1 == results[j].Cube2 && results[i].Cube2 == results[j].Cube1)
            {
                results.RemoveAt(j);
            }
        }
    }
    Die Fehler darin hättest du übrigens heraus gefunden wenn du verstanden hättest was der Algorithmus tun soll und du dann Schrittweise debuggt hättest.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert R3turnz Montag, 5. Oktober 2015 14:53
    Montag, 5. Oktober 2015 13:01
    Moderator
  • Ok danke, muss einfach nochmal etwas in die Richtung machen...

    LG

    Montag, 5. Oktober 2015 14:54