Contest #2: Space Invaders



  • Skym0sh0 schrieb:

    so, auf visual c++ portiert(so dass es läuft), aber hab keinen anderen compiler, daher kann ichd a nix sagen

    Hab Deinen Code umgefrickelt, daß die Plattformabhängigkeiten aus dem Haupt-Code raus sind.
    Aber wieder mit gcc unter linux.
    Gehts noch unter visual c++?

    #include <iostream>
    #include <vector>
    #include <cstdlib>
    #include <ctime>
    #include <memory>
    using namespace std;
    
    #ifdef WIN32
    #include <Windows.h>
    void sleep(int seconds)
    {
        Sleep(1000*seconds);
    }
    void cls()
    {
        system("cls");
    }
    #else
    #include <unistd.h>
    void cls()
    {
        cout << "\x1b[2J\x1b[H" << flush;
    }
    #endif // WIN32
    
    struct Point
    {
        size_t x, y;
    
        Point(size_t x_ = 0, size_t y_ = 0)
            : x(x_), y(y_)
        {}
    };
    
    class SpaceField;
    class SpaceShip
    {
    private:
        Point position;
        bool aLive, moveDone;
    public:
        SpaceShip()
        : position(8, 15)
        , aLive(true), moveDone(false)
        { }
    
        void destroy() { aLive = false; }
        bool isAlive() const { return aLive; }
    
        void doMove(SpaceField &field);
    
        virtual void computeNextMove(const SpaceField &field) = 0;
    
        void moveRight()
        {
            if(moveDone) return;
            ++position.x;
            moveDone = true;
        }
    
        void moveLeft()
        {
            if(moveDone) return;
            --position.x;
            moveDone = true;
        }
    
        void moveUp()
        {
            if(moveDone) return;
            --position.y;
            moveDone = true;
        }
    
        void moveDown()
        {
            if(moveDone) return;
            ++position.y;
            moveDone = true;
        }
    
        Point getPosition() const { return position; }
    };
    
    class Astroids
    {
    private:
        vector<Point> astroidsPosition;
        size_t difficulty;
        long seed;
    
        long randomy()
        {
            return (((seed = seed * 214013L + 2531011L) >> 16) & 0x7fff);
        }
    
        void generateNewAstroids()
        {
            if(randomy() % 2 == 0) return;
    
            int noOfAstroids = randomy() % (difficulty > 15 ? 15 : difficulty) +1;
            while(noOfAstroids--)
            {
                astroidsPosition.push_back(Point(randomy() % 20, 0));
            }
    
        }
    public:
        Astroids()
        {
            difficulty = 1;
            seed = 1234;
        }
    
        void increaseDifficulty()
        {
            ++difficulty;
        }
    
        size_t getDifficulty() const
        {
            return difficulty;
        }
    
        void moveForward()
        {
            generateNewAstroids();
    
            for(vector<Point>::iterator it = astroidsPosition.begin(); it != astroidsPosition.end();)
            {
                if(++it->y > 20)
                    it = astroidsPosition.erase(it);
                else ++it;
            }
        }
    
        vector<Point> getAstroidPosition() const
        {
            return astroidsPosition;
        }
    };
    
    class SpaceField
    {
    private:
        char spaceField[20][20];
    
        SpaceShip *spaceShip;
    
        Astroids astroids;
        Point lastShipPosition;
    
        void init()
        {
            for(size_t y = 0; y < 20; ++y)
                for(size_t x = 0; x < 20; ++x)
                    spaceField[x][y] = '_';
        }
    
        void updateField()
        {
            init();
            spaceField[lastShipPosition.y][lastShipPosition.x] = 'S';
    
            vector<Point> astroPoints = astroids.getAstroidPosition();
    
            for(size_t i = 0; i < astroPoints.size(); ++i)
                spaceField[astroPoints[i].y-1][astroPoints[i].x] = 'A';
        }
    public:
        SpaceField()
        {
            init();
        }
    
        void insertShip(SpaceShip *ship)
        {
            spaceShip = ship;
            spaceField[spaceShip->getPosition().y][spaceShip->getPosition().x] = 'S';
    
            lastShipPosition = spaceShip->getPosition();
        }
    
        void increaseLevel()
        {
            astroids.increaseDifficulty();
        }
    
        bool isAstroidHere(Point checkPoint) const
        {
            return spaceField[checkPoint.y][checkPoint.x] == 'A';
        }
    
        size_t getLevel() const
        {
            return astroids.getDifficulty();
        }
    
        size_t getSizeY() const { return 20-1; }
        size_t getSizeX() const { return 20-1; }
    
        void moveShip(Point to)
        {
            if(spaceField[lastShipPosition.y][lastShipPosition.x] != 'A')
                spaceField[lastShipPosition.y][lastShipPosition.x] = '_';
    
            if(spaceField[to.y][to.x] == 'A')
            {
                spaceShip->destroy();
                return;
            }
    
            spaceField[to.y][to.x] = 'S';
            lastShipPosition = to;
        }
    
        void moveAstroidsForward()
        {
            astroids.moveForward();
            updateField();
        }
    
        void printField() const
        {
            cls();
            for(size_t y = 0; y < 20; ++y)
            {
                for(size_t x = 0; x < 20; ++x)
                    cout << spaceField[y][x];
    
                cout << endl;
            }
            cout << endl;
        }
    };
    
    void SpaceShip::doMove(SpaceField &field)
    {
        moveDone = false;
        computeNextMove(field);
        field.moveShip(position);
    }
    
    class CustomSpaceShip : public SpaceShip
    {
    public:
        void computeNextMove(const SpaceField &field)
        {
            Point checkPoint = this->getPosition();
            --checkPoint.y;
    
            if(field.isAstroidHere(checkPoint)){
                if(field.getSizeX() > checkPoint.x)
                    this->moveRight();
                else
                    this->moveLeft();
            }
        }
    };
    
    int main()
    {
        SpaceField spaceField;
    
        std::shared_ptr<SpaceShip> ship(new CustomSpaceShip());
        spaceField.insertShip(ship.get());
    
        long cycles = 0;
        while(ship->isAlive())
        {
            ++cycles;
            spaceField.printField();
    
            spaceField.moveAstroidsForward();
            ship->doMove(spaceField);
    
            if(cycles % 10 == false)
                spaceField.increaseLevel();
    
            cout << cycles << " light years survived" << endl;
            cout << "Level" << spaceField.getLevel() << endl;
    
            sleep(1);
        }
    
        cout << "\nYou survived " << cycles << " light years far!" << endl;
    
        return 0;
    }
    


  • ja, kompiliert mit /W4 ohne warnung



  • @volkard: Erst jetzt funktioniert es sogar bei mir.


  • Mod

    mit

    #ifdef WIN32
    extern "C" void __stdcall Sleep(unsigned long);
    void sleep(int seconds)
    {
        Sleep(1000u*seconds);
    }
    

    spart man sich das Einbinden von windows.h und kann sogar die Spracherweiterungen abschalten.



  • Danke für die Änderungen. Habe den Orginalbeitrag angepasst.



  • KasF schrieb:

    Danke für die Änderungen. Habe den Orginalbeitrag angepasst.

    fyi: die korrekte Loesung dafuer dass das Schiff nicht unendlich weit fliegen kann ist, dass computeNextMove einen Wert returned der die Richtig angibt die das Schiff fliegen will.

    Weil aktuell kann ich mit const_cast immer noch soweit fliegen wie ich will.



  • Und eine wirksame Massnahme gegen unerwünschtes Modifizieren des Feldes wäre das Feld vor jedem computeNextMove Aufruf zu kopieren, und nur einen Zeiger/Referenz auf die Kopie zur Verfügung zu stellen.



  • da kann man auch gleich en copy by value machen...
    aber wäre schonmal was



  • Skym0sh0 schrieb:

    da kann man auch gleich en copy by value machen...

    Ja, stimmt.



  • Update:

    • Shade
    • Skym0sh0/hustbaer
    • recursionDetected: Avoid recursive call of computeNextMove over doMove


  • Bisherige Einsendungen: 0 :-\



  • Das liegt wohl daran, dass sich die Parameter für den Contest alle naselang ändern. Siehe auch den ersten Contest.

    Zumindest ich persönlich habe keine Lust, meine Zeit drauf zu verwenden wenn die Sache in wenigen Stunden wieder komplett anders aussehen kann. Denn Contest an sich finde ich ja eine gelungene Abwechselung, aber nur dann, wenn die Aufgabe a) feststeht und b) auch soweit durchdacht ist, dass sie nicht mehr geändert wird.

    Bis dahin, werde ich meine Zeit anders einsetzen 😉



  • Ja, das stimmt. Warten wir mal ab, ob noch einige Verbesserungsvorschläge kommen werden.



  • Bisherige Einsendungen: 0 :-\

    Hihi.
    Wundert mich jetzt nicht.

    Sowas sollte man denke ich ankündigen (oder hab ich die Ankündigung übersehen), und dann auch besser ausschreiben - nicht husch-pfusch.
    Und vielleicht auch etwas vortasten welche Themen auf wie viel Resonanz stossen.


Anmelden zum Antworten