Kann man so etwas wie Karol auch in Python programmieren? Bestimmt! Wenn man genug Zeit dazu hat…
Aber man kann ja zumindest mal damit anfangen und dieses Projekt nutzen, um Python zu lernen! Wer möchte, darf sich gerne beteiligen!
Es gibt eine Klasse „Welt“ und eine Klasse „Roboter“. Der Roboter kann sich in der Welt bewegen und Ziegel hinlegen. Die Anzahl der Ziegel kann auch direkt festgelegt werden.
class Welt(object): # Konstruktor def __init__(self,laenge=10,breite=10,hoehe=10): self.Laenge = laenge self.Breite = breite self.Hoehe = hoehe # eine zweidimensionale Liste anlegen und mit Nullen füllen self.Ziegel = [] for j in range(laenge): reihe = [] for i in range(breite): reihe.append(0) self.Ziegel.append(reihe) # Anzahl der Ziegel an einer bestimmten Position direkt eingeben def setZiegel(self,x,y,anzahl): self.Ziegel[x][y] = anzahl # Anzahl der Ziegel an einer bestimmten Position um 1 erhöhen def hinlegenZiegel(self,x,y): self.Ziegel[x][y] += 1 class Roboter(object): # Konstruktor def __init__(self,welt,posx=0,posy=0,richtung=1): self.Welt = welt # Richtungen: +1 self.Posx = posx # -2 +2 self.Posy = posy # -1 self.Richtung = richtung # ein Feld nach vorne gehen def schritt(self): self.Posx += self.Richtung / 2 self.Posy += self.Richtung % 2 # nach rechts drehen def rechtsDrehen(self): if self.Richtung == 1: self.Richtung = 2 elif self.Richtung == 2: self.Richtung = -1 elif self.Richtung == -1: self.Richtung = -2 else: self.Richtung = 1 # nach links drehen def linksDrehen(self): self.rechtsDrehen() self.Richtung *= -1 # einen Ziegel vor den Roboter legen def hinlegen(self): ziegelposx = self.Posx + self.Richtung / 2 ziegelposy = self.Posy + self.Richtung % 2 self.Welt.hinlegenZiegel(ziegelposx,ziegelposy)
Die Ausgabe erfolgt zunächst über die Kommandozeile mit diesen Prozeduren:
from RobbiDaten import * def weltausgeben(welt): print "Länge: ",welt.Laenge print "Breite:",welt.Breite print "Höhe: ",welt.Hoehe for j in range(welt.Laenge-1,-1,-1): for i in range(welt.Breite): print welt.Ziegel[i][j], print def roboterausgeben(roboter): print "Koordinaten:",roboter.Posx, roboter.Posy print "Richtung: ",roboter.Richtung def allesausgeben(welt,roboter): print "Länge: ",welt.Laenge print "Breite:",welt.Breite print "Höhe: ",welt.Hoehe for j in range(welt.Laenge-1,-1,-1): for i in range(welt.Breite): if roboter.Posx == i and roboter.Posy == j: print "X", else: print welt.Ziegel[i][j], print
Testen von der Python-Shell aus:
>>> w=Welt() >>> r=Roboter(w) >>> r.hinlegen();r.schritt() >>> r.hinlegen();r.schritt() >>> r.hinlegen();r.schritt() >>> r.rechtsDrehen() >>> r.hinlegen();r.schritt() >>> r.hinlegen();r.schritt() >>> r.schritt() >>> allesausgeben(w,r) Länge: 10 Breite: 10 Höhe: 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 X 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Es fehlt eine Überprüfung, ob der Roboter am Rand der Welt angelangt ist sowie die Roboter-Methode „aufheben“.
Die oben fehlende Überprüfung ist eingefügt: Der Roboter kennt nun seine Welt und kann vor jeder Aktion überprüfen, ob er sie durchführen kann. Die Koordinaten des Roboters wurden geändert und die Richtung des Roboters ist nun ein 2-dimensionaler Vektor.
Eine große Änderung besteht in der Bedienung durch eine grafische Benutzeroberfläche. Diese wurde mit dem Modul Tkinter geschrieben.
Darüber hinaus lässt sich der Roboter mit folgenden Befehlen programmieren:
Das Robbie-Programm kann gespeichert und wieder geladen werden.
So sieht das Programm bisher aus:
class Welt(object): # Konstruktor def __init__(self,laenge=10,breite=10,hoehe=10): self.Laenge = laenge self.Breite = breite self.Hoehe = hoehe # eine zweidimensionale Liste anlegen und mit Nullen füllen self.Ziegel = [[0 for i in range(breite)] for j in range(laenge)] # Anzahl der Ziegel an einer bestimmten Position direkt eingeben def setZiegel(self,x,y,anzahl): self.Ziegel[x][y] = anzahl # Anzahl der Ziegel an einer bestimmten Position um 1 erhöhen def hinlegenZiegel(self,x,y): if self.Ziegel[x][y] < self.Hoehe: self.Ziegel[x][y] += 1 # Anzahl der Ziegel an einer bestimmten Position um 1 erniedrigen def aufhebenZiegel(self,x,y): if self.Ziegel[x][y] > 0: self.Ziegel[x][y] -= 1 class Roboter(object): # Konstruktor def __init__(self,welt,posx=0,posy=0,richtung=[1,0]): self.Welt = welt self.Posx = posx self.Posy = posy self.Richtung = richtung # ein Feld nach vorne gehen, falls möglich def schritt(self): self.Posx += self.Richtung[0] if self.Posx < 0: self.Posx = 0 if self.Posx > self.Welt.Laenge - 1: self.Posx = self.Welt.Laenge - 1 self.Posy += self.Richtung[1] if self.Posy < 0: self.Posy = 0 if self.Posy > self.Welt.Breite - 1: self.Posy = self.Welt.Breite - 1 # nach rechts drehen def rechtsDrehen(self): if self.Richtung == [1,0]: self.Richtung = [0,1] elif self.Richtung == [0,1]: self.Richtung = [-1,0] elif self.Richtung == [-1,0]: self.Richtung = [0,-1] else: self.Richtung = [1,0] # nach links drehen def linksDrehen(self): if self.Richtung == [1,0]: self.Richtung = [0,-1] elif self.Richtung == [0,1]: self.Richtung = [1,0] elif self.Richtung == [-1,0]: self.Richtung = [0,1] else: self.Richtung = [-1,0] # einen Ziegel vor den Roboter legen falls möglich def hinlegen(self): ziegelposx = self.Posx + self.Richtung[0] ziegelposy = self.Posy + self.Richtung[1] if 0 <= ziegelposx < self.Welt.Laenge and 0<= ziegelposy < self.Welt.Breite: self.Welt.hinlegenZiegel(ziegelposx,ziegelposy) return True else: return False # einen Ziegel vor dem Roboter aufheben falls möglich def aufheben(self): ziegelposx = self.Posx + self.Richtung[0] ziegelposy = self.Posy + self.Richtung[1] if 0 <= ziegelposx < self.Welt.Laenge and 0<= ziegelposy < self.Welt.Breite: self.Welt.aufhebenZiegel(ziegelposx,ziegelposy) return True else: return False
Dies war der Daten-Teil. Jetzt folgt die GUI. Was noch überhaupt nicht schön ist: der Robbi-Interpreter steht noch in der GUI, wo er eigentlich nicht hingehört.
from RobbiDaten import * #from RobbiShell import * #from RobbiInter import * #from tkFileDialog import askopenfilename from Tkinter import * import tkFileDialog #from tkMessageBox import * #from tkColorChooser import askcolor class GUI: def __init__(self,roboter): # Daten-Objekte self.Roboter = roboter self.Ziegel = [[0 for i in range(10)] for j in range(10)] # GUI-Objekte definieren self.fenster = Tk() self.fenster.title("Robbi Roboter") self.frame1 = Frame(master=self.fenster) self.frame2 = Frame(master=self.fenster) self.welt2d = Canvas(master=self.frame1, width=511, height=511, bg="white") self.eingabe = Text(master=self.frame1, width=40, height=36, bg = "#f0f0f0") self.buttonQuit = Button(master=self.frame2, text="Quit", command=self.fenster.quit) self.buttonNeueWelt = Button(master=self.frame2, text="Neue Welt", command=self.welt2dzeichnen) self.buttonSchritt = Button(master=self.frame2, text="Schritt", command=self.schritt) self.buttonLinks = Button(master=self.frame2, text="Linksdrehen", command=self.linksdrehen) self.buttonRechts = Button(master=self.frame2, text="Rechtsdrehen", command=self.rechtsdrehen) self.buttonHinlegen = Button(master=self.frame2, text="Hinlegen", command=self.hinlegen) self.buttonAufheben = Button(master=self.frame2, text="Aufheben", command=self.aufheben) self.buttonAusfuehren = Button(master=self.frame1, text ="Ausführen", command=self.ausfuehrenclick) self.buttonLaden = Button(master=self.frame1, text ="Laden", command=self.laden) self.buttonSpeichern = Button(master=self.frame1, text ="Speichern", command=self.speichern) # GUI-Objekte anordnen self.frame1.pack() self.frame2.pack() self.welt2d.pack(expand=YES, fill=BOTH, side=LEFT) self.eingabe.pack(side=TOP) self.buttonNeueWelt.pack(side=RIGHT) self.buttonQuit.pack(side=LEFT) self.buttonSchritt.pack(side=LEFT) self.buttonLinks.pack(side=LEFT) self.buttonRechts.pack(side=LEFT) self.buttonHinlegen.pack(side=LEFT) self.buttonAufheben.pack(side=LEFT) self.buttonAusfuehren.pack(side=LEFT) self.buttonLaden.pack(side=LEFT) self.buttonSpeichern.pack(side=LEFT) # Gitter zeichnen def welt2dzeichnen(self): self.welt2d.create_rectangle(10,10,510,510) for i in range(10,510,50): self.welt2d.create_line(10,i,510,i) for i in range(10,510,50): self.welt2d.create_line(i,10,i,510) # Alle Ziegel zeichnen (Zahl oder leerer String) def ziegelzeichnen(self): for j in range(10): for i in range(10): te=str(self.Roboter.Welt.Ziegel[i][j]) if te =="0":te="" self.Ziegel[i][j]=self.welt2d.create_text(i*50+35,j*50+35,text=te) # Roboter (Dreieck) zeichnen) def roboterzeichnen(self): robx = 50*self.Roboter.Posx + 35 roby = 50*self.Roboter.Posy + 35 if self.Roboter.Richtung == [0,1]: self.dreieck=self.welt2d.create_polygon(robx-25,roby-25,robx+25,roby-25,robx,roby+25) elif self.Roboter.Richtung == [0,-1]: self.dreieck=self.welt2d.create_polygon(robx-25,roby+25,robx+25,roby+25,robx,roby-25) elif self.Roboter.Richtung == [1,0]: self.dreieck=self.welt2d.create_polygon(robx-25,roby-25,robx-25,roby+25,robx+25,roby) elif self.Roboter.Richtung == [-1,0]: self.dreieck=self.welt2d.create_polygon(robx+25,roby+25,robx+25,roby-25,robx-25,roby) # Roboter bewegen und neu zeichnen def schritt(self): self.welt2d.delete(self.dreieck) self.Roboter.schritt() self.roboterzeichnen() # Roboter nach links drehen und neu zeichnen def linksdrehen(self): self.welt2d.delete(self.dreieck) self.Roboter.linksDrehen() self.roboterzeichnen() # Roboter nach links drehen und neu zeichnen def rechtsdrehen(self): self.welt2d.delete(self.dreieck) self.Roboter.rechtsDrehen() self.roboterzeichnen() # Ziegel hinlegen und veränderten Ziegel neu zeichnen def hinlegen(self): if self.Roboter.hinlegen(): neuziegelx = self.Roboter.Posx + self.Roboter.Richtung[0] neuziegely = self.Roboter.Posy + self.Roboter.Richtung[1] te=str(self.Roboter.Welt.Ziegel[neuziegelx][neuziegely]) if te =="0":te="" self.welt2d.itemconfig(self.Ziegel[neuziegelx][neuziegely],text=te) # Ziegel aufheben und veränderten Ziegel neu zeichnen def aufheben(self): if self.Roboter.aufheben(): neuziegelx = self.Roboter.Posx + self.Roboter.Richtung[0] neuziegely = self.Roboter.Posy + self.Roboter.Richtung[1] te=str(self.Roboter.Welt.Ziegel[neuziegelx][neuziegely]) if te =="0":te="" self.welt2d.itemconfig(self.Ziegel[neuziegelx][neuziegely],text=te) def ausfuehrenclick(self): eingabe = self.eingabe.get("1.0",END) programm = eingabe.split() for i in range(len(programm)): if programm[i] == "wiederhole": programm[i] = "w" elif programm[i] == "*wiederhole": programm[i] = "*w" elif programm[i] == "schritt": programm[i] = "s" elif programm[i] == "rechtsdrehen": programm[i] = "r" elif programm[i] == "linksdrehen": programm[i] = "l" elif programm[i] == "aufheben": programm[i] = "a" elif programm[i] == "hinlegen": programm[i] = "h" self.ausfuehren(programm) def ausfuehren(self,liste): print liste merke = [0,0,0,0] schleifenzaehler = [0,0,0,0] schleife = -1 i = 0 while i < len(liste): if liste[i] == "w": schleife += 1 i += 1 schleifenzaehler[schleife] = int(liste[i]) merke[schleife]=(i+1) elif liste[i] == "*w": if schleifenzaehler[schleife] > 1: schleifenzaehler[schleife] -= 1 i = merke[schleife] - 1 else: schleife -=1 elif liste[i] == "s": self.schritt() elif liste[i] == "r": self.rechtsdrehen() elif liste[i] == "l": self.linksdrehen() elif liste[i] == "h": self.hinlegen() elif liste[i] == "a": self.aufheben() i += 1 def laden(self): filename = tkFileDialog.askopenfilename() programmdatei = open(filename,"r") self.eingabe.delete("1.0",END) for zeile in programmdatei: self.eingabe.insert(END,zeile) programmdatei.close() def speichern(self): filename = tkFileDialog.asksaveasfilename() programmdatei = open(filename,"w") programmdatei.write(self.eingabe.get("1.0",END)) programmdatei.close() w=Welt() # Welt der Größe 10x10 r=Roboter(w) # Roboter in dieser Welt gui = GUI(r) # Grafische Oberfläche initialisieren gui.roboterzeichnen() # Den Roboter einzeichnen gui.ziegelzeichnen() # Die Ziegel einzeichnen gui.welt2dzeichnen() # Das Gitter zeichnen gui.fenster.mainloop() # Auf Buttonklick warten