Würfelspiel



  • Hallo,

    bräuchte mal eure Hilfe, im Rahmen einer Hausarbeit sollen wir unser erstes Programm selbst schreiben. Das Problem ist nur das ich bisher noch nie etwas in meinem Leben mit Programmieren zutun hatte.

    Es geht darum das Würfelspiel Kniffel zu programmieren.

    Habe schon versucht so viel wie nur möglich selbst zu erarbeiten und dabei im Rahmen des Tutoriums 5 Würfel wie folgt programmiert:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main ()
    {
    
        srand ( time(NULL) );
    
        int w1 = rand() % 6+1;
        int w2 = rand() % 6+1;
        int w3 = rand() % 6+1;
        int w4 = rand() % 6+1;
        int w5 = rand() % 6+1;
    
        printf ("Würfel 1: %d\n", w1);
        printf ("Würfel 2: %d\n", w2);
        printf ("Würfel 3: %d\n", w3);
        printf ("Würfel 4: %d\n", w4);
        printf ("Würfel 5: %d\n", w5);
    
        return 0;
    }
    

    Dies war noch relativ einfach doch nun geht es darum die verschiedenen möglichen Ergebnisse wie Straße Pasch Augenzahl etc. einzubeziehen.
    Doch ehrlichgesagt habe ich noch keine Ahnung wie ich das realisieren könnte.

    Hoffe es erbarmt sich jemand mir zu helfen 😃

    Viele Grüße,
    Marc


  • Mod

    ProfiStudent schrieb:

    Das Problem ist nur das ich bisher noch nie etwas in meinem Leben mit Programmieren zutun hatte.

    Es geht darum das Würfelspiel Kniffel zu programmieren.

    Das ist ganz schön ambitioniert...

    Doch ehrlichgesagt habe ich noch keine Ahnung wie ich das realisieren könnte.

    Das ist bei dem Kenntnisstand zu befürchten gewesen. Aber wie soll man dir helfen? Es ist eine schwierige Aufgabe, für die man Erfahrung in so ziemlich jedem Thema der C-Programmierung benötigt. Die richtige Antwort wäre, dass du Programmieren lernen musst. Wir können dir im Rahmen des Forums natürlich nicht komplett C beibringen, wir können nur Detailsfragen beantworten. Hast du ein Buch? Es gibt hier viele Bücherthreads und Threads speziell für Neulinge (unter anderem ganz oben in der Threadanzeige).

    Um ein komplettes Projekt von diesem Umfang anzugehen, ist wildes drauflosgehen auf scheinbare Teilprobleme eigentlich nicht die richtige Technik. Du solltest dir im Vorhinein überlegen, wie die nötigen Datenstrukturen aussehen sollen, welche Funktionen auf diesen arbeiten sollen. Das kannst du aber nur planen, wenn du dich sowohl im Großen als auch im Kleinen auskennst: Du musst bereits einen Plan im Kopf haben, was das Programm alles können soll (das ist eventuell durch die Aufgabenstellung vorgegeben), damit du die verschiedenen Teilprobleme erfassen kannst. Du musst wissen, wie gängige Datenstrukturen aussehen, was gängige Algorithmen sind und was ungefähr alles möglich ist und was nicht, damit du die Problemstellungen sinnvoll zerlegen und angehen kannst.

    Kniffel ist zwar noch überschaubar, aber schon so groß, dass es nicht mehr einfach ist. Du brauchst Erfahrung mit einfacheren Übungen.



  • Hallo Marc,

    das ist aber schon eine etwas anspruchsvollere Aufgabe als dein bisheriger Kenntnisstand vermuten läßt.

    Kennst du denn schon Arrays (wenn nicht dann lies es nach ;-)? Und schreibe dein Programm entsprechend um - und als Ausgabe eine Schleife (for oder while) verwenden.

    Und folgendes könnte dann noch hilfreich sein, wenn du die verschiedenen Ergebnisse vergleichen willst:
    - eine Count-Funktion schreiben, welche die Anzahl der Würfel einer bestimmten (übergebenen) Zahl zurückgibt
    - Sortieren eines Arrays (z.B. mittels qsort) für kleine und große Straße

    Das wird aber wohl einige Tage dauern...



  • Hi,

    Eine Count-Funktion für die Anzahl der Würfel mit einer bestimmten Augenzahl
    lohnt sich eher nicht. Irgendeine Sortierung ist auch nicht erforderlich.

    Du brauchst eine Funktion, die anhand der gewürfelten Augen der 5 Würfel
    (Array mit 5 Werten) und der gewünschten Kategorie (z.B. int/enum) die
    erzielten Punkte ermittelt. Als Teil dieser Funktion bietet sich dann im
    ersten Schritt an, ein Array mit den Anzahlen der jeweils gewürfelten
    unterschiedlichen Würfelaugen (Array mit 6 Werten) zu erstellen (mittels
    Schleife über die 5 Würfel den entsprechenden Wert um 1 erhöhen) und dann
    die gemäß Kategorie unterschiedlichen Berechnungen durchzuführen (switch).

    Für die Ermittlung, ob eine Straße vorliegt, könnten dann z.B. folgende Bedingungen für die Werte des letztgenannten Arrays geprüft werden:
    - klein : Die Werte für die 3 und 4 müssen jeweils größer 0 sein und zusätzlich ebenso für die 1 und 2, 2 und 5 oder 5 und 6.
    - groß : Die Werte für die 2, 3, 4 und 5 müssen jeweils größer 0 (d.h. in diesem Fall genau 1) sein und zusätzlich ebenso für die 1 oder 6.



  • ich habe es so realisiert:
    dicewidget.cpp
    #include "dicewidget.h"
    #include <stdlib.h>

    DiceWidget::DiceWidget( QWidget* parent )
    : QWidget( parent ), value( rand() % 6 + 1 ), rollable( yes ), clickStarted( false )
    {
    setMinimumSize( 40, 40 );
    time = new QTimer;
    rolled = 0;

    connect(time,SIGNAL(timeout()),this,SLOT(rolling()));
    }

    int DiceWidget::getValue( void )
    {
    return( value );
    }

    void DiceWidget::paintEvent( QPaintEvent* /* event*/ )
    {
    QPainter painter( this );
    painter.setRenderHint( QPainter::Antialiasing );
    QPen pen( palette().color( rollable ? QPalette::WindowText : QPalette::HighlightedText) );
    pen.setWidth( 3 );
    painter.setPen( pen );
    painter.setBrush( palette().color( rollable ? QPalette::Base : QPalette::Highlight));
    painter.translate( rect().center() );
    int diceSize = width() < height() ? width() : height();
    diceSize -= 3;
    diceSize /= 14;
    painter.drawRoundedRect( -diceSize * 7, -diceSize * 7,
    diceSize * 14, diceSize * 14,
    20, 20, Qt::RelativeSize );
    painter.setBrush( palette().color( rollable ? QPalette::WindowText : QPalette::HighlightedText) );
    switch( value )
    {
    case 5:
    painter.drawEllipse( QPoint( -diceSize * 4, diceSize * 4 ), diceSize, diceSize );
    painter.drawEllipse( QPoint( diceSize * 4, -diceSize * 4 ), diceSize, diceSize );
    case 3:
    painter.drawEllipse( QPoint( -diceSize * 4, -diceSize * 4 ), diceSize, diceSize );
    painter.drawEllipse( QPoint( diceSize * 4, diceSize * 4 ), diceSize, diceSize );
    case 1:
    painter.drawEllipse( QPoint(), diceSize, diceSize );
    break;
    case 6:
    painter.drawEllipse( QPoint( -diceSize * 4, 0 ), diceSize, diceSize );
    painter.drawEllipse( QPoint( diceSize * 4, 0 ), diceSize, diceSize );
    case 4:
    painter.drawEllipse( QPoint( -diceSize * 4, -diceSize * 4 ), diceSize, diceSize );
    painter.drawEllipse( QPoint( diceSize * 4, diceSize * 4 ), diceSize, diceSize );
    case 2:
    painter.drawEllipse( QPoint( -diceSize * 4, diceSize * 4 ), diceSize, diceSize );
    painter.drawEllipse( QPoint( diceSize * 4, -diceSize * 4 ), diceSize, diceSize );
    break;
    }
    }

    void DiceWidget::rollDice( void )
    {
    time->start(50);
    rolled = 0;
    }

    void DiceWidget::rolling(void)
    {
    if(rolled <= 4)
    {
    if( !rollable ) return;
    int newValue = rand() % 6 + 1;
    if( value != newValue )
    {
    value = newValue;
    update();
    emit valueChanged( value );
    }
    emit diceRolled( value );
    }
    rolled++;
    }

    bool DiceWidget::getRollable( void )
    {
    return( rollable );
    }

    void DiceWidget::setRollable( bool newState )
    {
    if( newState != rollable )
    {
    rollable = newState;
    update();
    emit rollableChanged( newState );
    }
    }

    void DiceWidget::mousePressEvent(QMouseEvent* event )
    {
    if(event->button() == Qt::LeftButton )
    {
    clickStarted = true;
    }
    }

    void DiceWidget::mouseReleaseEvent(QMouseEvent* event)
    {
    if(event->button() == Qt::LeftButton )
    {
    if( clickStarted )
    {
    emit clicked();
    clickStarted = false;
    }
    }
    }

    void DiceWidget::toggleRollable(void)
    {
    setRollable( !rollable );
    }

    dicewidget.h:
    #ifndef DICEWIDGET_H
    #define DICEWIDGET_H

    #include <QtGui>
    #include <QTimer>
    #define yes true
    #define no false

    class DiceWidget : public QWidget
    {
    Q_OBJECT
    private:
    int value;
    bool rollable;
    bool clickStarted;
    QTimer time;
    int rolled;
    public:
    explicit DiceWidget( QWidget
    parent = 0 );
    int getValue( void );
    bool getRollable( void );
    public slots:
    void rollDice( void );
    void rolling( void );
    void setRollable( bool newState );
    void toggleRollable( void );
    protected:
    virtual void paintEvent( QPaintEvent* event );
    virtual void mousePressEvent(QMouseEvent* event );
    virtual void mouseReleaseEvent(QMouseEvent* event);
    signals:
    void valueChanged( int newValue );
    void diceRolled( int newValue );
    void rollableChanged( bool newState );
    void clicked( void );
    };

    #endif // DICEWIDGET_H



  • Erst einmal vielen Dank für die Zahlreichen und sachlichen Antworten in der kurzen Zeit.

    Ihr habt mir wirklich schon sehr geholfen, vielen Dank.

    Ich denke es wird darauf hinauslaufen das ich mir ein anderes Projekt einfallen lasse, einfacher. Wie z.B. ein BMI Rechner etc. da hätte ich zumindest schonmal nen groben Ansatz im Kopf und wirklich nur Detailfragen.

    Für den Rest, denke ich, sollte ich mir wirklich erst einmal die Grundkenntnisse komplett aneignen.

    Hart auf hart muss ich das Projekt durchziehen da ich es immerhin schon so angemeldet habe, aber dann hab ich hier ja schonmal einige Ansätze und Anregungen von euch erhalten was die Sache für mich wirklich schon jetzt um einiges leichter macht. Hätte auch nie geglaubt dass das wirklich so umfangreich ist.
    Eher so 5 Zufallszahlen 1-6 und dann noch ein paar "Wenn das, dan das" so in der Art 😃

    Wie auch immer, nochmal vielen Dank für die schnelle und Umfangreiche Hilfe.

    Ach ja und an kniffel77 für was ist

    dicewidget.cpp 
    #include "dicewidget.h"
    

    bei dir?
    Standartbibliothek komm ich ja noch mit klar aber welche Funktion erfüllt diese Datei in deinem Code?



  • ProfiStudent schrieb:

    ... für was ist

    dicewidget.cpp 
    #include "dicewidget.h"
    

    bei dir?
    Standartbibliothek komm ich ja noch mit klar aber welche Funktion erfüllt diese Datei in deinem Code?

    dicewidget.cpp ist der Name der Datei die da gerade gezeigt wird.
    #include "dicewidget.h" bindet die Datei dicewidget.h ein.
    Die steht da auch noch. Angekündigt mit dicewidget.h

    Ist blöd dass er nicht die Codetags benutzt hat.
    Ist auch blöd, dass er C++ Code gepostet hat.
    Ist auch blöd, dass da noch Qt mit drin ist, ohne Kommentar


  • Mod

    ProfiStudent schrieb:

    Ich denke es wird darauf hinauslaufen das ich mir ein anderes Projekt einfallen lasse, einfacher. Wie z.B. ein BMI Rechner etc. da hätte ich zumindest schonmal nen groben Ansatz im Kopf und wirklich nur Detailfragen.

    Das klingt schon realistischer. 👍

    Ach ja und an kniffel77 für was ist

    dicewidget.cpp 
    #include "dicewidget.h"
    

    bei dir?
    Standartbibliothek komm ich ja noch mit klar aber welche Funktion erfüllt diese Datei in deinem Code?

    Das ist der Header, der am Ende seines Beitrags steht. In C ist es üblich, die Deklaration (man beachte den Unterschied zur Definition!) von structs und Funktionen, die noch in anderen Übersetzungseinheiten Verwendung finden könnten, in Headerdateien zu schreiben. Das wird dir klarer werden, wenn du über Headerdateien lernst.
    Bedenke auch, dass kniffel77s Code für das Qt-Framework geschrieben ist. Weder ist das C (es ist C++), noch hat dieses C++ irgendeine Ähnlichkeit mit "normalem" C++ (d.h. ohne Qt), da fast ausschließlich Qt-Funktionalität genutzt wird (was auch richtig so ist, wenn man Qt benutzt). Und mit ANSI-C hat das ganze überhaupt nichts zu tun außer ein paar Gemeinsamkeiten in der Syntax (d.h. der Grammatik der Programmiersprache).



  • hab mal versucht nen Ansatz mit meinem schmächtigen knowledge zu programmieren - ist mir nicht gelungen.
    Ich hab Kniffel noch nie gespielt und als ich gemerkt habe, dass ich die Regeln überhaupt nicht verstehe hab ich aufgehört. Aber der Ansatz hilft ProfiStudent sicher nach der Korrektur.

    Das Programm soll folgendes machen:
    - es ist 1 Wurf mit 5 Würfeln
    - die Zahlenaugen der 5 Würfel werden addiert ( Funktion: punkteanfangs() )
    - zu dem Ergebnis wird 25 bei zwei und drei gleichen- (fullhouse) oder 50 bei fünf gleichen Zahlenaugen (Kniffel) addiert (funktioniert nicht).

    Der code ist selbsterklärend:

    #include<stdio.h>
    int punkteanfangs();//fuer jede gewürfelte Augenzahl gleich erstmal zu Beginn 1 Punkt
    int fhoderkniff();//fullhouse oder Kniffel? return 25 oder 50 Punkte
    int main(){
    
    srand ( time(NULL) );
    int w[5];//Die Wuerfe
    int i;
    int Punkte=0;
    for(i=0;i<5;i++){
            w[i]=rand() %6+1;
            printf("Wuerfel %d: %d\n",(i+1),w[i]);}
    Punkte=Punkte+punkteanfangs(w)+fhoderkniff(w);
    printf("Punkte: %d\n",Punkte);
    return 0;}
    
    int punkteanfangs(int x[]){
    
    int i;
    int Anzahl=0;
    for(i=0;i<5;i++) Anzahl+=x[i];
    return Anzahl;}
    
    int fhoderkniff(int x[]){
    
    int i1,i2; //Zaehlvariabeln
    int Anzahl=0;
    int Anzahl2=0;
    for(i1=1;i1<7;i1++){//alle Augenzahlen (1 bis 6) werden durchgegangen
            for(i2=0;i2<5;i2++){//alle Wuerfel werden auf die Augenzahl verglichen
                    if(i1==x[i2]) Anzahl++;}
            if(Anzahl==5) {return 50; break;}//Kniffel! , kein fullhouse mehr moeglich
            if(Anzahl==2||Anzahl==3) Anzahl2=Anzahl;//Anzahl wird ja noch benoetigt
            if(Anzahl==2 && Anzahl2==3) {return 25; break;}//fullhouse
            if(Anzahl==3 && Anzahl2==2) {return 25; break;}//fullhouse
            Anzahl=0;}
    }
    

    Die Funktion fhoderkniff():
    Die fünf Würfelaugennummern werden jeweils auf gleichheit mit den Zahlen 1,2,3,4,5 und 6 verglichen.
    Die erste Schleife erzeugt die Nummer 1-6.

    for(i1=1;i1<7;i1++){
    

    Die Anzahl, wie viele Würfel den selben Wert wir diese Nummer haben wird in Anzahl gespeichert.

    for(i2=0;i2<5;i2++){
                    if(i1==x[i2]) Anzahl++;}
    

    Haben 5 Würfel Beispielsweise den Wert von 1, dann ist Anzahl == 5 und der Rückgabewert der Funktion ist 50, man hat einen Kniffel. Die Funktion wird dann mit break beendet.

    if(Anzahl==5) {return 50; break;}
    

    Ist dies nicht der Fall, so wird überprüft, ob 2 oder 3 Würfel die gleiche Augennummer aufweisen. Ist dies so, wird der Wert 2 oder 3 in eine nicht störende Variable Anzahl2 kopiert.

    if(Anzahl==2||Anzahl==3) Anzahl2=Anzahl;
    

    Die Hauptvariable wird wieder auf 0 gesetzt und das Programm überprüft eine Nummer weiter ...

    Anzahl=0;}
    

    Wenn nun 2 gleiche und 3 gleiche Zahlenaugen oder 3 gleiche und 2 gleiche vorkommen, dann hat man ein fullhouse. Der Rückgabewert der Funktion ist 25 und die Funktion bricht ab.

    if(Anzahl==2 && Anzahl2==3) {return 25; break;}
    if(Anzahl==3 && Anzahl2==2) {return 25; break;}
    

    Ist dies nicht der Fall, so hat die Funktion einfach keinen Rückgabewert.

    In der main-Funktion sieht die Ausgabe dann so aus:

    Punkte=Punkte+punkteanfangs(w)+fhoderkniff(w);
    printf("Punkte: %d\n",Punkte);
    


  • So es gibt Neuigkeiten 🙂

    Habe mich mit dem Prof. darauf geeinigt in Hinsicht der Vereinfachung der Aufgabe.

    Es sollen die folgenden 4 möglichen Ergebnisse ausgegeben werden.

    Chance (Alle 5 Augenzahlen zusammenzählen, bei jedem Wurf unabhängig von anderen Ergebnissen)

    3er Pasch (3x die selbe Augenzahl)

    4er Pasch (4x die selbe Augenzahl)

    Kniffel (alle 5 Würfel haben die selbe Augenzahl)

    Werde mich morgen früh wieder dem Projekt widmen und es hoffentlich im laufe des Tages fertig bekommen 😉

    Vielen Dank für die Hilfe und Unterstützung.
    Besonders an superstar für die Mühe.

    Viele Grüße,
    Marc



  • Wo studierst du wenn ich fragen darf?


Anmelden zum Antworten