Nevu - ein Neuanfang
Verfasst: 28.11.2006 20:09
Hallo, einige erinnern sich vieleicht noch an Nevu, wenn nicht, hier ist ein altes Forumsthema dazu, dass mitlerweile sehr alt ist: http://www.purebasic.fr/german/viewtopic.php?t=6832
Ich habe das Programm neugeschreiben, vereinfacht und gut Kommentiert, so dass es besser von euch verstanden und vielleicht sogar erweitert werden kann:
Verbesserungen vielleicht gleich hier posten.
Ich habe das Programm neugeschreiben, vereinfacht und gut Kommentiert, so dass es besser von euch verstanden und vielleicht sogar erweitert werden kann:
Code: Alles auswählen
;Nevu V1
;Gebrauchsanweisung:
;Am anfang mutation auf 100 stellen und futter auf 30 lassen
;im menü auf running drücken
;wenn es mehr als 100 Zellen gibt im menü auf visualisieren drücken, und nach belieben zusehen
;mutation am besten wieder auf einen wert unter 10 und über 0 stellen
;Vosicht:wenn die visualisierung an ist, läuft die Simulation viel langsammer
; Homepage: www.nevu.de
;MfG Marcel Richter
;{ complexität des codes für die Turingmaschine der Einzeller
#abc=2 ;anzahl der zeichen im alphabet der turingmaschine. mindestens 2, max 127 da in byte gespeichert
#zustandcount=5000 ;wieviele zustände kennt die turingmaschine (man könnte sagen wieiele zeielen hat der code der ki maximal)
#bandsize=10000 ;wieviele speicherzellen hat das turingband? muss größer als eingabe und ausgabeteil sein.
#maxsteps=100000 ;wieviele arbeitsschritte kan die turingmaschine einer zelle maximal machen?
;wichtig, da manche turingcodes die entstehen sonst endlos laufen, und das programm abstürtzen lässt
;}
;{ config
#weltx=200 ;breite der simulierten welt
#welty=200 ; höhe der simulierten welt
#naehrwert=40 ; wieviel energie bekommt eine zelle gutgeschrieben, wenn es etwas zufressen findet?
#futterminimum=1500 ;wieviel essen\energie muss eine zelle angesammelt haben, bevor sie sich teilt
#maxalter=5000 ; wie alt kann eine zelle maximal werden?
;}
;{ Codelesbarkeit
#futter=1
#leer=0
#turing_terminationszustand=-1 ; wenn die zuringmaschine diesen zustand ereicht, beendet sie sich und ist fertig
;}
;{ Bandzeiger
#hoch_bewegen=0 ;hier sind namen für bestimmte elemente des turingbandes gegeben, je nach funktion
#runter_bewegen=#hoch_bewegen+1 ; die ersten bestimen zb wohin sich eine zelle bewegt
#rechts_bewegen=#runter_bewegen+1
#links_bewegen=#rechts_bewegen+1
#blickhoch=#links_bewegen+1 ; und diese zeiger, zeigen auf die stellen im turingband auf die geschrieben wird
#blickrunter=#blickhoch+1 ; was um die zelle vorgeht
#blickrechts=#blickrunter+1
#blicklinks=#blickrechts+1
;}
InitSprite()
;{ konstanten
Enumeration
#hauptfenster
#hauptfenster_gadget_text_weltzeit
#hauptfenster_gadget_text_Zellenanzahl
#hauptfenster_gadget_text_rundenprosek
#hauptfenster_menu
#hauptfenster_menu_visualisierung
#hauptfenster_menu_running
#hauptfenster_menu_reset
#hauptfenster_menu_laden
#hauptfenster_menu_speichern
#hauptfenster_menu_web
#hauptfenster_gadget_trackbar_futter
#hauptfenster_gadget_text_futter
#hauptfenster_gadget_trackbar_mutationen
#hauptfenster_gadget_text_mutationen
#timer_hauptfenster_statistik
#visualisierungsfenster
EndEnumeration
;}
;{ Statistiksysem
Structure STATISTIK
weltzeit.l ;wie viele runden wurden berechnet?
alteweltzeit.l ;um die runden pro sekunde zu berechnen
EndStructure
Global statistik.STATISTIK
;}
;{ Zellenspeichersystem
Structure BODY
schreiben.b ;speichert, was auf das band geschreiben werden soll - vorsicht Byte geht nur bis 128
richtung.b ; In welche richtung soll der schreib\lesekopf verschoben werden?
zielzustand.l ; in welchen zustand soll die turingmaschine anschließend wechseln?
EndStructure
Structure ZUSTAND
eingabezeichen.BODY[#abc] ;jeder zustand muss auf jedes eingelesene zeichen reagieren können
EndStructure
Structure ZELLE
zustand.ZUSTAND[#zustandcount] ;jede zelle hat viele zustände gespeichert in der die turingmaschine sein kann
x.l ;x und y position der zellen in der welt
y.l
band.b[#bandsize] ; das turingband
magen.l ;die energiereserven der zelle
alter.l ;wie alt ist die zelle?
EndStructure
Global NewList Zellen.ZELLE()
;}
;{ Statusspeicher
Structure STATUS
visualisierung.l ;ist true wenn die welt gezeichnet werden soll
running.l ;ist true wenn die simulation läuft
EndStructure
Global status.STATUS
;}
;{ Weltstruc
Structure WELTSTRUC
inhalt.l ;inhalt eines feldes der welt(leer oder futter)
EndStructure
Global Dim welt.WELTSTRUC(#weltx,#welty)
;}
;{ Umweltstruc
Structure UMWELTSTRUC
mutationen.l ;speichert wie sehr kinder mutiert werden
essenzusatz.l ;Wieviel futter wird verteilt
EndStructure
Global umwelt.UMWELTSTRUC
;}
Procedure update_gui_umweltkontrollen()
;aktualisiert die gui
SetGadgetState(#hauptfenster_gadget_trackbar_futter,umwelt\essenzusatz)
SetGadgetText(#hauptfenster_gadget_text_futter,Str(umwelt\essenzusatz))
SetGadgetState(#hauptfenster_gadget_trackbar_mutationen,umwelt\mutationen)
SetGadgetText(#hauptfenster_gadget_text_mutationen,Str(umwelt\mutationen))
EndProcedure
Procedure openhauptfenster()
OpenWindow(#hauptfenster,60,60,200,200,#PB_Window_MinimizeGadget ,"Nevu - Steuerfenster")
CreateGadgetList(WindowID(#hauptfenster))
TextGadget(#PB_Any,15,10,100,15,"Weltzeit:")
TextGadget(#hauptfenster_gadget_text_weltzeit,130,10,70,15,"0")
TextGadget(#PB_Any,15,30,100,15,"Zellenanzahl:")
TextGadget(#hauptfenster_gadget_text_zellenanzahl,130,30,70,15,"0")
TextGadget(#PB_Any,15,50,100,15,"Runden pro Sek:")
TextGadget(#hauptfenster_gadget_text_rundenprosek,130,50,70,15,"0")
TextGadget(#PB_Any,5,90,150,12,"Essenzusatz:")
TrackBarGadget(#hauptfenster_gadget_trackbar_futter, 0, 103, 150, 20, 0, 100)
TextGadget(#hauptfenster_gadget_text_futter,150,103,30,12,"0")
TextGadget(#PB_Any,5,120,150,12,"Mutation:")
TrackBarGadget(#hauptfenster_gadget_trackbar_mutationen, 0, 138, 150, 20, 0, 100)
TextGadget(#hauptfenster_gadget_text_mutationen,150,138,30,15,"0")
CreateMenu(#hauptfenster_menu,WindowID(#hauptfenster))
MenuTitle("Steuerung")
MenuItem(#hauptfenster_menu_visualisierung, "Visualisieren")
MenuItem(#hauptfenster_menu_running, "running")
MenuItem(#hauptfenster_menu_reset, "reset")
MenuItem(#hauptfenster_menu_laden, "laden")
MenuItem(#hauptfenster_menu_speichern, "speichern")
MenuItem(#hauptfenster_menu_web, "Visit http://www.nevu.de")
SetTimer_(WindowID(#hauptfenster),#timer_hauptfenster_statistik,1000,0)
update_gui_umweltkontrollen()
EndProcedure
Procedure start_visualisierung()
OpenWindow(#visualisierungsfenster,100,100,#weltx, #welty, #PB_Window_SystemMenu,"Visualisierung",WindowID(#hauptfenster))
OpenWindowedScreen(WindowID(#visualisierungsfenster),0,0,#weltx, #welty, 0, 0, 0)
status\visualisierung=#True
SetMenuItemState(#hauptfenster_menu, #hauptfenster_menu_visualisierung, 1)
EndProcedure
Procedure stop_visualisierung()
status\visualisierung=#False
SetMenuItemState(#hauptfenster_menu, #hauptfenster_menu_visualisierung, 0)
CloseScreen()
CloseWindow(#visualisierungsfenster)
EndProcedure
Procedure visualisiere_welt()
ClearScreen($000000)
StartDrawing(ScreenOutput())
For x=0 To #weltx-1
For y=0 To #welty-1
If welt(x,y)\inhalt=#futter
Plot(x,y,$00ff00)
EndIf
; If welt(x,y)\inhalt=#mauer
; Plot(x,y,$0000ff)
; EndIf
Next
Next
ForEach zellen()
Box(zellen()\x, zellen()\y,2,2, $ffffff)
Next
StopDrawing()
FlipBuffers()
EndProcedure
Procedure start_running()
status\running=#True
SetMenuItemState(#hauptfenster_menu, #hauptfenster_menu_running, 1)
EndProcedure
Procedure stop_running()
status\running=#False
SetMenuItemState(#hauptfenster_menu, #hauptfenster_menu_running, 0)
EndProcedure
Procedure place_food()
;verteilt je nach einstellung futter in der welt
For i=1 To umwelt\essenzusatz
x=Random(#weltx-1)
y=Random(#welty-1)
If welt(x, y)\inhalt=0
welt(x, y)\inhalt=1
EndIf
Next
EndProcedure
;Diese zwei funktionen sorgen dafür das zellen die links aus der welt fallen, rechts wieder landen
Procedure real_x(x)
ProcedureReturn (x%#weltx+(#False Or x<0)*#weltx)
EndProcedure
Procedure real_y(y)
ProcedureReturn (y%#welty+(#False Or y<0)*#welty)
EndProcedure
Procedure run_turing()
;erst im web nachlesen was eine turingmaschine ist!
zustandsnummer=0 ;speichert den zustand in dem die turingmaschine ist
bandzeiger=0 ;auf welche stelle auf dem band zeigt der schreib\lesekopf?
Steps=0 ; wieviele arbeitsschritte hat die turingmamaschine schon gemacht?
Repeat
If bandzeiger<0 ;das band ist zu einem kreis verbogen, ein wirklich unendlich langes band geht ja nicht^^
bandzeiger+#bandsize
ElseIf bandzeiger>=#bandsize
bandzeiger-#bandsize
EndIf
gelesenes_zeichen=zellen()\band[bandzeiger] ;schreib\lesekopf liest das zeichen ein
zellen()\band[bandzeiger]=zellen()\zustand[zustandsnummer]\eingabezeichen[gelesenes_zeichen]\schreiben ;dem zustand und eingelesenem zeichen entsprechend wird ein zeichen geschrieben
bandzeiger+zellen()\zustand[zustandsnummer]\eingabezeichen[gelesenes_zeichen]\richtung ;verschiebt den schreib\lesekopf
zustandsnummer=zellen()\zustand[zustandsnummer]\eingabezeichen[gelesenes_zeichen]\zielzustand ;versetzt die turingmaschine in den neuen zustand
Steps+1
Until zustandsnummer=#turing_terminationszustand Or Steps>#maxsteps ;#turing_terminationszustand entspricht dem end von PB
If Steps>#maxsteps
ProcedureReturn #False ;das programm lief zu lange, der turingcode wird als fehlerhaft eingestuft
Else
ProcedureReturn #True
EndIf
EndProcedure
Procedure reset()
ClearList(zellen()) ;alle zellen löschen
;For k=1 To 100
AddElement(Zellen())
zellen()\band[#hoch_bewegen]=1 ;auf das band an der stelle wo bestimmt wird ob sich die zelle hoch bewegt, wird eine 1
;geschrieben
zellen()\magen=1000 ;der zelle etwas zu essen mitgeben
For i=1 To 1000000 ;den genetichen code etwas durcheinander wirbeln
zellen()\zustand[Random(#zustandcount-1)]\eingabezeichen[Random(#abc-1)]\schreiben=Random(#abc-1)
zellen()\zustand[Random(#zustandcount-1)]\eingabezeichen[Random(#abc-1)]\richtung=-1+Random(2)
zellen()\zustand[Random(#zustandcount-1)]\eingabezeichen[Random(#abc-1)]\zielzustand=Random(#zustandcount-1)
zellen()\zustand[Random(#zustandcount-1)]\eingabezeichen[Random(#abc-1)]\zielzustand=#turing_terminationszustand
Next
zellen()\zustand[0]\eingabezeichen[1]\schreiben=1 ;die zelle findet eine eins auf dem turingband und schreibt wieder eine
zellen()\zustand[0]\eingabezeichen[1]\zielzustand=#turing_terminationszustand ; und beendet sich sofort( eine minimal-ki)
zellen()\x=Random(#weltx-1) ;irgendwo freisetzen
zellen()\y=Random(#welty-1)
statistik\weltzeit=0
EndProcedure
Procedure calculate_zellen()
ForEach zellen()
zellen()\alter+1
If zellen()\alter>#maxalter ;zu alte zellen töten muhaha
DeleteElement(zellen())
Continue
EndIf
zellen()\band[#blickhoch]=welt(real_y(zellen()\y-1), real_x(zellen()\x))\inhalt ;hier wird der umwelt der zelle entsprechen
zellen()\band[#blickrunter]=welt(real_y(zellen()\y+1), real_x(zellen()\x))\inhalt ;etwas aufs band geschrieben, die augen und ohren
zellen()\band[#blicklinks]=welt(real_y(zellen()\y), real_x(zellen()\x-1))\inhalt
zellen()\band[#blickrechts]=welt(real_y(zellen()\y), real_x(zellen()\x+1))\inhalt
If run_turing()=#False ;hier wird das turingprogramm ausgeführt
DeleteElement(zellen()) ;und wen es fehler gab, die zelle getötet
Continue
EndIf
;{ Fressen
If welt(zellen()\x, zellen()\y)\inhalt=#futter
zellen()\magen+#naehrwert
welt(zellen()\x, zellen()\y)\inhalt=#leer
EndIf
zellen()\magen-1
If zellen()\magen<=0 ;tja, die zelle ist zu dumm um essen zu finden->tot..nur die besten überleben
DeleteElement(zellen())
Continue
EndIf
;}
;{ Bewegen
;je nachdem was auf dem turingband steht, nachdem die turingmaschine lief, bewegt sich die zelle ein stück
If zellen()\alter>45 ; die erste zeit beweg sich die zelle nach der geburt nicht
If zellen()\band[#hoch_bewegen]
zellen()\y-1
zellen()\magen-1
EndIf
If zellen()\band[#runter_bewegen]
zellen()\y+1
zellen()\magen-1
EndIf
If zellen()\band[#rechts_bewegen]
zellen()\x+1
zellen()\magen-1
EndIf
If zellen()\band[#links_bewegen]
zellen()\x-1
zellen()\magen-1
EndIf
zellen()\x=real_x(zellen()\x); wenn eine zelle über den rand fiel wird sie heir wieder zurecht gerückt
zellen()\y=real_x(zellen()\y)
EndIf
;}
;{ vermehrung
If zellen()\magen >= #futterminimum
zellen()\magen=zellen()\magen/2
mutterzellenspeicheradresse=@zellen()
zellen()\alter=0 ;beide zellen sind wieder jung
AddElement(zellen())
CopyMemory(mutterzellenspeicheradresse, @zellen(), SizeOf(ZELLE)) ;und hier entsteht ein neues leben ;)
For i=1 To umwelt\mutationen ; das hier gleich noch etwas verändert wird
zellen()\zustand[Random(#zustandcount-1)]\eingabezeichen[Random(#abc-1)]\schreiben=Random(#abc-1)
zellen()\zustand[Random(#zustandcount-1)]\eingabezeichen[Random(#abc-1)]\richtung=-1+Random(2)
zellen()\zustand[Random(#zustandcount-1)]\eingabezeichen[Random(#abc-1)]\zielzustand=Random(#zustandcount-1)
If Random(50)=1
zellen()\zustand[Random(#zustandcount-1)]\eingabezeichen[Random(#abc-1)]\zielzustand=#turing_terminationszustand
EndIf
Next
EndIf
;}
Next
EndProcedure
Procedure main()
;unser prozess soll schön im hintergrund laufen und kein anderes programm stören
SetPriorityClass_(GetCurrentProcess_(), #IDLE_PRIORITY_CLASS)
openhauptfenster()
Repeat
Select WindowEvent()
Case #PB_Event_CloseWindow
Select EventWindow()
Case #hauptfenster
;AK
;If MessageRequester("Wirklich beenden?","Sicher, dass sie das Programm beenden wollen?",#PB_MessageRequester_YesNo)=6
End
;EndIf
Case #visualisierungsfenster
stop_visualisierung()
Default
CloseWindow(EventWindow())
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case #hauptfenster_gadget_trackbar_futter
umwelt\essenzusatz=GetGadgetState(#hauptfenster_gadget_trackbar_futter)
update_gui_umweltkontrollen()
Case #hauptfenster_gadget_trackbar_mutationen
umwelt\mutationen=GetGadgetState(#hauptfenster_gadget_trackbar_mutationen)
update_gui_umweltkontrollen()
EndSelect
Case #PB_Event_Menu
Select EventMenu()
Case #hauptfenster_menu_web
;nicht entfernen
SetPriorityClass_(GetCurrentProcess_(), #NORMAL_PRIORITY_CLASS)
ShellExecute_(0,"open","http:\\www.nevu.de","","",#SW_SHOWNORMAL)
SetPriorityClass_(GetCurrentProcess_(), #IDLE_PRIORITY_CLASS)
Case #hauptfenster_menu_visualisierung
If status\visualisierung
stop_visualisierung()
Else
start_visualisierung()
EndIf
Case #hauptfenster_menu_running
If status\running
stop_running()
Else
start_running()
EndIf
Case #hauptfenster_menu_reset
reset()
Case #hauptfenster_menu_speichern
CreateFile(1,"save.save")
ForEach zellen() ;alle zellen in ein file speichern
If WriteData(1,@zellen(),SizeOf(ZELLE))<>SizeOf(ZELLE)
MessageRequester("Fehler","Fehler beim speichern. Nicht genügend festplattenplatz?")
EndIf
Next
CloseFile(1)
Case #hauptfenster_menu_laden
ClearList(zellen())
If OpenFile(1,"save.save")
Repeat ;alle zellen aus einer datei laden
AddElement(zellen())
ReadData(1, @zellen(), SizeOf(ZELLE))
Until Eof(1)
Else
MessageRequester("Fehler","Konnte Savefile nicht öffnen")
EndIf
CloseFile(1)
EndSelect
Case #WM_TIMER
Select EventwParam()
Case #timer_hauptfenster_statistik
SetGadgetText(#hauptfenster_gadget_text_zellenanzahl,Str(CountList(zellen())))
SetGadgetText(#hauptfenster_gadget_text_rundenprosek,Str(statistik\weltzeit-statistik\alteweltzeit))
SetGadgetText(#hauptfenster_gadget_text_weltzeit,Str(statistik\weltzeit))
statistik\alteweltzeit=statistik\weltzeit
EndSelect
Case 0
If status\visualisierung
visualisiere_welt()
EndIf
If status\running
statistik\weltzeit+1
calculate_zellen()
place_food()
Else
Delay(10)
EndIf
EndSelect
ForEver
EndProcedure
umwelt\essenzusatz=30
umwelt\mutationen=1
reset()
main()