Zufalls Funktion?



  • Hi,

    ich hab zwei fragen:
    1. Gibt es ne Funktion mit er ich eine zufällige Zahl generieren kann?

    2. Ich arbeite an nem Spiel: "UBoot Jagd" und ein Schiff zufällig umherfahren lassen hat einer ne Idee?

    Hie die Klassen dafür:

    ship.h:

    #ifndef SHIP_H
    #define SHIP_H
    
    #include "Koord.h"
    #include "Torpedo.h"
    
    class ship                                    // Klasse ship, die Klassen UBoot
    {                                             // und Enemy leiten sich von ihr
      public:                                     // ab.
      ship();
      virtual ~ship();
    
      virtual int GetRichtung() const;
      virtual int GetXKoord() const;
      virtual int GetYKoord() const;
      virtual void SetKoord(int, int);
      virtual void SetRichtung(int);
    
      virtual void Move(int);
      virtual void Shoot(int, int, int);
      virtual void TorpLaden() = 0;
      virtual int CheckTorpedo() const;
      virtual void SetTorp(int x);
    
      protected:
      int itsRichtung;
      Koord itsKoord;
      Torpedo* itsTorp[25];
    };
    
    #endif
    

    ship.cpp:

    #include "defs.h"
    #include "Koord.h"
    #include "ship.h"
    
    ship::ship()
    {}
    
    ship::~ship()
    {}
    
    int ship::GetRichtung() const
    {
      return itsRichtung;
    }
    
    int ship::GetXKoord() const
    {
      return itsKoord.GetX();
    }
    
    int ship::GetYKoord() const
    {
      return itsKoord.GetY();
    }
    
    void ship::SetKoord(int x, int y)
    {
      itsKoord.SetX(x);
      itsKoord.SetY(y);
    }
    
    void ship::SetRichtung(int richtung)
    {
      itsRichtung = richtung;
    }
    
    void ship::Move(int i)
    {
      int x = itsKoord.GetX();
      int y = itsKoord.GetY();
      switch(itsRichtung)
      {
        case NORDEN:
        {
          y = y + i;
          itsKoord.SetY(y);
          break;
        }
    
        case SUEDEN:
        {
          y = y - i;
          itsKoord.SetY(y);
          break;
        }
    
        case WESTEN:
        {
          x = x - i;
          itsKoord.SetX(x);
          break;
        }
    
        case OSTEN:
        {
          x = x + i;
          itsKoord.SetX(x);
          break;
        }
      }
    }
    
    void ship::Shoot(int richtung, int x, int y)
    {
      int i = CheckTorpedo();
      itsTorp[i]->SetRichtung(richtung);
      itsTorp[i]->SetZiel(x, y);
    }
    
    int ship::CheckTorpedo() const               // Funktion zur überprüfung welcher
    {                                            // Torpedo der erste nicht
      int i;                                     // abgefeuerte Torpedo ist.
      for(i = 0; i < 25; i++)
      {
        if (itsTorp[i] != 0)
        {
          break;
        }
      }
      return i;
    }
    
    void ship::SetTorp(int x)
    {
      delete itsTorp[x];
      itsTorp[x] = 0;
    }
    

    Enemy.h:

    #ifndef ENEMY_H
    #define ENEMY_H
    
    #include "ship.h"
    #include "State.h"
    #include "WasserBombe.h"
    
    class Enemy : public ship
    {
      public:
      Enemy();
      Enemy(int, int);
      ~Enemy();
    
      void BombeLaden();
      int CheckBombe() const;
      void ShootBombe();
      void TorpLaden();
    
      void Reagiere(UBoot&);
      void ChangeState(State*);
      int GetPlayer(UBoot&) const;
      void SearchPlayer();// <------------------- Da soll das umherfahren rein
    
      private:
      State * CurrentState;
      WasserBombe * itsBomben[30];
    };
    
    #endif
    

    Enemy.cpp:

    #include <iostream>
    
    #include "defs.h"
    #include "State.h"
    #include "StatePlayerUnknown.h"
    #include "Torpedo.h"
    #include "WasserBombe.h"
    #include "Enemy.h"
    #include "UBoot.h"
    
    Enemy::Enemy()
    {
      CurrentState = new State_PlayerUnknown;
    
      for (int i = 0; i < 25; i++)
      {
        itsTorp[i] = new Torpedo;
      }
    
      for (int i = 0; i < 30; i++)
      {
        itsBomben[i] = new WasserBombe;
      }
    }
    
    Enemy::Enemy(int x, int y)
    {
      itsKoord.SetX(x);
      itsKoord.SetY(y);
    
      CurrentState = new State_PlayerUnknown;
    
      for (int i = 0; i < 25; i++)
      {
        itsTorp[i] = new Torpedo;
      }
    
      for (int i = 0; i < 30; i++)
      {
        itsBomben[i] = new WasserBombe;
      }
    }
    
    Enemy::~Enemy()
    {}
    
    int Enemy::CheckBombe() const
    {
      int i;
      for(i = 0; i < 25; i++)
      {
        if (itsBomben[i] != 0)
        {
          break;
        }
      }
      return i;
    }
    
    void Enemy::ShootBombe()
    {
    
    }
    
    void Enemy::BombeLaden()
    {
      for (int i = 0; i < 30; i++)
      {
        itsBomben[i] = new WasserBombe;
      }
    }
    
    void Enemy::TorpLaden()
    {
      for (int i = 0; i < 25; i++)
      {
        itsTorp[i] = new Torpedo;
      }
    }
    
    void Enemy::Reagiere(UBoot& player)
    {
      CurrentState->Execute(this, player);
    }
    
    void Enemy::ChangeState(State * newState)
    {
      delete CurrentState;
      CurrentState = newState;
    }
    
    int Enemy::GetPlayer(UBoot & player) const
    {
      int x = player.GetXKoord();
      int y = player.GetYKoord();
      int itsX = itsKoord.GetX();
      int itsY = itsKoord.GetY();
    
      //***********************************
      if(itsX > x)
      {
        if(itsX - x > 3)
        {
          return UNBEKANNT;
        }
      }
      if(itsX < x)
      {
        if(x - itsX > 3)
        {
          return UNBEKANNT;
        }
      }                             // Auserhalb des Erfassungsbereichs
      if(itsY > y)
      {
        if(itsY - y > 3)
        {
          return UNBEKANNT;
        }
      }
      if(itsY < y)
      {
        if(y - itsY > 3)
        {
          return UNBEKANNT;
        }
      }
      //*************************************
    
        if(itsX == x && itsY == y)
        {
          return GEFUNDEN;
        }
    
        if(itsX == x)
        {
          if(y > itsY)
          {
            return NORDEN;
          }
          if(y < itsY)
          {
            return SUEDEN;
          }
        }
    
        if(itsY == y)
        {
          if(x > itsX)
          {
            return OSTEN;
          }
          if(x < itsX)
          {
            return WESTEN;
          }
        }
    
        if(y > itsY)
        {
          return NORDEN;
        }
        if(y < itsY)
        {
          return SUEDEN;
        }
    
    }
    
    void Enemy::SearchPlayer()
    {
      //<------------------------------ Hier das umherfahren
    }
    

    defs.h:

    #ifndef DEFS_H
    #define DEFS_H
    
    #define NORDEN    0
    #define WESTEN    1
    #define OSTEN     2
    #define SUEDEN    3
    #define UNBEKANNT 4
    #define GEFUNDEN  5
    
    #endif
    

    Wie ich das schiff bewege könnt ihr in der Move Funktion von ship sehen.

    Mfg Yazoo



    1. Ja, gibt es - nennt sich rand() (und Erklärungen/Hinweise zum Umgang damit solltest du im Web mehr als genug finden)

    2. Ich glaube kaum, daß sich jemand die Mühe machen wird, diesen Wust durchzuarbeiten. Im wesentlichen mußt du nur zufällige SetRichtung() und Move() Aufrufe aneinanderreihen und angemessen auf "Feindkontakt" reagieren.



  • Die Funktion std::rand() liefert die einen zufälligen Wert zwischen 0 und RAND_MAX,
    sie ist in cstdlib definiert (#incude <cstdlib>). Initalisieren tust du den Zufallsgenerator mit der Funktion std::srand().
    Beispiele findest du im entsprechenden Artikel im Magazin.
    http://magazin.c-plusplus.net/artikel/Zuf�lle gibt`sFragezeichenAusrufezeichen



  • das mit zufälligem SetRichtung() sollte sich mit rand() machen lassen, da die Richtung als int gespeichert wird, oder?



  • ich würde dir trotzdem ein enum empfehlen, ist schönerer Stil imho 😉



  • Hallo Yazoo,

    bevor ich zu dem 'Umherfahren' komme - benutzte bitte die Vektor- bzw. Positionsklasse Koord um die Positionen und Richtungen zu beschreiben. Dann wird alles einfacher übersichtlicher und viiiel kürzer. Ich hoffe, sie kann das, sonst siehe Listing von 'class Vec' weiter unten. Ebenso solltest Du die Richtung als Vektor auffassen. Also

    class ship 
    { 
    public:
      // ..
      Koord GetPos() const { return itsKoord; }
    protected:
      // ..
      Koord itsRichtung;
      Koord itsKoord;
    

    Dann vereinfacht sich das Move zu

    void ship::Move( const Koord& dir )
    {
        itsKoord += dir;
        itsRichtung = dir;
    }
    

    und das Enemy::GetPlayer

    int Enemy::GetPlayer( const UBoot& player ) const
    {
      const Koord to_player = player.GetPos() - itsKoord;
      if( abs( to_player ) > 3 )  // siehe class Vec
      {
        // Auserhalb des Erfassungsbereichs
        return UNBEKANNT;
      }
      if( to_player == Koord() ) // to_player = (0,0)
      {
          return GEFUNDEN;
      }
      // usw. - ggf. gibt es hier auch einen allgemeinen Code, wenn
      // die Schnittstelle geändert wird - z.B. einfach:
      return to_player / abs( to_player ); // mit der Richtung zurück
    }
    

    Jetzt zum zufälligen Verfahren. Ich benutzt dazu eine Zufall-Klasse aus einem anderen Thread. Das Schiff soll so fahren, dass es öfter geradeaus fährt, als die Richtung wechselt. Das erreicht man z.B. so:

    void Enemy::SearchPlayer()
    {
      //<------------------------------ Hier das umherfahren
      const int N = 3; // grosses N, oft geradeaus, kleines N oft Kurswechsel
      Zufall< int > z( -N, N+1 ); // liefert Werte im Intervall [-N,N+1[ = [-N,N]
      for(;;) // Schleife über alle Schritte
      {
        move( itsRichtung.turn( z() / N ) ); // Z()/N liefert -1,0,1
        // neue Position erreicht
        // .. 
      }
    }
    

    das war's eigentlich schon. Hier noch das Listing von 'class Vec':

    #include <algorithm>
    #include <cmath>
    #include <iostream>
    
    // --   eine ganz einfache Vektor- bzw. Positionsklasse
    class Vec
    {
    public:
        Vec() : m_x(0), m_y(0) {}
        Vec( int x, int y ) : m_x(x), m_y(y) {}
    
        Vec& operator+=( const Vec& b )
        {
            m_x += b.m_x; m_y += b.m_y;
            return *this;
        }
        Vec& operator-=( const Vec& b )
        {
            m_x -= b.m_x; m_y -= b.m_y;
            return *this;
        }
    
        bool operator==( const Vec& b ) const
        {
            return m_x == b.m_x && m_y == b.m_y;
        }
    
        // --   Betrag ist hier der maximale Abstand in einer Richtung
        friend int abs( const Vec& v )
        {
            return std::max( std::abs( v.m_x ), std::abs( v.m_y ) );
        }
    
        // --   gedrehten Vektor bestimmen: 
        //      dir > 0: links, dir = 0: gerade; dir < 0: rechts
        Vec turn( int dir ) const
        {
            if( dir > 0 )   // drehen nach links
                return Vec( -m_y, m_x );
            if( dir < 0 )   // drehen nach rechts
                return Vec( m_y, -m_x );
            return *this;   // geradeaus = nicht drehen
        }
    
        // --   Ausgabe
        friend std::ostream& operator<<( std::ostream& out, const Vec& v )
        {
            return out << v.m_x << " " << v.m_y;
        }
        // --   Getters (bitte sparsam benutzen!)
        friend int X( const Vec& Vec ) { return Vec.m_x; }
        friend int Y( const Vec& Vec ) { return Vec.m_y; }
    
    private:
        int m_x, m_y;
    };
    
    Vec operator+( Vec a, const Vec& b )
    {
        return a += b;
    }
    Vec operator-( Vec a, const Vec& b )
    {
        return a -= b;
    }
    bool operator!=( const Vec& a, const Vec& b )
    {
        return !(a == b);
    }
    // und ggf.:
    typedef Vec Koord;
    

    Gruß
    Werner



  • ehrlichgesagt ich habe nur die hälfte davon verstanden was Werner Salomon sagte, aber trozdem danke euch allen das ihr euch so viel mühe gemacht habt mir zu helfen.

    Das Prob ist gelöst, aber es ist schon ein neues aufgetreten, seht euch meinen neuen thread an...

    thx und cya



  • Yazoo schrieb:

    ehrlichgesagt ich habe nur die hälfte davon verstanden was Werner Salomon sagte, ...

    Tue mir doch mal den Gefallen und sage mir, was Du genau nicht verstanden hast.

    das wäre super
    Werner



  • vor allen das mit dem turn() versteh ich nicht, also wie du genau die richtung speicherst und veränderst.



  • Yazoo schrieb:

    vor allen das mit dem turn() versteh ich nicht, also wie du genau die richtung speicherst und veränderst.

    Ok - da wäre ich gar nicht drauf gekommen, dass das ein Problem ist.

    Zu Richtung speichern: die Richtung ist im Prinzip auch eine Koordinate - genaugenommen ein Vektor - aber eben keine Koordinate wie die des Schiffs, die sich ja auf einen globalen Ursprung bezieht, sondern die Richtung ist die Koordinate, die dort startet wo Dein Schiff sich gerade befindet.

    Ich unterstelle jetzt mal, dass die x-Achse nach Osten (bzw. rechts) zeigt und Dein Koordinatensystem mathematisch positiv dreht, Dann wären die Himmelsrichtungen
    Osten = ( 1, 0) ein Schritt nach rechts
    Norden = ( 0, 1) ein Schritt nach oben
    Westen = (-1, 0) ein Schritt nach links
    Süden = ( 0,-1) ein Schritt nach unten

    Bespiel: das Schiff befindet sich an Position (7,2) und die Richtung wäre Norden also (0,1), dann brauchst Du nur die beiden Koordinaten bzw. Vektoren addieren und das Schiff ist dann bei
    (7,2) + (0,1) = (7,3)
    im Programm ist das die Stelle

    itsKoord += dir;
    

    Der Vorteil dieser Methode - gegenüber dem mühseligen Abfragen (if(Norden) else if(Westen) usw.) - ist, dass die Richtung auch andere Werte z.B.20° annehmen kann. Ich unterstelle jetzt, dass 0° genau nach Osten also nach (1,0) zeigt. Dann ist:
    Richtung(20°) = (cos(20°); sin(20°)) = (0,940; 0,342)

    Ein Turn nach links - also eine Drehung um 90° nach links - vertauscht einfach die Koordinaten und negiert den neuen x-Wert. Versuche es erst mit den Himmelsrichtungen
    aus Osten ( 1,0) wird (-0,1) = (0,1) also Norden
    aus Norden (0,1) wird (-1,0) als Westen usw.

    Wäre das ein beliebiger Winkel w geht es genauso
    aus (cos(w), sin(w)) wird (cos(w+90°), sin(w+90°))
    schau Dir mal die Additionstheoreme der Trigonometrie an, so ist
    cos(w+90°) = cos(w)*cos(90°) - sin(w)*sin(90°) und
    sin(w+90°) = sin(w)*cos(90°) + cos(w)*sin(90°)

    wenn man jetzt weiß, dass sin(90°)=1 und cos(90°)=0 ist, dann ergibt sich
    cos(w+90°) = -sin(w) und
    sin(w+90°) = cos(w)
    bzw. die neue Richtung
    (cos(w+90°), sin(w+90°)) = ( -sin(w), cos(w) )

    Mit dem turn nach links also Drehung um -90° geht es entsprechend.

    Gruß
    Werner



  • ich habe das prob so gelöst:

    void ship::Move(int i)
    {
      double x = itsKoord.GetX();
      double y = itsKoord.GetY();
    
      x += std::sin(deg_to_rad(itsRichtung)) * i;
      y += std::cos(deg_to_rad(itsRichtung)) * i;
    
      itsKoord.SetAll(x, y);
    }
    

    itsRichtung ist int variable der klasse ship


Anmelden zum Antworten