Qt Feld mit 25x25 Feldern



  • Hallo

    Wie würde man denn nachdem man das 25x25 Feld erstellt hat die 94 Hindernisse und Start-/Zielpunkt setzen?

    Schöne Grüße



  • Du wählst random eine Position aus, wenn diese schon belegt ist, wählst du eine neue. Das machst du 94 mal.



  • Hier ist unser derzeitiges Ergebnis.

    Wir haben eine Oberfläche, die aktuell die verschiedenen Felder darstellt.
    Nun haben wir Probleme damit Bewegung ins Ganze zubekommen.

    #include "Field.h"
    #include <QTime>
    
    Field::Field() {
        for (int x = 0; x < 25; x++) {
            for (int y = 0; y < 25; y++) {
                setFree(QPoint(x, y));
            }
        }
    
        qsrand(QTime::currentTime().msec());
    
        int counter = 0;
        while (counter < 94) {
            QPoint p = getRandomPoint();
            if (isFree(p)) {
                setBlocked(p);
                counter++;
            }
        }
    
        while (true) {
            QPoint p = getRandomPoint();
            if (isFree(p)) {
                target = p;
                break;
            }
        }
    
        while (true) {
            QPoint p = getRandomPoint();
            if (isFree(p)) {
                robot.setRobotPosition(p);
                break;
            }
        }
    }
    
    QPoint Field::getRandomPoint() {
        return QPoint(qrand() % 25, qrand() % 25);
    }
    
    bool Field::isBlocked(QPoint p) {
        return allocation[p.x()][p.y()] == 1;
    }
    
    bool Field::isFree(QPoint p) {
        return allocation[p.x()][p.y()] == 0;
    }
    
    void Field::setBlocked(QPoint p) {
        allocation[p.x()][p.y()] = 1;
    }
    
    void Field::setFree(QPoint p) {
        allocation[p.x()][p.y()] = 0;
    }
    
    QPoint Field::getTarget() {
        return target;
    }
    
    QPoint Field::getRobot() {
        return robot.getRobot();
    }
    
    #include "MainWindow.h"
    #include <QPainter>
    #include <QPoint>
    #include "Robot.h"
    
    MainWindow::MainWindow() {
        setFixedSize(625, 625);
        this->field = new Field();
    }
    
    void MainWindow::paintEvent(QPaintEvent* event) {
        QPainter painter;
        painter.begin(this);
    
        QPoint target = field->getTarget();
        QPoint robot = field->getRobot();
    
        for (int x = 0; x < 25; x++) {
            for (int y = 0; y < 25; y++) {
                QPoint p(x, y);
    
                if (field->isBlocked(p))
                    painter.fillRect(x * 25, y * 25, 25, 25, Qt::darkRed);
    
                if (field->isFree(p))
                    painter.fillRect(x * 25, y * 25, 25, 25, Qt::darkGreen);
    
                if (p == target)
                    painter.fillRect(x * 25, y * 25, 25, 25, Qt::yellow);
    
                if (p == robot)
                    painter.fillRect(x * 25, y * 25, 25, 25, Qt::black);
            }
        }
    
        painter.end();
    }
    
    #include "Robot.h"
    #include "Field.h"
    #include <stdio.h>
    #include <windows.h>
    
    Robot::Robot() {
    
    }
    
    QPoint Robot::getRobot() {
        return robotPosition;
    }
    
    void Robot::setRobotPosition(QPoint p) {
        robotPosition = p;
    }
    

    Vielleicht findet sich ja jemand, der uns nen Tipp gibt, wie wir den Roboter auf dem Feld bewegen könnten.

    Schöne Grüße



  • Student94 schrieb:

    Vielleicht findet sich ja jemand, der uns nen Tipp gibt, wie wir den Roboter auf dem Feld bewegen könnten.

    Was heißt das? Willst du irgendwelche Animationen, oder willst du Drag&Drop? Wenn du einfach nur Drag&Drop willst, wäre das mit QGraphicsScene und -view einfacher. Kriegt man allerdings auch ohne hin. Die entsprechenden Methoden überschreiben (dragEnterEvent usw.) und das QMimeData initialisieren.



  • Der Robot soll sich von allein über das Feld bewegen, also kein Drag&Drop oder unnötige Animationen.



  • Dann benutze dafür am besten einen Timer (z.B. mit 1s Intervall), in dem du die Roboterposition veränderst und dann für das MainWindow ein Neuzeichnen (per update() oder repaint()) erzwingst.



  • Danke für die Tipps.

    Wie können wir den QPoint, der auf die Position des Roboters zeigt verschieben?
    Am besten auf unser Beispiel bezogen, weil wir theoretisch wissen, wie es funktioniert.



  • Du hast doch schon die entsprechenden Funktionen:

    QPoint p = robot.getRobot();
    p.X++;
    robot.setRobotPosition(p);
    

    Wobei robot dann deine Membervariable in der Field-Klasse ist, d.h. diese müßtest du dann der Main-Klasse zugänglich machen, so daß es besser ist, du benennst deine Funktionen sinnvoller um:

    Robot& Field::getRobot()
    {
        return robot;
    }
    
    QPoint Robot::getPosition()
    {
        return robotPosition;
    }
    

    Alternativ (und m.E. besser!) erzeugst du dir in der Field-Klasse eine MoveRobot-Funktion:

    void Field::MoveRobot(QPoint move)
    {
      QPoint p = robot.getPosition();
      p += move;
      robot.setPosition(p);
    }
    

    Aufruf dann z.B. so

    field->MoveRobot(QPoint(1, 0));
    

    (müßtest natürlich noch Ränder und Wände etc. abfangen)



  • Wir haben jetzt das Programm soweit am Laufen, dass sich der Robot auch visuell auf dem Feld bewegt.

    Jetzt haben wir das Problem, dass wir keine schöne Lösung für das Umgehen von Hindernissen finden. D.h. wir würden es mit einer enormen Menge verschachtelter if-Bedingungen bzw. einem case versuchen.
    Das wirkt auf uns aber leider recht unschön.

    Hat jemand einen Tipp wie man das Umgehen gut bewerkstelligen kann?

    MfG

    Student94



  • Da bietet sich der A*-Algorithmus an, s. z.B. Implementation of A*

    Edit: sehe gerade "Der Roboter kann nur die 8 Felder um Ihn Herum sehen." 😞
    Kennt der Roboter denn wenigstens die Position des Ziels (und seine eigene innerhalb der Map)? Damit er wenigstens den Abstand zum Ziel kennt und darauf basierend dann versucht dem Ziel näher zu kommen (und bei Hindernissen dann z.B. zufällig nach rechts oder links sich bewegt) - sinnvoll wäre dann auf jeden Fall sich zu merken, wo der Roboter schon gewesen ist, um nicht "im Kreis zu fahren".

    Evtl. hilft auch Lösungsalgorithmen für Irrgärten



  • Vielen Dank für die schnelle Antwort!

    Wir haben unseren Hirnschmalz ein wenig angestrengt und uns ist aufgefallen, dass wir die möglichen nächsten Schritte in eine QList eintragen können und die schon gegangenen ebenfals, sodass wir es ausschließen das der Robot im Falle einer Sackgasse immer wieder in die hineinläuft.

    MfG

    Student94



  • Randbemerkung
    QList verwaltet die Daten je nach Größe des Datentyps anders.

    Internally, QList<T> is represented as an array of pointers to items of type T. If T is itself a pointer type or a basic type that is no larger than a pointer, or if T is one of Qt's shared classes, then QList<T> stores the items directly in the pointer array.

    Q: http://doc.qt.io/qt-4.8/qlist.html

    Das Entscheidungskriterium ist Plattform abhängig (32 bit pointer = 4 byte, 64 bit pointer = 8 byte).

    Vgl: https://marcmutz.wordpress.com/effective-qt/containers/

    Ich würde Abstand von QList nehmen ... entweder STL oder eine Qt Klasse wo das Speicherlayout fest ist, egal welcher Datentyp T und Zielplatform.


Anmelden zum Antworten