import java.awt.Graphics; import java.awt.Font; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.awt.event.ActionListener; import java.awt.Button; import javax.swing.JPanel; import javax.swing.JApplet; import java.awt.image.BufferedImage; /** * Datum: 020220 * ueberschrift: Aufgabe F3, Spiel des Lebens, Simulation * Beschreibung: in einem simplen array wird durch regeln ein "leben" simuliert * Methoden: *- arrayIni (...) *- ausgabe (...) * * * Copyright: (c) 2002 letzte aenderung 0711 * Organisation: I/O-n * @author: pascal.christoph'at'web..de * @version 1.2 * * GEil: es funzt ! * GANZ WICHTIG: nie 2 mal hintereinander auf start drücken ! * dazwischen den thread durch stop anhalten. Danke . * so jetzt muss das ding noch auf eine ordentliche grafische umgebung umgesetzt werden. * am besten : ein applet, ein array-eintrag sei ein punkt auf dem bildschirm, generationen seien * farblich gekennzeichnet. soll schön aussehn :) * * also: da spielt man jahrelang DINGE und ist auch fan von simulationen (wie sim-city). * auch das "spiel des lebens" hab ich mal als 12 jaehriger in meinen 8 bit-computer getippt - und * wunderschoene muster erhalten, die sich aus einem chaos in eine geordnete struktur überführten ! * natürlich muss ich an populousII erinnern, das wohl um die '90 erschien - ein spiel, dass ich, wie * populousI , von "göttern" gemacht dachte! ( man beachte auch die technik: lief auf einer 7,16 mhz cpu!!) * na, und da gab es so katastrophen , die man einsetzen konnte, hiess "swamp". dieser sumpf entwickelte * sich nach den regeln des spiel des lebens: setzte man die sumpf-rechtecke nur richtig, breiteten sie * sich nach allen richtungen aus, entwickelten statische formen, dynamische, oder verschwanden gaenzlich * (natürlich interagierten sie mit der sie umgebenden natur, also felsen, wasser, baeume etc). * ach ja, die goldenen zeiten ... ;) * * * Anmerkung 1: hat man etwas rumexperimentiert, und zyklische verbindungen gefunden, die aus einem chaotischen * haufen von sternchen hervorgegangen sind, und laesst diese nun rückwärts scrollen, so zeigt die anschauung, * dass es sich um non-reversible gesetze handelt. * Anmerkung 2: viele naturgesetze sind non-reversibel. * * ---- * nun, es gibt für die regeln bestimmt mehrere interpretationen. die einfachste ist, dass es sich bei der * definition von nachbarn um nur 4 handelt; es sich also um rechteckig eingeteilte felder handelt. * if so, wird schnell etwas statisches erreicht; die zellen "bewegen" sich meist (?) in zwei phasen und * bleiben aber an einer bestimmten position. * wenn man die felder aber als oktagon definiert und somit nicht nur 4, sondern 8 nachbarn haben kann, * so wird das ganze complexer. habe bisher nur eine statische figur gefunden (aus zwei zellen, taucht * auch beim quadratNachbar auf). andere statische figuren "wandern" über den schirm; hier wäre es interssant, * die welt als kugel zu definieren, so dass eine zelle, die links vom rand verschwindet, rechts wieder * auftaucht. ansonsten bilden sich hier teilweise schöne muster, kristall aehnlich, die auch in etwa so * wachsen. * wie waere es mit einem 12-eck ... ? anderen regeln ? * * --- * die grafische benutzeroberfläche schreitet voran. es ist nun ein jApplet, (das leider nicht als applet * funktioiert :( ) in ein frame eingebettet. es fehlt die richtige implemantation von buttons ; * es soll dem benutzer möglich sein, während der simulation parameter zu verändern. etwa farben, zoom, * restart, ganz neu, muster-wahl, populationsdichte etc. * dazu wird wohl folgende technik anzuwenden sein: * bei meinen experimenten mit der abfrage von buttons ging dies nur dann, wenn die paint() nicht * in einer do-loop schleife ist. es wird kein click registriert :( * also werde ich wohl auf die thread-technik kommen: in einem frame-thread spielt die simulation/ * grafische ausgabe, in dem anderen thread ist die actionListener/Button behandlung. * wende mich dem später zu - lasse das project erst mal ruhn und mache andere HA. * * *---- 06-07 *diverse knöpfe installiert, sim läuft nun in einem thread, dadurch funzt actionListener. *aus jApplet ein applet gemacht, und siehe da: es funzt im browser ! (thx Jan !) *ins netz gestellt : *http://galileo.spaceports.com/sim/AufgabeF3.html *thx spaceports.com für platz und support. *auf leifs wunsch hin nun auch rauszoombar *es fehlt noch: das aussuchen eines ini-musters, relatives zoomen, flackern wegmachen *eigener entwurf eines ini-musters ... * *290204 * flackern weg * *020404 *-noch bunter *-aussserdem sind librarys conkret, ohne wildcards, importiert. *(vielleicht läd es dadurch schneller, oder besser für security ?) *- einige redundante sachen entfernt *-ausklammern der apllication main() *- das random muster ist ja schön :) */ public class SimLife extends JApplet implements ActionListener { //der actionListener ist für menü-dinger Button knopf = new Button("START "); Button zoomKleiner = new Button("+"); Button zoomGrosser = new Button("-"); Button stop = new Button("STOP"); Button clear = new Button("Clear"); Button rndMuster = new Button("Random"); Button dichteMinus = new Button("Dichte-"); Button dichtePlus = new Button("Dichte+"); Button nachbarnVier = new Button("Quadrat"); Button nachbarnAcht = new Button("Oktagon"); static String stri; static int farbe=80,farbe1=10,farbe2=150; int faktor=10,farbe1Faktor=3, farbe2Faktor=5; // 10 , 7 experimentier static double populationsDichte=0.99; // entscheidend für zufallswerte. liegt zwischen 0.0 und 0.99999 ! static int generationen=2000, maxPopulation=400000, zoom=2, nachbarn=8; //, voll=0; JPanel buttonPanel = new JPanel(); // manuell: auswahl kann 1 (rechtecke) oder 4 (String *) sein public static int auswahl=1, xmax=900, ymax=650; // x,y= groesse des array-fensters static Matrix verwaltung = new Matrix(); //damit wirds zur application. entsprechende librarys importieren public static void main(String args[]) {//throws IOException { JFrame fenster = new JFrame("Simulation of some cellular life. Spinfo-Homework number 35 or so, given by Yves Lalande in 2002. Now pepped up :-)"); SimLife alsApplet = new SimLife(); alsApplet.init(); // init methode des Applets alsApplet aufrufen alsApplet.start();// "" fenster.getContentPane().add(alsApplet); // Applet alsApplet wird auf den Frame-Container gestellt fenster.setSize(xmax,ymax+70); // groesse der Fenster-flaeche fenster.setVisible(true); // fenster wird angezeigt fenster.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { // macht fenster schliessbar System.exit(0); } }); } Screen screen; public void init(){ image = new BufferedImage(xmax,ymax,BufferedImage.TYPE_INT_RGB); screen = new Screen(); getContentPane().add(screen); buttonPanel.add(knopf); buttonPanel.add(zoomKleiner); buttonPanel.add(zoomGrosser); buttonPanel.add( stop ); buttonPanel.add( clear ); buttonPanel.add( rndMuster ); // buttonPanel.add( dichteMinus); // buttonPanel.add( dichtePlus); buttonPanel.add( nachbarnVier); buttonPanel.add( nachbarnAcht); rndMuster.setBackground(Color.lightGray); rndMuster.addActionListener(this); knopf.setBackground(Color.green); knopf.addActionListener(this); zoomKleiner.addActionListener(this); zoomKleiner.setBackground(Color.lightGray); zoomGrosser.addActionListener(this); zoomGrosser.setBackground(Color.lightGray); stop.addActionListener(this); stop.setBackground(Color.red); clear.addActionListener(this); clear.setBackground(Color.lightGray); dichteMinus.addActionListener(this); dichteMinus.setBackground(Color.lightGray); dichtePlus.addActionListener(this); dichtePlus.setBackground(Color.lightGray); nachbarnVier.addActionListener(this); nachbarnVier.setBackground(Color.lightGray); nachbarnAcht.addActionListener(this); nachbarnAcht.setBackground(Color.lightGray); buttonPanel.setBackground(Color.black); getContentPane().add("North", buttonPanel); simuPaint = new SimuPaint(); // neuer thread instantiiert verwaltung=Muster.arrayMuster5(); // vordefiniert } BufferedImage image; // globales bild class Screen extends JPanel { Screen() { this.setBackground(Color.black); this.setDoubleBuffered(false); this.setVerifyInputWhenFocusTarget(false); } public void paint(Graphics g) { g.drawImage(image,0,0,null); } public void update(Graphics g){ paint(g); // überschreiben, statt (default) hintergrund löschen } } private boolean running =false; SimuPaint simuPaint; public void actionPerformed(ActionEvent ae) { // ae ist variable typs ActionEvent if (ae.getSource()==knopf) { verwaltung=Muster.arrayMuster5(); // vordefiniert if(running=true) simuPaint.stop(); simuPaint = new SimuPaint(); simuPaint.start(); } if (ae.getSource()==zoomKleiner) zoom++; if (ae.getSource()==zoomGrosser){ if (zoom>1) zoom--; } if (ae.getSource()==stop){ if(running=true) simuPaint.stop(); } if (ae.getSource()==clear){ if(running=true) simuPaint.stop(); simuPaint.clear(); image = new BufferedImage(xmax,ymax,BufferedImage.TYPE_INT_RGB); } if (ae.getSource()==dichteMinus){ if (populationsDichte>0) populationsDichte = populationsDichte-0.1; } if (ae.getSource()==dichtePlus){ if (populationsDichte>0) populationsDichte = populationsDichte+0.1; } if (ae.getSource()==nachbarnVier) nachbarn=4; if (ae.getSource()==nachbarnAcht) nachbarn=8; if (ae.getSource()==rndMuster){ // simuPaint.clear(); // image = new BufferedImage(xmax,ymax,BufferedImage.TYPE_INT_RGB); if(running=true) simuPaint.stop(); verwaltung=Muster.arrayRandom(populationsDichte); // vordefiniert simuPaint = new SimuPaint(); simuPaint.start(); } } public class SimuPaint extends Thread { Evolution evolution = new Evolution(); SimuPaint() { setDaemon(true); // thread mit hoher priorität und als daemon setPriority(9); } public void beenden(){ running=false; } void clear(){ Graphics g = getGraphics(); g.setColor(Color.black); g.fillRect(0,0,xmax,ymax); } public void run() { Color color=Color.black; int pixel= (zoom)*4; Graphics g = image.createGraphics(); g.setFont(new Font("Helvetica", Font.BOLD,(pixel))); while(running) { // voll=0; // verwaltung=arrayInit(populationsDichte); // für zufalls-welt //verwaltung=arraySolo(populationsDichte); // ausgabe des arrays, um muster nachvollziehen zu koennen /* for (int y=0; y < 5 ; y++) { // durchlaufen des 2d-arrays; erst y-achse, dann x achse for (int x=0; x < 5; x++) { // da die raender false sein sollen,start 1, ende -1 if ( verwaltung.verwaltungsMatrix[x][y]) { g.drawString(x, x*6,670+y*6); g.drawString(",", x*6,670+y*6); g.drawString(y, x*6,670+y*6); } } } */ if (auswahl==1){ for (int i=0; i=240 || farbe<=10) faktor=faktor*-1; if (farbe1 >=240 || farbe1<=11) farbe1Faktor=farbe1Faktor*-1; if (farbe2 >=240 || farbe2<=11) farbe2Faktor=farbe2Faktor*-1; // g.setColor(Color.black); // g.fillRect(0,35,xmax,ymax); // "löschen" des grafikbildschirms int forXMax=(Matrix.x)/zoom; int forYMax=(Matrix.y)/zoom; color = new Color(farbe1,farbe,farbe2); for (int x=0; x< forXMax; x++){ // durchlaufen des 2d-arrays; erst x-achse for (int y=40/zoom;y< forYMax; y++) { // dann y achse if (verwaltung.verwaltungsMatrix[x][y]) { g.setXORMode(getBackground()); g.setColor(color); // g.setColor(Color.blue); g.fillRect(x*zoom,y*zoom,zoom,zoom); // voll++; } // diese löschfunktion dauert zu lange /* else { g.setColor(Color.black); g.drawRect(x*zoom,y*zoom,zoom*2,zoom*2); } */ } } if (nachbarn == 4) evolution.evolutionNachbarn4(); if (nachbarn == 8) evolution.evolutionNachbarn8(); screen.repaint(); } } if (auswahl==4) { for (int i=0; i octagon. nicht nur 3*2-2 => quadrat // folglich müssen 8 felder durch ifs abgefragt werden int ymax= Matrix.y/SimLife.zoom-1; // fuer for-schleife s.unten int xmax = Matrix.x/SimLife.zoom-1; public void evolutionNachbarn8() { Matrix generation = new Matrix(); int nachbar =0; for (int y=1; y < Matrix.y/SimLife.zoom-1 ; y++) { // durchlaufen des 2d-arrays; erst y-achse for (int x=1; x < Matrix.x/SimLife.zoom-1 ; x++) { // durchlaufen des 2d-arrays; erst y-achse if (SimLife.verwaltung.verwaltungsMatrix[x-1][y-1]) // wenn links oben einer ist nachbar=nachbar+1; if (SimLife.verwaltung.verwaltungsMatrix[x][y-1]) // wenn oben einer ist nachbar=nachbar+1; if (SimLife.verwaltung.verwaltungsMatrix[x+1][y-1]) // wenn rechts oben einer ist nachbar=nachbar+1; if (SimLife.verwaltung.verwaltungsMatrix[x-1][y]) // wenn links einer ist nachbar=nachbar+1; if (SimLife.verwaltung.verwaltungsMatrix[x+1][y]) // wenn rechts einer ist nachbar=nachbar+1; if (SimLife.verwaltung.verwaltungsMatrix[x-1][y+1]) // wenn links unten einer ist nachbar=nachbar+1; if (SimLife.verwaltung.verwaltungsMatrix[x][y+1]) // wenn unten einer ist nachbar=nachbar+1; if (SimLife.verwaltung.verwaltungsMatrix[x+1][y+1]) // wenn rechts unten einer ist nachbar=nachbar+1; // auswertung der nachbarschaftsverhältnisse if (nachbar <=1) // vereinsamungsTod generation.verwaltungsMatrix[x][y]=false; if ((SimLife.verwaltung.verwaltungsMatrix[x][y]==false) && nachbar ==2) {// 2 elter erzeugen ... generation.verwaltungsMatrix[x][y]=true; // ... NACHWUCHS ! } if (nachbar >=3) // stressTod generation.verwaltungsMatrix[x][y]=false; nachbar=0; // reinitialisieren nicht vergessen ! (du dost ;)) } } SimLife.verwaltung=generation; } public void evolutionNachbarn4() { Matrix generation = new Matrix(); int nachbar =0; for (int y=1; y < ymax ; y++) { // durchlaufen des 2d-arrays; erst y-achse for (int x=1; x < xmax ; x++) { // durchlaufen des 2d-arrays; erst y-achse if (SimLife.verwaltung.verwaltungsMatrix[x][y-1]) // wenn oben einer ist nachbar=nachbar+1; if (SimLife.verwaltung.verwaltungsMatrix[x-1][y]) // wenn links einer ist nachbar=nachbar+1; if (SimLife.verwaltung.verwaltungsMatrix[x+1][y]) // wenn rechts einer ist nachbar=nachbar+1; if (SimLife.verwaltung.verwaltungsMatrix[x][y+1]) // wenn unten einer ist nachbar=nachbar+1; // auswertung der nachbarschaftsverhältnisse if (nachbar <=1) // vereinsamungsTod generation.verwaltungsMatrix[x][y]=false; if ((SimLife.verwaltung.verwaltungsMatrix[x][y]) && nachbar ==2) {// 2 elter erzeugen ... generation.verwaltungsMatrix[x][y]=true; // ... NACHWUCHS ! } if (nachbar >=3) // stressTod generation.verwaltungsMatrix[x][y]=false; nachbar=0; // reinitialisieren nicht vergessen ! (du dost ;)) } } SimLife.verwaltung=generation; } } //classe der Matrix für die simulation class Matrix { static final int x=SimLife.xmax, y=SimLife.ymax; // die groesse der matrix boolean[][] sternchenMatrix = new boolean[x-2][y-2]; // die eigentliche populationsmatrix boolean[][] verwaltungsMatrix = new boolean[x][y]; // ränder, damit das berechnen einfacher ist } class Muster { // initialisiert eine neue Matrix.sternchenmatrix mit zufallswerten, die von der globalen // double populationsDichte bestimmt ist static Matrix verwaltung = new Matrix(); public static Matrix arrayRandom(double populationsDichte) { Matrix verwaltung = new Matrix(); for (int y=1; y < Matrix.y-1 ; y++) { // durchlaufen des 2d-arrays; erst y-achse, dann x achse for (int x=1; x < Matrix.x-1; x++) { // da die raender false sein sollen,start 1, ende -1 if (Math.random() > populationsDichte) // zufallswert entscheidet ueber populationsDichte verwaltung.verwaltungsMatrix[x][y]=true; } } return verwaltung; } // initialisiert neue matrix mit zufallswerten, allerdings nur central. // daurch einzelne musterbildungen besser beobachtbar, da von aussen unbeeinflusst // kasten von 5*5 public static Matrix arraySolo(double populationsDichte) { Matrix verwaltung = new Matrix(); for (int y=(int) ((Matrix.y/2-10)); y < (int) ((Matrix.y/2+10)) ; y++) { // durchlaufen des 2d-arrays; erst y-achse, dann x achse // die zoom werte realtivieren die groesse for (int x=(int) ((Matrix.x/2-10)); x < (int) ((Matrix.x/2+10)); x++) { // da die raender false sein sollen,start 1, ende -1 if (Math.random() > populationsDichte) // zufallswert entscheidet ueber populationsDichte verwaltung.verwaltungsMatrix[x][y]=true; } } return verwaltung; } // entworfene muster. funzen nur mit der Matrix "evolutionNachbarn8" public static Matrix arrayMuster2() { Matrix verwaltung = new Matrix(); verwaltung.verwaltungsMatrix[Matrix.x/2-2][Matrix.y/2-2]=true; verwaltung.verwaltungsMatrix[Matrix.x/2][Matrix.y/2]=true; verwaltung.verwaltungsMatrix[Matrix.x/2+2][Matrix.y/2+2]=true; verwaltung.verwaltungsMatrix[Matrix.x/2-2][Matrix.y/2+2]=true; return verwaltung; } public static Matrix arrayMuster3() { Matrix verwaltung = new Matrix(); verwaltung.verwaltungsMatrix[Matrix.x/2-2][Matrix.y/2-2]=true; verwaltung.verwaltungsMatrix[Matrix.x/2-2][Matrix.y/2-1]=true; verwaltung.verwaltungsMatrix[Matrix.x/2-2][Matrix.y/2+2]=true; verwaltung.verwaltungsMatrix[Matrix.x/2-2][Matrix.y/2+1]=true; verwaltung.verwaltungsMatrix[Matrix.x/2-2][Matrix.y/2]=true; return verwaltung; } public static Matrix arrayMuster4() { Matrix verwaltung = new Matrix(); verwaltung.verwaltungsMatrix[Matrix.x/2][Matrix.y/2-2]=true; verwaltung.verwaltungsMatrix[Matrix.x/2][Matrix.y/2-1]=true; verwaltung.verwaltungsMatrix[Matrix.x/2][Matrix.y/2]=true; verwaltung.verwaltungsMatrix[Matrix.x/2][Matrix.y/2+1]=true; return verwaltung; } public static Matrix arrayMuster5() { // **** // * * geiler anfang ! // **** wieder mal , thx Jan Matrix verwaltung = new Matrix(); verwaltung.verwaltungsMatrix[(int)(Matrix.x/(2*SimLife.auswahl*SimLife.zoom))][(int)Matrix.y/(2*SimLife.auswahl*SimLife.zoom)]=true; verwaltung.verwaltungsMatrix[(int)(Matrix.x/(2*SimLife.auswahl*SimLife.zoom))+1][(int)Matrix.y/(2*SimLife.auswahl*SimLife.zoom)]=true; verwaltung.verwaltungsMatrix[(int)(Matrix.x/(2*SimLife.auswahl*SimLife.zoom))+2][(int)Matrix.y/(2*SimLife.auswahl*SimLife.zoom)]=true; verwaltung.verwaltungsMatrix[(int)(Matrix.x/(2*SimLife.auswahl*SimLife.zoom))+3][(int)Matrix.y/(2*SimLife.auswahl*SimLife.zoom)]=true; verwaltung.verwaltungsMatrix[(int)(Matrix.x/(2*SimLife.auswahl*SimLife.zoom))][(int)Matrix.y/(2*SimLife.auswahl*SimLife.zoom)+1]=true; verwaltung.verwaltungsMatrix[(int)(Matrix.x/(2*SimLife.auswahl*SimLife.zoom))+3][(int)Matrix.y/(2*SimLife.auswahl*SimLife.zoom)+1]=true; verwaltung.verwaltungsMatrix[(int)(Matrix.x/(2*SimLife.auswahl*SimLife.zoom))][(int)Matrix.y/(2*SimLife.auswahl*SimLife.zoom)+2]=true; verwaltung.verwaltungsMatrix[(int)(Matrix.x/(2*SimLife.auswahl*SimLife.zoom))+1][(int)Matrix.y/(2*SimLife.auswahl*SimLife.zoom)+2]=true; verwaltung.verwaltungsMatrix[(int)(Matrix.x/(2*SimLife.auswahl*SimLife.zoom))+2][(int)Matrix.y/(2*SimLife.auswahl*SimLife.zoom)+2]=true; verwaltung.verwaltungsMatrix[(int)(Matrix.x/(2*SimLife.auswahl*SimLife.zoom))+3][(int)Matrix.y/(2*SimLife.auswahl*SimLife.zoom)+2]=true; return verwaltung; } //sollte eigentlich stabil sein, aber -?? public static Matrix arrayMuster1() { Matrix verwaltung = new Matrix(); verwaltung.verwaltungsMatrix[Matrix.x/2][Matrix.y/2]=true; verwaltung.verwaltungsMatrix[Matrix.x/2+1][Matrix.y/2-1]=true; return verwaltung; } }