Einstieg - Simulation eines Roboters

Der Roboter baut mit Ziegeln

Bisher kann der Roboter nur in seiner Welt herumlaufen. Die Fähigkeiten des Roboters sollen jetzt so erweitert werden, dass er in seiner Welt auch mit Ziegeln bauen kann.

Roboterwelt

Wenn ein Programm zur Simulation eines Roboters eingesetzt werden soll, dann muss es die Daten der Roboterwelt erfassen und Vorgänge in der Roboterwelt simulieren können. Die Roboterwelt mit bestimmten Gegenständen (Roboter, Ziegel, ...) und Vorgängen (Schritt vorwärts gehen, Ziegel aufheben, ...) muss also im Programm geeignet erfasst werden.

Aufgabe 1

Das bisher entwickelte Robotersystem wird von zwei Objekten dargestellt, einem Objekt rob zur Verwaltung des Roboters und einem Objekt welt zur Verwaltung der Weltdaten.

Im weiterentwickelten Robotersystem (mit den Ziegeln) muss verwaltet werden, in welchen Feldern wie viele Ziegel liegen. Zudem müssen Operationen wie Ziegel hinlegen und Ziegel aufheben ausgeführt werden können.

Welches Objekt wird wohl für welche Aufgabe zuständig sein?

Verwaltung der Ziegel

Die Verwaltung der in der Welt befindlichen Ziegel soll vom Welt-Objekt welt übernommen werden. Für jedes Feld muss sich das Objekt welt dann merken, wie viele Ziegel dort abgelegt sind. Das Objekt welt benötigt hierzu ein zusätzliches Attribut ziegel, mit dem alle diese Anzahlen erfasst werden. Die vom Attribut ziegel verwaltete Datenstruktur ist eine Reihung von Reihungen von Zahlen, die mit Hilfe von Listen dargestellt werden kann. Hier soll eine Darstellung benutzt werden, die die oben gezeigte Welt so beschreibt:

{welt: 
    felderX -> 4, 
    felderY -> 4, 
    ziegel -> [[0, 1, 2, 3], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
}

Die erste Liste [0, 1, 2, 3] beschreibt die Anzahl der Ziegel in den Feldern der hintersten Felderreihe - das sind die mit den Koordinaten (0, 0), (1, 0), (2, 0), (3, 0). Entsprechend beschreibt die zweite Liste [0, 0, 0, 0] die Anzahl der Ziegel in den Feldern der davorliegenden Felderreihe - das sind die mit den Koordinaten (0, 1), (1, 1), (2, 1), (3, 1), usw..

Aufgabe 2

Wie sieht die folgendermaßen beschriebene Welt aus?

{welt: 
    felderX -> 4, 
    felderY -> 4, 
    ziegel -> [[1, 1, 1, 1], [1, 0, 0, 1], [1, 0, 0, 1], [1, 1, 1, 1]]
}

Neue Operationen der Klasse Welt

Um Ziegel in einem Feld der Welt hinzufügen oder wegnehmen zu können, benötigt man geeignete Methoden. Zusätzlich benötigt man Zugriffsmethoden, um die jeweilige Anzahl von Ziegeln in einem Feld ermitteln zu können. Zu diesem Zweck soll ein Welt-Objekt über folgende Methoden verfügen:

incZiegel(x: int, y: int):

vorher: Das Welt-Objekt beschreibt einen Weltzustand.

nachher: Das Welt-Objekt beschreibt einen Weltzustand, bei dem die Anzahl der Ziegel im Feld mit den Koordinten (x, y) inkrementiert worden ist (d. h. um 1 erhöht worden ist).

decZiegel(x: int, y: int):

vorher: Das Welt-Objekt beschreibt einen Weltzustand.

nachher: Das Welt-Objekt beschreibt einen Weltzustand, bei dem die Anzahl der Ziegel im Feld mit den Koordinten (x, y) dekrementiert worden ist (d. h. um 1 vermindert worden ist - sofern diese Anzahl vorher größer als 1 war).

getZiegel(x: int, y: int): int:

vorher: Das Welt-Objekt beschreibt einen Weltzustand.

nachher: Das Welt-Objekt beschreibt denselben Weltzustand. Die Methode liefert die Anzahl der Ziegel im Feld mit den Koordinten (x, y) als Wert zurück.

getAlleZiegel(x: int, y: int): list:

vorher: Das Welt-Objekt beschreibt einen Weltzustand.

nachher: Das Welt-Objekt beschreibt denselben Weltzustand. Die Methode liefert die gesamte Liste mit allen Ziegelanzahlen als Wert zurück.

Klassendiagramm zur Klasse Welt

Insgesamt ergibt sich so das folgende neue Klassendiagramm:

Klassendiagramm

Implementierung der Klasse Welt

Die folgende Klassendeklaration in Python implementiert die Klasse Welt des gezeigten Klassendiagramms.

class Welt(object):
    def __init__(self, x, y):
        self.felderX = x
        self.felderY = y
        # Erzeugung der Listen
        l = []
        for i in range(self.felderY):
            m = []
            for j in range(self.felderX):
                m = m + [0]
            l = l + [m]
        self.ziegel = l

    def getFelderX(self):
        return self.felderX

    def getFelderY(self):
        return self.felderY

    def incZiegel(self, x, y):
        self.ziegel[y][x] = self.ziegel[y][x] + 1

    def decZiegel(self, x, y):
        if self.ziegel[y][x] > 0:
            self.ziegel[y][x] = self.ziegel[y][x] - 1

    def getZiegel(self, x, y):
        return self.ziegel[y][x]

    def getAlleZiegel(self):
        return self.ziegel    

Aufgabe 3

(a) Welche zusätzliche Aufgabe wird hier vom Konstruktor __init__ übernommen?

(b) Teste die Klassendeklaration durch ein Python-Protokoll wie das folgende.

>>> welt = Welt(4, 4)
>>> welt.getAlleZiegel()
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> welt.incZiegel(2, 1)
>>> welt.getAlleZiegel()
[[0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

Erweiterung der Klasse Roboter

Bisher kann der Roboter nur in seiner Welt herumlaufen. Die Fähigkeiten des Roboters sollen jetzt so erweitert werden, dass er Ziegel in die Welt hinlegen und wieder aufheben kann. Das folgende Klassendiagramm zeigt die hierzu erforderlichen neuen Methoden.

Klassendiagramm Roboter

ziegelHinlegen():

vorher: Das Roboter-Objekt befindet sich irgendwo in der Welt.

nachher: Das Roboter-Objekt befindet sich im selben Feld. Wenn das Roboter-Objekt nicht vor einer Wand steht, dann hat es in dem vor ihm liegenden Feld einen Ziegel abgelegt.

ziegelAufheben():

vorher: Das Roboter-Objekt befindet sich irgendwo in der Welt.

nachher: Das Roboter-Objekt befindet sich im selben Feld. Wenn das Roboter-Objekt nicht vor einer Wand steht, dann hat es in dem vor ihm liegenden Feld einen Ziegel wegenommen, sofern hier Ziegel gelegen haben.

vorZiegel(): bool

vorher: Das Roboter-Objekt befindet sich irgendwo in der Welt.

nachher: Das Roboter-Objekt befindet sich im selben Feld der Welt. Die Methode liefert den Wert True bzw. False zurück, sofern sich im Feld unmittelbar vor dem Roboter-Objekt Ziegel befinden bzw. nicht befinden.

nichtVorZiegel(): bool

analog

Implementierung der Klasse Roboter

Die folgende Klassendeklaration in Python implementiert die Klasse Roboter des gezeigten Klassendiagramms.

class Roboter(object):   

    # ... wie bisher ...

    def ziegelHinlegen(self):
        if self.r == 'O' and self.x < self.w.getFelderX()-1:
            self.w.incZiegel(self.x+1, self.y)
        elif self.r == 'S' and self.y < self.w.getFelderY()-1:
            self.w.incZiegel(self.x, self.y+1)
        elif self.r == 'W' and self.x > 0:
            self.w.incZiegel(self.x-1, self.y)
        elif self.r == 'N' and self.y > 0:
            self.w.incZiegel(self.x, self.y-1)

    def ziegelAufheben(self):
        if self.r == 'O' and self.x < self.w.getFelderX()-1:
            self.w.decZiegel(self.x+1, self.y)
        elif self.r == 'S' and self.y < self.w.getFelderY()-1:
            self.w.decZiegel(self.x, self.y+1)
        elif self.r == 'W' and self.x > 0:
            self.w.decZiegel(self.x-1, self.y)
        elif self.r == 'N' and self.y > 0:
            self.w.decZiegel(self.x, self.y-1)

    # ... def vorZiegel(self): ...

    # ... def nichtVorZiegel(self): ...

Aufgabe 4

(a) Analysiere die Implementierung der Methode ziegelHinlegen. Erkläre, wie das Ziegelhinlegen hier softwaretechnisch gelöst wird.

(b) Teste die Klassendeklaration durch ein Python-Protokoll wie das folgende.

>>> welt = Welt(4, 4)
>>> rob = Roboter()
>>> rob.setWelt(welt)
>>> welt.getAlleZiegel()
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> rob.schritt()
>>> rob.schritt()
>>> rob.ziegelHinlegen()
>>> welt.getAlleZiegel()
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 0]]

(c) Entwickle ein Testprogramm, bei dem der Roboter eine Ziegelreihe an den Rand der Welt baut.

(d) Ergänze eine Implementierung der Methoden vorZiegel und nichtVorZiegel.

X

Fehler melden

X

Suche