Python :: Aufgabe #173 :: Lösung #1

2 Lösungen Lösungen öffentlich
#173

Simulation eines Staubsaug-Roboters

Fortgeschrittener - Python von hollst - 22.11.2017 um 22:14 Uhr
Ich bin im Haushalt ein ziemlich fauler Hund. Meine Frau weiß das und so hielt sie mich deshalb kürzlich an, wenigstens hin und wieder das Wohnzimmer zu saugen. Nun gut, mir kam die geniale Idee, dafür einen Staubsaug-Roboter zu kaufen. Gesagt, getan. Meine Frau runzelte zwar, aber letzt­lich war ihr das egal, wichtig war ja nur, dass sie etwas von der Hausarbeit entlastet wird.

Das Gerät überraschte mich von Anfang an. Es fährt immer geradeaus bis es irgendwo anstößt. Dann dreht es sich auf der Stelle in eine zufällige andere Richtung und fährt wieder weiter gerade­aus bis zum nächsten Hindernis. Es teilt mir auch sprachlich z. B. mit, wenn der Akku fast leer ist, es jetzt eine Pause machen wird und zur Ladestation fährt. Andermal sagte es, dass sein Haupt­speicher (sprich Staubsammeltüte) voll ist und ich ihn leeren solle. Das übernimmt natürlich meine Frau, denn bei einem solchen mechanischen Eingriff hat sie kein Vertrauen zu mir.

Der Gipfel war aber, als der Roboter mir bei der gestrigen Arbeit mitteilte, dass er fertig sei und im Zimmer der gesamten Fußboden gereinigt ist.

Das ist doch unmöglich, woher will er das wissen. Und "der gesamte Fußboden" geht schon gar­nicht, denn in die Ecken kommt er ja sowieso nicht. Ich war immer der Meinung, dass er erst fertig zu sein hat, wenn er abgeschaltet wird. Aber Nein sagte meine Frau, das macht er immer so, ich soll­te ihn, wie vereinbart war, nur hin und wieder selbst einsetzen und beobachten (beobachtet wird das Gerät bisweil immer nur von unserer Hauskatze).

Ich wurde neugierig und las entgegen meinen Gewöhnheiten auch die Betriebsanleitung. In der Tat stand darin, dass der Roboter anhält, wenn er mehr als 95 % der Fußbodenfläche gesaugt hat.

Ich dachte, nun gut, 95 % ist okay, aber, wie will er das wissen. Da muss schon eine ziemlich clevere Software im Roboter stecken. Prinzipiell kann man zwar die besaugte Fläche bei Kenntnis der Fahr­geschwindigkeit, der Anstoßpunkte und der neuen Fahrtrichtungen berechnen. Die Flächenseg­mente, die durch das Zufallsprinzip bereits besaugt worden ware, sind entsprechend zu berücksich­tigen (abzuziehen). Alles mathematisch recht kom­pliziert.

Der Gedanke, es statt einer mathematischen Berechnung durch eine informathematische Simulation abzuschätzen, legt auf der Hand. Dies soll daher die Aufgabenstellung sein.

Ausgehend von einer beliebigen Startposition auf einer leeren, rechteckigen Fläche F = LX x LY, mit LX und LY als Seitenlängen des Rechtecks, einer vorgegebenen Fahrgeschwindigkeit V und einer zufälli­gen Richtungsände­rung bei Zusammenstoß mit einem Hindernis (Wand) ist der Anteil besaugter Fläche bzgl. der Gesamtfußbodenfläche wie folgt anzuschätzen:

Auf einem zu Beginn 100 % mit "Staubpixeln" belegten Rechteck wird ein Staubsaug-Roboter mit dem Radius R gesetzt und fährt per Zufall gewählter Richtung staubsaugend geradeaus (Geschwin­digkeit V). Bei Berührung einer Wand ändert er zufällig seine Fahrtrichtung. Während der Fahrt werden alle überfahrenen "Staubpixeln" durch "Reinpixel" ersetzt (siehe Abb. 1). Die Fahrt endet, wenn P_okay = 95 % der Rechtecksfläche mit "Reinpixeln" belegt ist.
#1
vote_ok
von 0 (0 Punkte) - 28.11.2017 um 19:21 Uhr
Quellcode ausblenden Python-Code

#----------------------------------------------------
# Dateiname:  staubsauger.py
# Die Fläche wird durch die Pixel eines Rechteckes dargestellt
# 
# 
# bei 95% Sauberkeit wird die Meldung fertig ausgegeben sowie die insgesamt benötigte Zeit
# 
# Python 3.6.1
# Nr. 173 trainyourprogrammer.de
# Mot Sonne 28.11.2017
# Vielen Dank an User hollst!
#----------------------------------------------------

import pygame
from random import choice,randint
from time import time

BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
GREEN = ( 0, 255, 0)
RED = ( 255, 0, 0)
YELLOW=(197,201,107)
DGREEN=(33,82,24)
HGREEN=(71,237,38)
BROWN=(102,9,11)
BLUE=(67,177,224)
colors=[GREEN,RED,YELLOW,DGREEN,HGREEN,BROWN,BLUE]
richtung=["N","NE","NW","O","W","S","SO","SW"]
#es wurden die Himmelsrichtungen gewählt
#zunächst einige Klassendefinitionen-eigentlich Modul Klassen
#alle Klassen erben die Methoden der Sprite Objekte

class Staub(pygame.sprite.Sprite):
#einzelne Pixel-Punkte mit zufälliger Farbe
    def __init__(self, x, y):
        super().__init__()
        color=choice(colors)
        self.image = pygame.Surface([1, 1])
        self.image.fill(WHITE)
        self.image.set_colorkey(WHITE)
        pygame.draw.rect(self.image, color, [0, 0, 1, 1])
        self.rect = self.image.get_rect()
        self.rect.x=x
        self.rect.y=y

class Sauger(pygame.sprite.Sprite):
#Der Sauger ist steuerbar und kann in einen Demo-modus geschalten werden(update),Ausgang ist hierbei rechts und unten der Fläche
    def __init__(self,radius,v):
        super().__init__()
        self.dir=0
        self.v=v
        self.image = pygame.Surface([radius*2, radius*2])
        self.image.fill(WHITE)
        self.image.set_colorkey(WHITE)
        pygame.draw.circle(self.image, choice(colors), [radius, radius], radius)
        self.rect = self.image.get_rect()
        self.radius=radius
    def moveRight(self, pixels):
        self.rect.x += pixels
    
    def moveLeft(self, pixels):
        self.rect.x -= pixels
    def moveUp(self, pixels):
        self.rect.y -= pixels
    
    def moveDown(self, pixels):
        self.rect.y += pixels
    def spin(self,a,b):
        self.dir=choice(richtung)
        if self.rect.x<-1:
            self.rect.x=0
        if self.rect.x>a+1:
            self.rect.x=a-1
        if self.rect.y<-1:
            self.rect.y=0
        if self.rect.y>b+1:
            self.rect.y=b-1
            
    def update(self):
        #Ausgabe der Koordinaten des Saugers
        #v beschreibt die Anzahl der überfahrenen Pixel
        #print("x:"+str(self.rect.x)+" y:"+str(self.rect.y))
        if not self.dir:
            self.dir=choice(richtung)
        if self.dir=="N":
            self.moveUp(self.v)
        elif self.dir=="S":
            self.moveDown(self.v)
        elif self.dir=="O":
            self.moveRight(self.v)
        elif self.dir=="W":
            self.moveLeft(self.v)
        elif self.dir=="NE":
            self.moveRight(self.v)
            self.moveUp(self.v)
        elif self.dir=="NW":
            self.moveLeft(self.v)
            self.moveUp(self.v)
        elif self.dir=="SE":
            self.moveRight(self.v)
            self.moveDown(self.v)
        elif self.dir=="SW":
            self.moveLeft(self.v)
            self.moveDown(self.v)

class Wand(pygame.sprite.Sprite):

    #die vier Wände als Abgrenzung des Raumes
    def __init__(self,a,b,X,Y):
        
        super().__init__()
        self.image = pygame.Surface((a, b))
        self.image.fill(WHITE)
        self.image.set_colorkey(WHITE)
        pygame.draw.line(self.image, BLACK, X,Y)
        self.rect = self.image.get_rect()
        self.rect.x,self.rect.y=X
class Tisch(pygame.sprite.Sprite):
#als Beispiel eines kleinen Objektes im Raum,nicht maßstabsgerecht
    def __init__(self,a,b,x,y):
        
        super().__init__()
        self.image = pygame.Surface((a, b))
        self.image.fill(WHITE)
        self.image.set_colorkey(WHITE)
        pygame.draw.rect(self.image, BLACK, [0, 0, a, b])
        self.rect = self.image.get_rect()
        self.rect.x,self.rect.y=x,y
    def update(self,v):
        self.rect.x+=v
        self.rect.y+=v
#Jetzt das eigentliche "Spiel"
pygame.init()
#Hier  Eingabe der Größen
v=1#Geschwindigkeit des Saugers in Pixel/Zeit
a=150#Breite
b=150#Höhe
r=15#Radius des Saugers
size = (a, b)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Staubsauger")
#Liste aller Staubkörner
sprite_list_staub = pygame.sprite.Group()

for i in range(3,a-2):
    for j in range(3,b-2):
        sprite_list_staub.add(Staub(i,j))

#Gesamtanzahl an Körner für sauber 95%
anz=len(sprite_list_staub)*0.05

#Staubsauger-Objekt mit zufälligen Anfangskoordinaten

player=Sauger(r,v)
player.rect.x=randint(3*r,a-r*3)
player.rect.y=randint(3*r,b-r*3)
#Liste mit Staubsauger
sprite_list = pygame.sprite.Group()
sprite_list.add(player)
#Liste mit Wänden, jede Wand ist eine Linie
sprite_list_wall=pygame.sprite.Group()
for m,n,X,Y in [(a,1,(0,0),(a,0)),(1,b,(0,0),(0,b)),(a,1,(0,b),(a,b)),(1,b,(a,0),(a,b))]:
    sprite_list_wall.add(Wand(m,n,X,Y))
#Optional können weitere Objekte in die Objekt-Liste gepackt werden:
sprite_list_obj=pygame.sprite.Group()
sprite_list_obj.add(Tisch(10,10,round(3*a/4),round(3*b/4)))
carryOn = True
# Uhr für die Frame-Begrenzung
clock = pygame.time.Clock()
#zu Beginn kann gefahren werden
demo=False
beginn=time()
while carryOn:
    # --- loop
    for event in pygame.event.get(): # Man kann den Staubsauger steuern
        if event.type == pygame.QUIT: # Beenden durch User
            carryOn = False # Ende
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        player.moveLeft(5)
    if keys[pygame.K_RIGHT]:
        player.moveRight(5)
    if keys[pygame.K_UP]:
        player.moveUp(5)
    if keys[pygame.K_DOWN]:
        player.moveDown(5)
    #Tab startet die Demo für den Staubsauger 
    if keys[pygame.K_TAB]:
        demo=True
        beginn=time()
    if demo:
        sprite_list.update()
    
    #Kollision des Staubs mit dem runden Staubsauger zerstört die Pixel
    collision_list_staub = pygame.sprite.spritecollide(player,sprite_list_staub,True,collided = pygame.sprite.collide_circle)
    if len(sprite_list_staub)<anz:
        print("Staub beseitigt")
        ende=time()
        print("Benötigte Zeit: "+str(ende-beginn)+" Sekunden")
        carryOn=False
#wenn weniger als 5% an Staub-Pixeln übrig ist der Sauger fertig
    #Bei Berührung einer Wand Richtungswechsel:
    if pygame.sprite.spritecollideany(player,sprite_list_wall,False):
        player.spin(a,b)
        #print("!")
    #Bei Berührung eines Objektes Richtungswechsel und Bewegung des Objektes
    collision_list_obj = pygame.sprite.spritecollide(player,sprite_list_obj,False,collided = pygame.sprite.collide_circle)
    for obj in collision_list_obj:
        obj.update(v)
    
    screen.fill(WHITE)
    sprite_list_staub.draw(screen)
    sprite_list.draw(screen)
    sprite_list_wall.draw(screen)
    sprite_list_obj.draw(screen)
    pygame.display.flip()
    #Framerate
    clock.tick(30)

pygame.quit()


Kommentare:

Für diese Lösung gibt es noch keinen Kommentar

Bitte melden Sie sich an um eine Kommentar zu schreiben.
Kommentar schreiben