Mensch-Ärgere-Dich-Nicht MP
MatFertigMP_13_33.py — Python Source, 24 KB (25572 bytes)
Dateiinhalt
from visual import * from threading import Thread PORT = 51347 # Colormap: rot = 0, blau = 1, gruen = 2, gelb = 3 #Wichtigste Klasse, initalisiert Graphik und macht Bewegungen class Spielfeld(Thread): def __init__(self): Thread.__init__(self) self.curPlayer = 0 self.result = 0 self.boxMain = box(pos=(0,-0.25,0),length=11,height=0.5, width=11) #Spielfeld self.goal = [0,0,0,0] #Spielstand self.colorStartField = [0,10,20,30] #Startfeld fuer Figuren einer Farbe die aus dem Haus kommen self.colorEndField = [39,9,19,29] #Endfeld fuer Figuren einer Farbe die aus dem Haus kommen # Array der Spieler: self.p[x][y] mit x = color und y = Nummer des Spielers eines Teams self.p = [[Player((1,0,0)),Player((1,0,0)),Player((1,0,0)),Player((1,0,0))],[Player((0,0,1)),Player((0,0,1)),Player((0,0,1)),Player((0,0,1))],[Player((0,1,0)),Player((0,1,0)),Player((0,1,0)),Player((0,1,0))],[Player((1,1,0)),Player((1,1,0)),Player((1,1,0)),Player((1,1,0))]] # Setzt die Startposition der Figuren self.p[0][0].pos = (-5,0,-4) self.p[0][1].pos = (-5,0,-5) self.p[0][2].pos = (-4,0,-4) self.p[0][3].pos = (-4,0,-5) self.p[1][0].pos = (5,0,-4) self.p[1][1].pos = (5,0,-5) self.p[1][2].pos = (4,0,-4) self.p[1][3].pos = (4,0,-5) self.p[2][0].pos = (5,0,4) self.p[2][1].pos = (5,0,5) self.p[2][2].pos = (4,0,4) self.p[2][3].pos = (4,0,5) self.p[3][0].pos = (-5,0,4) self.p[3][1].pos = (-5,0,5) self.p[3][2].pos = (-4,0,4) self.p[3][3].pos = (-4,0,5) #Kopiert die Startpositionen in posCopy, damit die Ursprungsposition einer Figur gespeichert ist self.p[0][0].posCopy = (-5,0,-4) self.p[0][1].posCopy = (-5,0,-5) self.p[0][2].posCopy = (-4,0,-4) self.p[0][3].posCopy = (-4,0,-5) self.p[1][0].posCopy = (5,0,-4) self.p[1][1].posCopy = (5,0,-5) self.p[1][2].posCopy = (4,0,-4) self.p[1][3].posCopy = (4,0,-5) self.p[2][0].posCopy = (5,0,4) self.p[2][1].posCopy = (5,0,5) self.p[2][2].posCopy = (4,0,4) self.p[2][3].posCopy = (4,0,5) self.p[3][0].posCopy = (-5,0,4) self.p[3][1].posCopy = (-5,0,5) self.p[3][2].posCopy = (-4,0,4) self.p[3][3].posCopy = (-4,0,5) #Array der "Haus"-Felder: self.pRoot[x][y] mit x = color und y = Nummer des Hausfeldes eines Teams self.pRoot = [[PosFeld((1,0,0)),PosFeld((1,0,0)),PosFeld((1,0,0)),PosFeld((1,0,0))],None,None,None] self.pRoot[1] = [PosFeld((0,0,1)),PosFeld((0,0,1)),PosFeld((0,0,1)),PosFeld((0,0,1))] self.pRoot[2] = [PosFeld((0,1,0)),PosFeld((0,1,0)),PosFeld((0,1,0)),PosFeld((0,1,0))] self.pRoot[3] = [PosFeld((1,1,0)),PosFeld((1,1,0)),PosFeld((1,1,0)),PosFeld((1,1,0))] # Setzt die Position der "Haus"-Felder self.pRoot[0][0].pos = (-5,0,-4) self.pRoot[0][1].pos = (-5,0,-5) self.pRoot[0][2].pos = (-4,0,-4) self.pRoot[0][3].pos = (-4,0,-5) self.pRoot[1][0].pos = (5,0,-4) self.pRoot[1][1].pos = (5,0,-5) self.pRoot[1][2].pos = (4,0,-4) self.pRoot[1][3].pos = (4,0,-5) self.pRoot[2][0].pos = (5,0,4) self.pRoot[2][1].pos = (5,0,5) self.pRoot[2][2].pos = (4,0,4) self.pRoot[2][3].pos = (4,0,5) self.pRoot[3][0].pos = (-5,0,4) self.pRoot[3][1].pos = (-5,0,5) self.pRoot[3][2].pos = (-4,0,4) self.pRoot[3][3].pos = (-4,0,5) #Array der "End"-Felder: self.pEnd[x][y] mit x = color und y = Nummer dse Endfeldes eines Teams self.pEnd = [[PosFeld((1,0,0)),PosFeld((1,0,0)),PosFeld((1,0,0)),PosFeld((1,0,0))],[PosFeld((0,0,1)),PosFeld((0,0,1)),PosFeld((0,0,1)),PosFeld((0,0,1))],[PosFeld((0,1,0)),PosFeld((0,1,0)),PosFeld((0,1,0)),PosFeld((0,1,0))],[PosFeld((1,1,0)),PosFeld((1,1,0)),PosFeld((1,1,0)),PosFeld((1,1,0))]] # Setzt die Position der "End"-Felder self.pEnd[0][0].pos = (-4,0,0) self.pEnd[0][1].pos = (-3,0,0) self.pEnd[0][2].pos = (-2,0,0) self.pEnd[0][3].pos = (-1,0,0) self.pEnd[1][0].pos = (0,0,-4) self.pEnd[1][1].pos = (0,0,-3) self.pEnd[1][2].pos = (0,0,-2) self.pEnd[1][3].pos = (0,0,-1) self.pEnd[2][0].pos = (4,0,0) self.pEnd[2][1].pos = (3,0,0) self.pEnd[2][2].pos = (2,0,0) self.pEnd[2][3].pos = (1,0,0) self.pEnd[3][0].pos = (0,0,4) self.pEnd[3][1].pos = (0,0,3) self.pEnd[3][2].pos = (0,0,2) self.pEnd[3][3].pos = (0,0,1) #Array der "neutralen"-Felder: self.pEnd[x] mit x = Nummer des Feldes startend beim roten Startfeld self.fieldNeutral = [] for x in range(40): if x == 0: self.fieldNeutral.append(PosFeld((1,0,0))) #rotes Startfeld elif x == 10: self.fieldNeutral.append(PosFeld((0,0,1))) #blaues Startfeld elif x == 20: self.fieldNeutral.append(PosFeld((0,1,0))) #gruenes Startfeld elif x == 30: self.fieldNeutral.append(PosFeld((1,1,0))) #gelbes Startfeld else: self.fieldNeutral.append(PosFeld()) #schwarzes Feld # Setzt die Position der "neutralen"-Felder self.fieldNeutral[0].pos= (-5,0,-1) self.fieldNeutral[1].pos= (-4,0,-1) self.fieldNeutral[2].pos= (-3,0,-1) self.fieldNeutral[3].pos= (-2,0,-1) self.fieldNeutral[4].pos= (-1,0,-1) self.fieldNeutral[5].pos= (-1,0,-2) self.fieldNeutral[6].pos= (-1,0,-3) self.fieldNeutral[7].pos= (-1,0,-4) self.fieldNeutral[8].pos= (-1,0,-5) self.fieldNeutral[9].pos= (0,0,-5) self.fieldNeutral[10].pos= (1,0,-5) self.fieldNeutral[11].pos= (1,0,-4) self.fieldNeutral[12].pos= (1,0,-3) self.fieldNeutral[13].pos= (1,0,-2) self.fieldNeutral[14].pos= (1,0,-1) self.fieldNeutral[15].pos= (2,0,-1) self.fieldNeutral[16].pos= (3,0,-1) self.fieldNeutral[17].pos= (4,0,-1) self.fieldNeutral[18].pos= (5,0,-1) self.fieldNeutral[19].pos= (5,0,0) self.fieldNeutral[20].pos= (5,0,1) self.fieldNeutral[21].pos= (4,0,1) self.fieldNeutral[22].pos= (3,0,1) self.fieldNeutral[23].pos= (2,0,1) self.fieldNeutral[24].pos= (1,0,1) self.fieldNeutral[25].pos= (1,0,2) self.fieldNeutral[26].pos= (1,0,3) self.fieldNeutral[27].pos= (1,0,4) self.fieldNeutral[28].pos= (1,0,5) self.fieldNeutral[29].pos= (0,0,5) self.fieldNeutral[30].pos= (-1,0,5) self.fieldNeutral[31].pos= (-1,0,4) self.fieldNeutral[32].pos= (-1,0,3) self.fieldNeutral[33].pos= (-1,0,2) self.fieldNeutral[34].pos= (-1,0,1) self.fieldNeutral[35].pos= (-2,0,1) self.fieldNeutral[36].pos= (-3,0,1) self.fieldNeutral[37].pos= (-4,0,1) self.fieldNeutral[38].pos= (-5,0,1) self.fieldNeutral[39].pos= (-5,0,0) #Methode, die berechnet ob playerFrame um die Anzahl field bewegt werden kann (return bool) def calcPossible(self,playerFrame,field): newField = playerFrame.fieldPos + field #neue Position der Figur #wenn im Endbereich if playerFrame.isEndZone: #wenn neue Position innerhalb des Endbereich if newField < 4: #wenn keine eigene Figur blockiert if self.fieldNeutral[newField].player == None or not self.fieldNeutral[newField].player.color == playerFrame.color: return True return False #wenn im Haus elif playerFrame.fieldPos == -1: #wenn keine eigene Figur blockiert if (self.fieldNeutral[newField].player == None or not self.fieldNeutral[newField].player.color == playerFrame.color) and field == 6: return True else: return False #wenn kommt in den Endbereich elif newField > self.colorEndField[playerFrame.color]and (playerFrame.fieldPos < self.colorStartField[playerFrame.color] or playerFrame.color == 0): if newField < self.colorEndField[playerFrame.color] + 5: newField -= (self.colorEndField[playerFrame.color] +1)#neue Position auf das korrekte Endfeld setzten #wenn keine eigene Figur blockiert if self.pEnd[playerFrame.color][newField].player == None or not self.fieldNeutral[newField].player.color == playerFrame.color: return True else: return False else: return False #wenn Overflow im Array elif newField > 39: newField -= 40 #Overflow beheben #wenn keine eigene Figur blockiert if (self.fieldNeutral[newField].player == None or not self.fieldNeutral[newField].player.color == playerFrame.color): return True else: return False #sonst, wenn keine eigene Figur blockiert elif self.fieldNeutral[newField].player == None or not self.fieldNeutral[newField].player.color == playerFrame.color: return True return False #Methode, die playerFrame um die Anzahl field bewegt, wenn moeglich (return bool) def movePlayer(self,playerFrame,field): newField = playerFrame.fieldPos + field #neue Position der Figur #wenn im Endbereich if playerFrame.isEndZone: #wenn neue Position innerhalb des Endbereich if newField < 4: #wenn keine eigene Figur blockiert if self.fieldNeutral[newField].player == None or not self.fieldNeutral[newField].player.color == playerFrame.color: self.pEnd[playerFrame.color][playerFrame.fieldPos] = None #Spieler im alten Feld entfernen playerFrame.fieldPos = newField #neue Position des Spielers intern setzten self.pEnd[playerFrame.color][newField].player = playerFrame #Spieler im neuen Feld anmelden playerFrame.pos = self.pEnd[playerFrame.color][newField].pos #neue Position des Spielers graphisch setzten return True return False #wenn im Haus elif playerFrame.fieldPos == -1: newField = self.colorStartField[playerFrame.color] #wenn keine eigene Figur blockiert if (self.fieldNeutral[newField].player == None or not self.fieldNeutral[newField].player.color == playerFrame.color) and field == 6: #wenn anderer Spieler wird geschlagen if not self.fieldNeutral[newField].player == None and not self.fieldNeutral[newField].player.color == playerFrame.color: self.fieldNeutral[newField].player.pos = self.fieldNeutral[newField].player.posCopy #geschlagenen Spieler zuruecksetzen self.fieldNeutral[newField].player.fieldPos = -1 #neue Position des geschlagenen Spielers auf im Haus setzten playerFrame.fieldPos = newField #neue Position des Spielers intern setzten self.fieldNeutral[newField].player = playerFrame #Spieler im neuen Feld anmelden playerFrame.pos = self.fieldNeutral[newField].pos #neue Position des Spielers graphisch setzten return True return False #wenn kommt in den Endbereich elif newField > self.colorEndField[playerFrame.color]and (playerFrame.fieldPos < self.colorStartField[playerFrame.color] or playerFrame.color == 0): if newField < self.colorEndField[playerFrame.color] + 5: print newField newField -= self.colorEndField[playerFrame.color] newField -= 1 #neue Position auf das korrekte Endfeld setzten print newField #wenn keine eigene Figur blockiert if (self.fieldNeutral[newField].player == None or not self.fieldNeutral[newField].player.color == playerFrame.color): self.goal[playerFrame.color] += 1 #der Farbe einem Punkt geben playerFrame.isEndZone = True #Zustand des Spielers intern auf im Ziel setzten self.fieldNeutral[playerFrame.fieldPos].player = None #Spieler im alten Feld entfernen playerFrame.fieldPos = newField #neue Position des Spielers intern setzten self.pEnd[playerFrame.color][newField].player = playerFrame #Spieler im neuen Feld anmelden playerFrame.pos = self.pEnd[playerFrame.color][newField].pos #neue Position des Spielers graphisch setzten return True else: return False else: return False #wenn Overflow im Array elif newField > 39: newField -= 40 #Overflow beheben #wenn keine eigene Figur blockiert if (self.fieldNeutral[newField].player == None or not self.fieldNeutral[newField].player.color == playerFrame.color): #wenn anderer Spieler wird geschlagen if not self.fieldNeutral[newField].player == None and not self.fieldNeutral[newField].player.color == playerFrame.color: self.fieldNeutral[newField].player.pos = self.fieldNeutral[newField].player.posCopy #geschlagenen Spieler zuruecksetzen self.fieldNeutral[newField].player.fieldPos = -1 #neue Position des geschlagenen Spielers auf im Haus setzten self.fieldNeutral[playerFrame.fieldPos].player = None #Spieler im alten Feld entfernen playerFrame.fieldPos = newField #neue Position des Spielers intern setzten self.fieldNeutral[newField].player = playerFrame #Spieler im neuen Feld anmelden playerFrame.pos = self.fieldNeutral[newField].pos #neue Position des Spielers graphisch setzten return True return False #sonst, wenn keine eigene Figur blockiert elif self.fieldNeutral[newField].player == None or not self.fieldNeutral[newField].player.color == playerFrame.color: #wenn anderer Spieler wird geschlagen if not self.fieldNeutral[newField].player == None and not self.fieldNeutral[newField].player.color == playerFrame.color: self.fieldNeutral[newField].player.pos = self.fieldNeutral[newField].player.posCopy #geschlagenen Spieler zuruecksetzen self.fieldNeutral[newField].player.fieldPos = -1 #neue Position des geschlagenen Spielers auf im Haus setzten self.fieldNeutral[playerFrame.fieldPos].player = None #Spieler im alten Feld entfernen playerFrame.fieldPos = newField #neue Position des Spielers intern setzten self.fieldNeutral[newField].player = playerFrame #Spieler im neuen Feld anmelden playerFrame.pos = self.fieldNeutral[newField].pos #neue Position des Spielers graphisch setzten return True return False def allOfColorInHouse(self,color): for i in range(4): if self.p[color][i].fieldPos <> -1 and self.p[color][i].isEndZone == False: return False return True def encodePlayerSituation(self): PLAYER_SPLIT = "|" COORD_SPLIT = ":" END_STATE_SPLIT = "," rString = "" for color in range(4): for pIndex in range(4): if not rString == "": rString += PLAYER_SPLIT rString += str(color) + str(pIndex) + COORD_SPLIT + str(self.p[color][pIndex].fieldPos) + END_STATE_SPLIT + str(self.p[color][pIndex].isEndZone) return rString def decodePlayerSituation(self, dString): PLAYER_SPLIT = "|" COORD_SPLIT = ":" END_STATE_SPLIT = "," for cString in dString.split(PLAYER_SPLIT): pIndex = cString.split(COORD_SPLIT)[0] color = int(pIndex[:1]) subIndex = int(pIndex[1:2]) if self.p[color][subIndex].isEndZone: self.pEnd[color][self.p[color][subIndex].fieldPos] = None elif self.p[color][subIndex].fieldPos == -1: hi = 0 else: self.fieldNeutral[self.p[color][subIndex].fieldPos].player = None rawCoords = cString.split(COORD_SPLIT)[1] coords = rawCoords.split(END_STATE_SPLIT)[0] endState = rawCoords.split(END_STATE_SPLIT)[1] self.p[color][subIndex].fieldPos = int(coords) self.p[color][subIndex].isEndZone = (endState == "True") if self.p[color][subIndex].isEndZone: self.p[color][subIndex].pos = self.pEnd[color][self.p[color][subIndex].fieldPos].pos self.pEnd[color][self.p[color][subIndex].fieldPos].player = self.p[color][subIndex] elif self.p[color][subIndex].fieldPos == -1: self.p[color][subIndex].pos = self.p[color][subIndex].posCopy else: self.p[color][subIndex].pos = self.fieldNeutral[self.p[color][subIndex].fieldPos].pos self.fieldNeutral[self.p[color][subIndex].fieldPos].player = self.p[color][subIndex] def run(self): #Hauptthread ## scene.title = "Mensch aergere dich nicht!" #Fenstertitel scene.forward = (0,-0.5,-1) #Kamerawinkel scene.background = (1,1,1) #Hintergrund field = Spielfeld() #Spielfeld (Hauptobjekt) random.seed() #Wuerfel while True: #Spiel startet isAgain = True allInHouseCount = 0 #Zug beginnt while isAgain: endTurn = False #Wuerfeln print "Spieler Nummer "+ str(self.curPlayer) + " ist an der Reihe:" result = random.randint(1,7) self.controller.weiterleiten(self.encodePlayerSituation(), self.controller.SIT_DICE_KEY) print "Er wuerfelt " + str(result) isAgain = False ## if result == 6: ## isAgain = True ## else: ## isAgain = False ## ## if self.allOfColorInHouse(self.curPlayer) and allInHouseCount <2: ## isAgain = True ## allInHouseCount += 1 #testet Moeglichkeit zu ziehen for i in range(4): if self.calcPossible(self.p[self.curPlayer][i],result): #Mauseingabe: wartet auf korrekten Zug while not endTurn: rate(30) if scene.mouse.events: m1 = scene.mouse.getclick() #wenn Spieler angeklickt if type(m1.pick) == cone or type(m1.pick) == sphere: #wenn Farbe des Spielers stimmt if m1.pick.frame.color == self.curPlayer: #bewege Spieler und setzte ob der Zug korrekt war (je nach Ergebnis von movePlayer) endTurn = self.movePlayer(m1.pick.frame,result)# self.controller.weiterleiten(self.encodePlayerSituation(), self.controller.SIT_UPLOAD_KEY) #wenn Sieger if self.goal[self.curPlayer] > 3: print str(self.curPlayer) + "wins!" #Spieler wechseln self.curPlayer += 1 if self.curPlayer > 3: self.curPlayer = 0 self.controller.weiterleiten(str(self.curPlayer), self.controller.SET_CUR_PLAYER_KEY) #Klasse Player, erbt von Frame class Player(frame): def __init__(self,color = (1,1,1)): frame.__init__(self) #super-Konstruktor self.bottom = cone(frame = self,axis=(0,1,0), radius=0.35,color = color) #graphischer Rumpf self.head = sphere(frame = self, radius=0.3,pos=(0,0.8,0),color = color) #graphischer Kopf self.fieldPos = -1 #aktuelle Position (Startposition = -1) if color == (1,0,0): #Farbcode in Colormap (siehe Anfang der Datei) self.color = 0 elif color == (0,0,1): self.color = 1 elif color == (0,1,0): self.color = 2 elif color == (1,1,0): self.color = 3 self.isEndZone= False #Zustand(im Ziel, oder nicht) self.posCopy = None #Kopie der Startposition #Klasse PosFeld (Spielfeld), erbt von Frame class PosFeld(frame): def __init__(self,color= (0,0,0)): frame.__init__(self) #super-Konstruktor self.feld = ring(frame = self,axis=(0,1,0),radius=0.4,thickness= 0.05, color = color) #graphischer Kreis self.player = None #Spieler der auf dem Feld steht '''Diese Klasse ermoeglicht die Netzkommunikation. Bau sie in dein Projekt ein. Die eigentliche Spielklasse braucht ein Referenzattribut auf ein Objekt dieser Steuerungs-Klasse, und kann dann mittels der Steuerungs-Methode weiterleiten(nachricht) einen String an die Steuerung schicken, die ihrerseits das an den Server weiterleitet. (Was der Server macht, steht in der Datei "server_class.py", die sich im selben Verzeichnis befinden muss.) Der Konstruktor verlangt ein Objekt, dem er die Nachrichten des Servers schicken soll, also das eigentliche Spiel, und optional einen Port. Jedes Team sollte eine eigene fuenstellige Portnummer waehlen.''' class Steuerung(Thread): def __init__(self, spiel, port=50000): Thread.__init__(self) self.SIT_UPLOAD_KEY = "update_this:" self.SET_CUR_PLAYER_KEY = "set_player:" self.SET_DICE_KEY = "set_dice:" self.view=spiel # UDP-Client, der den Server als Subprozess startet import subprocess # Modul zum Starten von Subprozessen import socket # Modul fuer Netzwerkkommunikation self.PORT = port #Anlegen eines Socket self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # AF_INET = IPv4, SOCK_DGRAM = UDP self.s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1) # Broadcast ermoeglichen #Testen, ob es schon einen Server auf diesem Port gibt, notfalls selber starten try: self.s.sendto("print 'wer hoert mich?'", ('255.255.255.255', self.PORT)) # sende Nachricht 'an alle' self.s.settimeout(2) # warte 1/2 Sekunde.. print (self.s.recvfrom(64)[0]) # gibt Servermeldung aus #ein Problem, wenn timeout einmal gesetzt ist... self.s.settimeout(3000) except: # reagiert auf Zeitueberschreitung print ("Kein Server vorhanden - starte Server") # Rueckmeldung subprocess.Popen(['python','server_class.py',str(self.PORT)]) # Server starten self.s.setblocking(1) # nicht-blockierend self.s.sendto("print 'hallo'", ('255.255.255.255', self.PORT)) self.start() #Endlosmethode zum Abhoeren des Ports auf Nachrichten def run(self): while True: nachricht = self.s.recvfrom(1024)[0] self.auswerten(nachricht) #Methode zum Auswerten der eingegangenen Nachricht def auswerten(self,nachricht): a = "noin wtf es wurde wirklich etwas empfangen!!!" a += "\n" + nachricht if nachricht.startswith(self.SIT_UPLOAD_KEY): nachricht = nachricht[len(self.SIT_UPLOAD_KEY):] a += "\n(" + nachricht + ")" spiel.decodePlayerSituation(nachricht) elif nachricht.startswith(self.SET_CUR_PLAYER_KEY): nachricht = nachricht[len(self.SET_CUR_PLAYER_KEY):] print "Spieler " + nachricht + " ist jetzt dran. (remote festgelegt)" spiel.curPlayer = int(nachricht) elif nachricht.startswith(self.SET_DICE_KEY): nachricht = nachricht[len(self.SET_DICE_KEY):] print "Es wurde " + nachricht + " gewuerfelt. (remote festgelegt)" spiel.result = int(nachricht) #Methode zum Weiterleiten, wird von Spiel genutzt def weiterleiten(self, nachricht, key): print "weiterleiten:" nachricht = key + nachricht print nachricht self.s.sendto(nachricht, ('255.255.255.255', self.PORT)) # versenden der Nachricht an Tupel(IP, PORT) if __name__ == "__main__": spiel = Spielfeld() #das eigentliche Spiel steuerung = Steuerung(spiel, PORT) #Die Steuerung, mit dem Spiel und einem Port als Argument spiel.controller = steuerung #Setzen des Referenzattributs spiel.start() #Das Spiel muss von Thread erben, hier wird dessen run-Methode gestartet