Benutzer-Werkzeuge

Webseiten-Werkzeuge


ws2425:lebewesenverhalten

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen gezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
ws2425:lebewesenverhalten [2025/03/12 17:55]
R.Arndt
ws2425:lebewesenverhalten [2025/05/05 19:41] (aktuell)
stefanborn [Unser Code:]
Zeile 128: Zeile 128:
  
 ====Unser Code:==== ====Unser Code:====
 +
 +<code python>​import tkinter as tk
 +import random as r
 +import math as m
 +import numba
 +import matplotlib.pyplot as plt
 +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
 +
 +fenster = tk.Tk()
 +fenster.title("​Lebewesenverhalten"​)
 +
 +"""​
 +fenster.attributes("​-fullscreen",​ True)
 +def beenden(event=None):​
 +    fenster.attributes("​-fullscreen",​ False)
 +    exit()
 +fenster.bind("<​Escape>",​ beenden)
 +
 +width = fenster.winfo_screenwidth()
 +hight = fenster.winfo_screenheight()
 +"""​
 +
 +fenster.geometry("​1000x600"​)
 +
 +width = 1000
 +hight = 600
 +
 +
 +canvas = tk.Canvas(fenster,​ bg="​pink"​)
 +canvas.pack(fill="​both",​expand=True)
 +
 +def end_simulation(event):​
 + fenster.destroy()
 + fenste = tk.Tk()
 + fenste.title("​Statistik"​)
 + fenste.geometry("​1000x600"​)
 + fig, ax = plt.subplots(figsize=(6,​4))
 + ax.plot(x_werte,​ plant_values)
 + ax.plot(x_werte,​ meat_values)
 + canvas = FigureCanvasTkAgg(fig,​ master=fenste)
 + canvas.draw()
 + canvas.get_tk_widget().pack(fill=tk.BOTH,​ expand=True)
 +
 +fenster.bind("<​Return>",​ end_simulation)
 +
 +start_pflanzenfresser = 50
 +start_fleischfresser = 5
 +anzahl_seen = 1
 +lines = []
 +dis = 100
 +time = 0
 +pflanzenfresser = []
 +new_pflanzenfresser = []
 +fleischfresser = []
 +new_fleischfresser = []
 +seen = []
 +x_werte = []
 +plant_values = []
 +meat_values = []
 +
 +def update(event = None):
 + global time
 + if time % 50 == 0:
 + x_werte.append(time)
 + plant_values.append(len(pflanzenfresser))
 + for tier in pflanzenfresser:​
 + if not tier.alive:
 + plant_values[-1] -= 1
 + meat_values.append(len(fleischfresser))
 + for tier in fleischfresser:​
 + if not tier.alive:
 + meat_values[-1] -= 1
 + #for z in range(len(lines)):​
 + #​ canvas.delete(lines[z])
 + global new_pflanzenfresser
 + global new_fleischfresser
 + for baby in new_pflanzenfresser:​
 + pflanzenfresser.append(baby)
 + baby.show()
 + new_pflanzenfresser = []
 + for baby in new_fleischfresser:​
 + fleischfresser.append(baby)
 + baby.show()
 + new_fleischfresser = []
 +
 + for pflanzenfresse in pflanzenfresser:​
 + if pflanzenfresse.alive:​
 + if time % 5 == 2:
 + pflanzenfresse.sight()
 + pflanzenfresse.check_grazing()
 + pflanzenfresse.change_food(-5*pflanzenfresse.speed)
 + if pflanzenfresse.mating_cooldown > 0:
 + pflanzenfresse.mating_cooldown -= 5
 + pflanzenfresse.move()
 +
 + for fleischfresse in fleischfresser:​
 + if fleischfresse.alive:​
 + if time % 5 == 0:
 + fleischfresse.sight()
 + fleischfresse.change_food(-5*fleischfresse.speed)
 + if fleischfresse.mating_cooldown > 0:
 + fleischfresse.mating_cooldown -= 5
 + fleischfresse.move()
 + time += 1
 + #​fenster.bind("<​space>",​ update)
 + canvas.after(20,​ update)
 +
 +def det(alpha, beta):
 + return m.sin(m.radians(beta-alpha))
 +
 +#Distanz zwischen zwei Punkten
 +def distance(x1,​ x2, y1, y2):
 + return m.sqrt((x1 - x2)**2 + (y1 - y2)**2)
 +
 +#Quadrat des Abstandes zweier Punkte (für schnelle Berechnungen)
 +def squared_distance(x1,​ x2, y1, y2):
 + return (x1 - x2)**2 + (y1 - y2)**2
 +
 +class Objekt:
 + def __init__(self,​ x, y):
 + self.x = x
 + self.y = y
 +
 +class Tiere(Objekt):​
 + def __init__(self,​ x, y , direction, health = 1000, food = 10000, a = 40, b = 180, color = "​black",​ status = "​wandering"​):​
 +#​Eigenschaften
 + super().__init__(x,​ y)
 + self.direction = direction
 + self.direction_offset = 0
 + self.health = health
 + self.food = food
 + self.color = color
 + self.mating_cooldown = 0
 +#Sicht
 + self.sichtweite = a
 + self.sichtkegelwinkel = b
 +#​Eigenschaften,​ von denen das Handeln abhängt
 + self.alive = True
 + self.status = "​wandering"​
 + self.threat = None
 + self.target = None
 + self.avoiding = None
 +
 + def change_food(self,​ change):
 + if self.food > 0 or change > 0:
 + self.food += change
 + elif self.food <= 0:
 + self.change_health(-10)
 +
 +#tiere verlieren teile ihrer Gesundheit
 + def change_health(self,​ change):
 + self.health += change
 + if self.health <= 0:
 + self.die()
 +
 +#Änderung der Richtung
 + def change_direction(self,​ type, change):
 + if type == "​set":​
 + self.direction = change
 + elif type == "​add":​
 + self.direction += change
 + self.direction %= 360
 +
 +#tiere werden wenn sie keine Lebenspunkte mehr haben aus der update-schleife genommen
 + def die(self):
 + self.alive = False
 + if isinstance(self,​ Fleischfresser):​
 + print(self.id)
 + self.hide()
 +
 +#bewegt ein Tier vorwärts abhängig von "​speed"​ und "​direction"​
 + def forward(self):​
 + self.x += self.speed*m.cos(m.radians(self.direction+self.direction_offset))
 + self.y += self.speed*m.sin(m.radians(self.direction+self.direction_offset))
 + self.hide()
 + self.show()
 +
 +#beschreibt das Verhalten eines Tieres während seines sogenannten Zuges basierend auf dem Status
 + def move(self):
 + if self.status == "​wandering":​
 + self.change_direction("​add",​ r.randint(-5,​5))
 + self.forward()
 +
 + elif self.status == "​fleeing":​
 + if squared_distance(self.x,​ self.threat.x,​ self.y, self.threat.y) >= 90000 and self.threat.target != self:
 + self.status = "​wandering"​
 + self.threat = None
 + self.speed = self.walking_speed
 + self.forward()
 +
 + elif self.status == "​hunting":​
 + self.change_direction("​set",​ m.degrees(m.atan2((self.target.y-self.y),​(self.target.x-self.x))))
 + if (self.x-self.target.x)**2+(self.y-self.target.y)**2 <= (self.radius+self.target.radius)**2:​
 + self.collision()
 + self.forward()
 +
 +#​Visualisierung der Tiere
 + def show(self):
 + self.id = canvas.create_oval(self.x-self.radius,​ self.y-self.radius,​ self.x+self.radius,​ self.y+self.radius,​ fill=self.color)
 +
 + def hide(self):
 + canvas.delete(self.id)
 +
 +
 +#def det(alpha, beta):
 +# return m.sin(m.radians(beta-alpha))
 +#​Überprüft ob die Richtung des Hindernisses im Wahrnehmungsbereich des Tieres liegt
 + def in_sight(self,​ avoid):
 + direction_left_edge = (self.direction + self.direction_offset) + (self.sichtkegelwinkel / 2) #in der Visualiesierung sind die Seiten vertauscht, weil y-Achse auch gespiegelt ist
 + direction_right_edge = (self.direction + self.direction_offset) - (self.sichtkegelwinkel / 2) #in der Visualiesierung sind die Seiten vertauscht, weil y-Achse auch gespiegelt ist
 + return det(direction_left_edge,​ avoid) < 0 and det(avoid, direction_right_edge) < 0
 +
 +#​Wahrnehmung der Umwelt mithilfe von Stichpunktartigen Zustandschecks entlang der sightrichtung ("​direction"​)
 + def sight(self):​
 + self.avoiding = None
 +
 + potential_targets = []
 + potential_threats = []
 +
 +#debug:
 + #​lines.append(canvas.create_line(self.x,​ self.y, self.x+dis*m.cos(m.radians((self.direction + self.direction_offset) + (self.sichtkegelwinkel / 2))), self.y+dis*m.sin(m.radians((self.direction + self.direction_offset) + (self.sichtkegelwinkel / 2))), fill = "​orange"​))
 + #​lines.append(canvas.create_line(self.x,​ self.y, self.x+dis*m.cos(m.radians(self.direction+self.direction_offset)),​ self.y+dis*m.sin(m.radians(self.direction+self.direction_offset)),​ fill = "​orange"​))
 + #​lines.append(canvas.create_line(self.x,​ self.y, self.x+dis*m.cos(m.radians((self.direction + self.direction_offset) - (self.sichtkegelwinkel / 2))), self.y+dis*m.sin(m.radians((self.direction + self.direction_offset) - (self.sichtkegelwinkel / 2))), fill = "​orange"​))
 +
 +
 +#Kollision mit der Ecke links oben verhindern
 + if m.sin(m.radians(self.direction+self.direction_offset)) <= 0 and m.cos(m.radians(self.direction+self.direction_offset)) <= 0:
 + if self.x > dis and self.y <= dis:
 + self.avoiding = 270
 + elif self.x <= dis and self.y > dis:
 + self.avoiding = 180
 + elif self.x <= dis and self.y <= dis:
 + if self.avoiding == None:
 + self.avoiding = 180
 +
 +#Kollision mit der Ecke rechts oben verhindern
 + elif m.sin(m.radians(self.direction+self.direction_offset)) <= 0 and m.cos(m.radians(self.direction+self.direction_offset)) > 0:
 + if self.x <= width-dis and self.y <= dis:
 + self.avoiding = 270
 + elif self.x > width-dis and self.y > dis:
 + self.avoiding = 0
 + elif self.x > width-dis and self.y <= dis:
 + if self.avoiding == None:
 + self.avoiding = 0
 +
 +#Kollision mit der Ecke links unten verhindern
 + elif m.sin(m.radians(self.direction+self.direction_offset)) > 0 and m.cos(m.radians(self.direction+self.direction_offset)) <=  0:
 + if self.x > dis and self.y > hight-dis:
 + self.avoiding = 90
 + elif self.x <= dis and self.y <= hight-dis:
 + self.avoiding = 180
 + elif self.x <= dis and self.y > hight-dis:
 + if self.avoiding == None:
 + self.avoiding = 180
 +
 +#Kollision mit der Ecke rechts unten verhindern
 + elif m.sin(m.radians(self.direction+self.direction_offset)) > 0 and m.cos(m.radians(self.direction+self.direction_offset)) > 0:
 + if self.x <= width-dis and self.y > hight-dis:
 + self.avoiding = 90
 + elif self.x > width-dis and self.y <= hight-dis:
 + self.avoiding = 0
 + elif self.x > width-dis and self.y > hight-dis:
 + if self.avoiding == None:
 + self.avoiding = 0
 + if self.avoiding != None:
 + self.avoid(self.avoiding)
 +
 +
 + for k in range(len(pflanzenfresser)):​
 + if pflanzenfresser[k].alive and not ((isinstance(self,​ Pflanzenfresser) and k == self.number)):​
 + direction_animal = m.degrees(m.atan2((pflanzenfresser[k].y-self.y),​(pflanzenfresser[k].x-self.x)))
 + if self.in_sight(direction_animal):​
 + self.react_to_pflanzenfresser(k,​ potential_targets)
 +
 + for k in range(len(fleischfresser)):​
 + if fleischfresser[k].alive and not (isinstance(self,​ Fleischfresser) and k == self.number):​
 + direction_animal = m.degrees(m.atan2((fleischfresser[k].y-self.y),​(fleischfresser[k].x-self.x)))
 + if self.in_sight(direction_animal):​
 + self.react_to_fleischfresser(k,​ potential_threats)
 +
 + if len(potential_targets) > 0:
 + self.set_target(self.find_animal(potential_targets))
 + if len(potential_threats) > 0:
 + self.set_threat(self.find_animal(potential_threats))
 +
 + if self.avoiding == None:
 + self.change_direction("​add",​ self.direction_offset)
 + self.direction_offset = 0
 +
 +#Ändert die Richtung, mithilfe einer Offset variable
 + def avoid(self, direction_avoid):​
 + determinante = det(self.direction+self.direction_offset,​ direction_avoid)
 + if determinante < 0:
 + self.direction_offset += 10
 + else:
 + self.direction_offset -= 10
 +
 + def find_animal(self,​ animals):
 + if len(animals) > 0:
 + nearest_animal = animals[0]
 + for i in range(1, len(animals)):​
 + if squared_distance(self.x,​ animals[i].x,​ self.y, animals[i].y) < squared_distance(self.x,​ nearest_animal.x,​ self.y, nearest_animal.y):​
 + nearstest_animal = animals[i]
 + return nearest_animal
 +
 +#setzt den status auf "​fleeing"​
 + def set_threat(self,​ threat):
 + self.status = "​fleeing"​
 + self.threat = threat
 + self.speed = self.running_speed
 + self.change_direction("​set",​ m.degrees(m.atan2((self.threat.y-self.y),​(self.threat.x-self.x))) + 180)
 +
 +#setzt den status auf "​hunting"​
 + def set_target(self,​ target):
 + self.status = "​hunting"​
 + self.target = target
 + self.color = "​red"​
 + self.speed = self.running_speed
 +
 +#Wenn ein Fleischfresser einen Pflanzenfresser gefangen hat verliert der Pflanzenfresser leben bis er stirbt. Dann wird der Status des Fleischfressers wieder zurückgesetzt
 + def collision(self):​
 + self.target.change_health(-100)
 + if self.target.alive == False:
 + self.change_food(500)
 + self.status = "​wandering"​
 + self.color = "​blue"​
 + self.speed = self.walking_speed
 +
 +class Pflanzenfresser(Tiere):​
 + radius = 5
 + def __init__(self,​ i, x, y, direction):
 + self.number = i
 + self.grazing_speed = 0.1
 + self.walking_speed = 0.5
 + self.running_speed = 2.5
 + self.speed = self.walking_speed
 + super().__init__(x,​ y, direction, 1000, 1000, 40, 180, "​green"​)
 +
 + def check_grazing(self):​
 + if self.food < 900:
 + self.speed = self.grazing_speed
 + elif self.food >= 1000:
 + self.speed = self.walking_speed
 + if self.speed == self.grazing_speed:​
 + self.change_food(1)
 +
 + def react_to_pflanzenfresser(self,​ k, potential_threats):​
 + if self.status == "​wandering"​ and pflanzenfresser[k].status == "​wandering":​
 + if squared_distance(self.x,​ pflanzenfresser[k].x,​ self.y, pflanzenfresser[k].y) < 4*self.radius**2:​
 + if self.mating_cooldown == 0 and pflanzenfresser[k].mating_cooldown == 0:
 + if self.food >= 500 and pflanzenfresser[k].food >= 500:
 + if len(pflanzenfresser) <= 400:
 + global new_pflanzenfresser
 + random_direction = r.randint(0,​359)
 + new_pflanzenfresser.append(Pflanzenfresser(len(pflanzenfresser)+len(new_pflanzenfresser),​ self.x, self.y, random_direction))
 + self.mating_cooldown = 1000
 + pflanzenfresser[k].mating_cooldown = 1000
 + elif squared_distance(self.x,​ pflanzenfresser[k].x,​ self.y, pflanzenfresser[k].y) < 10000:
 + if self.mating_cooldown == 0:
 + self.change_direction("​set",​ m.degrees(m.atan2((pflanzenfresser[k].y-self.y),​(pflanzenfresser[k].x-self.x))))
 +
 + def react_to_fleischfresser(self,​ k, potential_threats):​
 + quadratischeDistanz = squared_distance(self.x,​ fleischfresser[k].x,​ self.y, fleischfresser[k].y)
 + if quadratischeDistanz <= dis**2:
 + potential_threats.append(fleischfresser[k])
 +
 +class Fleischfresser(Tiere):​
 + radius = 8
 + def __init__(self,​ i, x, y, direction):
 + self.number = i
 + self.walking_speed = 0.8
 + self.running_speed = 2
 + self.speed = self.walking_speed
 + super().__init__(x,​ y, direction, 1000, 1000, 100, 120, "​blue"​)
 +
 + def react_to_pflanzenfresser(self,​ k, potential_targets):​
 + quadratischeDistanz = squared_distance(self.x,​ pflanzenfresser[k].x,​ self.y, pflanzenfresser[k].y)
 + if quadratischeDistanz <= 200**2:
 + if self.food < 500:
 + if self.status == "​wandering":​
 + potential_targets.append(pflanzenfresser[k])
 + elif self.status == "​hunting":​
 + if quadratischeDistanz < squared_distance(self.x,​ self.target.x,​ self.y, self.target.y):​
 + potential_targets.append(pflanzenfresser[k])
 +
 + def react_to_fleischfresser(self,​ k, potential_targets):​
 + if self.status == "​wandering"​ and fleischfresser[k].status == "​wandering":​
 + if squared_distance(self.x,​ pflanzenfresser[k].x,​ self.y, pflanzenfresser[k].y) < 4*self.radius**2:​
 + if self.mating_cooldown == 0 and fleischfresser[k].mating_cooldown == 0:
 + if self.food >= 500 and fleischfresser[k].food >= 500:
 + global new_fleischfresser
 + random_direction = r.randint(0,​359)
 + new_fleischfresser.append(Fleischfresser(len(fleischfresser)+len(new_fleischfresser),​ self.x, self.y, random_direction))
 + self.mating_cooldown = 1000
 + fleischfresser[k].mating_cooldown = 1000
 + elif squared_distance(self.x,​ fleischfresser[k].x,​ self.y, fleischfresser[k].y) < 40000:
 + if self.mating_cooldown == 0:
 + self.change_direction("​set",​ m.degrees(m.atan2((fleischfresser[k].y-self.y),​(fleischfresser[k].x-self.x))))
 +
 +class See(Objekt):​
 + radius = 50
 + def __init__(self,​ number, x = 50, y = 50):
 + self.number = number
 + self.radius = radius
 + self.x = x
 + self.y = y
 + self.color = "​blue"​
 + super().__init__(x,​ y)
 +
 +#​Simulationsaufbau
 +for i in range(start_pflanzenfresser):​
 + random_x = r.randint(Pflanzenfresser.radius,​ width - Pflanzenfresser.radius)
 + random_y = r.randint(Pflanzenfresser.radius,​ hight - Pflanzenfresser.radius)
 + random_direction = r.randint(0,​359)
 + pflanzenfresser.append(Pflanzenfresser(i,​ random_x, random_y , random_direction))
 + pflanzenfresser[i].show()
 +
 +for i in range(start_fleischfresser):​
 + random_x = r.randint(Fleischfresser.radius,​ width - Fleischfresser.radius)
 + random_y = r.randint(Fleischfresser.radius,​ hight - Fleischfresser.radius)
 + random_direction = r.randint(0,​359)
 + fleischfresser.append(Fleischfresser(i,​ random_x, random_y, random_direction))
 + fleischfresser[i].show()
 +
 +
 +for i in range(anzahl_seen): ​                                     ###hiermit habe ich den See und Strand gezeichnet
 +   ​
 + id = canvas.create_rectangle(0,​ 70, 100, 0, fill= "​yellow",​ outline = "​yellow"​) ​   # Das ist die Füllung vom Loch oben links
 +   ​
 + id = canvas.create_rectangle(0,​ 200, 100, 0, fill= "​yellow",​ outline = "​yellow"​)
 +   ​
 + id = canvas.create_oval(0,​ 250, 100, 0, fill= "​yellow",​ outline = "​yellow"​)
 +
 + id = canvas.create_oval(0,​ 245, 50, 150, fill= "​yellow",​ outline = "​yellow"​)
 +
 + id = canvas.create_oval(0,​ 255, 70, 150, fill= "​yellow",​ outline = "​yellow"​)
 +
 + id = canvas.create_oval(-50,​ 255, 30, 100, fill= "​yellow",​ outline = "​yellow"​)
 +
 + id = canvas.create_oval(-100,​ 260, 100, 100, fill= "​yellow",​ outline = "​yellow"​)
 +
 + id = canvas.create_oval(-100,​ 260, 200, 100, fill= "​yellow",​ outline = "​yellow"​)
 +
 +
 +
 +   ​
 +   ​
 +                                       ​
 + id = canvas.create_oval(0,​ 150, 100, 0, fill= "​blue",​ outline = "​blue"​)
 +
 + id = canvas.create_oval(300,​ 150, 170, 0, fill= "​blue",​ outline = "​blue"​)
 +
 + id = canvas.create_oval(50,​ 100, 240, 200, fill= "​blue",​ outline = "​blue"​)
 +
 + id = canvas.create_rectangle(50,​ 0, 220, 150, fill= "​blue",​ outline = "​blue"​)
 +
 + id = canvas.create_oval(250,​ 140, 220, 157, fill= "​blue",​ outline = "​blue"​)
 +                                  
 + id = canvas.create_oval(16,​ 50, 220, 190, fill= "​blue",​ outline = "​blue"​)
 +update()
 +</​code>​
 +
 +
 +
 +
ws2425/lebewesenverhalten.1741798501.txt.gz · Zuletzt geändert: 2025/03/12 17:55 von R.Arndt