Ergebnis 1 bis 11 von 11

Game of Life

  1. #1 Zitieren
    Auserwählter
    Registriert seit
    Jul 2017
    Beiträge
    6.514
    Ihr kennt sicher diese Simulation.
    http://www.mathematische-basteleien.de/gameoflife.htm

    Man startet mit einer Anzahl Lebewesen und je nachdem, wie viele in der Nachbarschaft sind, bleiben sie am leben, sterben oder es werden neue Lebewesen geschaffen.
    Es ist interessant, was sich daraus für Gebilde entstehen.

    Das ganze läuft auf einem karierten Blatt. Das Lebewesen wird dabei umgeben von 8 Feldern.

    Folgende Regeln gibt es:

    1. Ist die betrachte Zelle besetzt, gilt_
    Das Lebewesen überlebt bei 2 oder 3 Nachbarn.
    Das Lebewesen stirbt bei 0 oder 1 Nachbarn aus Einsamkeit und bei 4 bis 8 Nachbarn wegen Übervölkerung.

    2. Die Zelle ist nicht besetzt.
    Gibt es genau 3 Nachbarn, entsteht in dieser Zelle ein neues Leben.

    Einfache Regeln, große Wirkung.

    Hab hierzu ein kleines Javaprogramm geschrieben mit Fensteroberfläche.

    Habt Spaß beim Testen verschiedener Startwerte. (Entweder den Randombutton nutzen und/oder selbst ins Fenster beliebige Felder anklicken.

    (Probiere gerade so ein paar Javasachen aus, weshalb da derzeit ein bisschen was rüberkommt. Also nicht wundern )

    Class GameofLife
    Code:
    package Haupt;
    
    import java.util.concurrent.TimeUnit;
    
    
    import Fenster.Fenster;
    
    
    public class GameofLife {
        int zeilen, spalten;
        boolean [][]matrix;
        
        public GameofLife(){
            zeilen=10; spalten=10;
            matrix=new boolean[zeilen][spalten];
            
            for(int i=0;i<10;i++)
                for(int j=0;j<10;j++)matrix[i][j]=false;
        }
        
        public GameofLife(int zeilen, int spalten) {
            this.zeilen=zeilen; this.spalten=spalten;
            
            try {
            matrix=new boolean[zeilen][spalten];
            } catch(Exception e) {
                System.out.println("Fehler bei Erstellung des Feldes!");
                System.out.println("Mache mit Standarddaten weiter");
                
                this.zeilen=10; this.spalten=10;
            }
            
            for(int i=0;i<zeilen;i++)
                for(int j=0;j<spalten;j++)matrix[i][j]=false;
    
    
        }
        
        void set_matrix(int zeile, int spalte, boolean setzen) {
            matrix[zeile][spalte]=setzen;
        }
        
        boolean all_false() {
            for(int i=0;i<zeilen;i++)
                for(int j=0;j<spalten;j++)if(matrix[i][j])return false;
            
            return true;
        }
        
        boolean zug() {
            int zaehler=0;
            boolean [][]tausch=new boolean[zeilen][spalten];
            boolean geändert=false;
            
            for(int i=0;i<zeilen;i++)
                for(int j=0;j<spalten;j++)
                    tausch[i][j]=matrix[i][j];
            
            for(int i=0;i<zeilen;i++) {
                for (int j=0;j<spalten;j++) {
                    if(i-1>-1) {
                        if(matrix[i-1][j])zaehler++;
                        if(j-1>-1)if(matrix[i-1][j-1])zaehler++;
                        if(j+1<spalten)if(matrix[i-1][j+1])zaehler++;
                        }
                    if(j-1>-1)if(matrix[i][j-1])zaehler++;
                    if(j+1<spalten)if(matrix[i][j+1])zaehler++;
                    if(i+1<zeilen) {
                        if(matrix[i+1][j])zaehler++;
                        if(j-1>-1)if(matrix[i+1][j-1])zaehler++;
                        if(j+1<spalten)if(matrix[i+1][j+1])zaehler++;
                        }
                    if(matrix[i][j]) {
                        if(zaehler>1&&zaehler<4)tausch[i][j]=true;
                        else tausch[i][j]=false;
                    }
                    else if(zaehler==3)tausch[i][j]=true;
    
    
                    zaehler=0;
                }
            }
            
            for(int i=0;i<zeilen;i++)
                for(int j=0;j<spalten;j++) {
                    if(matrix[i][j]!=tausch[i][j])geändert=true;
                    matrix[i][j]=tausch[i][j];
                }
            return geändert;
        }
    }
    
    
    class Mainframe{
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
    
            boolean erstellt=false;
            int zeit=0;
            int zyklus=0;
            Fenster z=new Fenster();
            
            
            while(true) {
                while(!z.get_start()) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                };
                
                if(!erstellt) {
                    z.set_start(false);
                    GameofLife a=new GameofLife(z.get_zeilen(), z.get_spalten());
                    zeit=z.get_milli();
                    for(int i=0;i<z.get_zeilen();i++)
                        for(int j=0;j<z.get_spalten();j++)
                            a.set_matrix(i, j, z.get_feld(i, j));
                    
                    erstellt=true;
                    while(!a.all_false()&&!z.get_neu() &&a.zug()){
                        //a.zug();
                        z.set_zyklus(++zyklus);
                        for(int i=0;i<z.get_zeilen();i++)
                            for(int j=0;j<z.get_spalten();j++)
                                z.set_feld(i,j,a.matrix[i][j]);
    
    
                        try {
                            TimeUnit.MILLISECONDS.sleep(zeit);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    while(z.get_neu()) {
                        z.set_neu(false);
                        try {
                            TimeUnit.MILLISECONDS.sleep(500);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    erstellt=false;
                    zyklus=0;
                }
            }
        }
        
    }
    class Fenster
    Code:
    package Fenster;
    
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Toolkit;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.util.Random;
    
    
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    
    
    
    
    public class Fenster implements MouseListener{
            
    //globale Konstanten
    final static int FENSTERBREITE=800;
    final static int FENSTERHOEHE=700;
                
    JFrame jframe;
    JPanel jp=new JPanel();
    JPanel jp_hauptpanel=new JPanel();
    JPanel jp_dimension=new JPanel();
    JPanel jp_zeit=new JPanel();
    JPanel jp_zufall=new JPanel();
    JPanel jp_spielfeld=new JPanel();
    JButton[][] jb_matrix;
    JButton jb_dim=new JButton("Ok");
    JButton jb_zeit=new JButton("Ok");
    JButton jb_zufall=new JButton("Ok");
    JButton jb_start=new JButton("Start");
    JButton jb_neu=new JButton("Neu");
    JTextField jt_x=new JTextField("10");
    JTextField jt_y=new JTextField("10");
    JTextField jt_zeit=new JTextField("500");
    JTextField jt_zufall=new JTextField("20");
    JLabel jl_dim=new JLabel("Spielfelddimension");
    JLabel jl_zeit=new JLabel("Zeit");
    JLabel jl_milli=new JLabel("Millisekunden");
    JLabel jl_zeilen=new JLabel("Anzahl Zeilen");
    JLabel jl_spalten=new JLabel("Anzahl Spalten");
    JLabel jl_zufall=new JLabel("Belegung per Zufall");
    JLabel jl_wieviel_felder=new JLabel("Wieviele Felder");
    JLabel jl_zyklus=new JLabel("Zyklus :");
    JLabel jl_zyklus1=new JLabel("0");
    
    
    boolean start=false, neu=false;
    int zeilen=10; int spalten=10;
    int milli=500;
    Color color;
    boolean [][] matrix;
                
    public    Fenster(){
    
    
        jframe=new JFrame("Game of Life");
        JFrame.setDefaultLookAndFeelDecorated(true);
    
    
        jframe.pack();
                
        jframe.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                
    
    
        jframe.setBounds(Toolkit.getDefaultToolkit().getScreenSize().width/2 - FENSTERBREITE/2, 
                         Toolkit.getDefaultToolkit().getScreenSize().height/2-FENSTERHOEHE/2, 
                         FENSTERBREITE, FENSTERHOEHE);
                
        jframe.setResizable(false);
                
        //Listener fuer Window- und key_events hinzufuegen
        jframe.addWindowListener(new WindowClosingAdapter());
                
        jframe.setLayout(new java.awt.GridLayout(1, 1));
        Font font=new Font("Arial",Font.PLAIN,10);
        
        jb_matrix=new JButton[zeilen][spalten];
                
        matrix=new boolean[zeilen][spalten];
        for(int i=0;i<zeilen;i++)
               for(int j=0;j<spalten;j++){
                   matrix[i][j]=false;
                   jb_matrix[i][j]=new JButton();
                   jb_matrix[i][j].addMouseListener(this);
                   jb_matrix[i][j].setFocusable(false);
               }
        
        color=jb_matrix[0][0].getBackground();
                
               jp_spielfeld=new JPanel();
               jp_spielfeld.setBounds(5, 5, 600, 600);
               jp_spielfeld.setLayout(new java.awt.GridLayout(zeilen, spalten));
               jp_spielfeld.setBorder(BorderFactory.createLineBorder( Color.black ));
                
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++){
                jp_spielfeld.add(jb_matrix[i][j]);
            }
        jl_dim.setBounds(3, 3, 100, 20);
        jl_dim.setFont(font);
        
        jl_zeilen.setBounds(3, 30, 90, 20);
        jl_zeilen.setFont(font);
        jt_x.setBounds(95, 30, 50, 20);
        jt_x.setHorizontalAlignment(JTextField.RIGHT);
        jt_x.setFont(font);
    
    
        jl_spalten.setBounds(3, 55, 90, 20);
        jl_spalten.setFont(font);
        jt_y.setBounds(95, 55, 50, 20);
        jt_y.setHorizontalAlignment(JTextField.RIGHT);
        jt_y.setFont(font);
    
    
        jb_dim.setBounds(95, 90,50,20);
        jb_dim.setFont(font);
        jb_dim.addMouseListener(this);
    
    
        
        jp_dimension.setLayout(null);
        jp_dimension.setBounds(620, 5,150,130);
           jp_dimension.setBorder(BorderFactory.createLineBorder( Color.black ));
           jp_dimension.add(jl_dim);
           jp_dimension.add(jl_zeilen);
           jp_dimension.add(jt_x);
           jp_dimension.add(jl_spalten);
           jp_dimension.add(jt_y);
           jp_dimension.add(jb_dim);
    
    
        jl_zufall.setBounds(3, 3, 100, 20);
        jl_zufall.setFont(font);
        
        jl_wieviel_felder.setBounds(3, 30, 90, 20);
        jl_wieviel_felder.setFont(font);
        jt_zufall.setBounds(95, 30, 50, 20);
        jt_zufall.setHorizontalAlignment(JTextField.RIGHT);
        jt_zufall.setFont(font);
    
    
        jb_zufall.setBounds(95, 60,50,20);
        jb_zufall.setFont(font);
        jb_zufall.addMouseListener(this);
    
    
        jp_zufall.setLayout(null);
        jp_zufall.setBounds(620, 140,150,100);
           jp_zufall.setBorder(BorderFactory.createLineBorder( Color.black ));
        jp_zufall.add(jl_zufall);
        jp_zufall.add(jl_wieviel_felder);
        jp_zufall.add(jt_zufall);
        jp_zufall.add(jb_zufall);
        
        jl_zeit.setBounds(3, 3, 100, 20);
        jl_zeit.setFont(font);
        
        jl_milli.setBounds(3, 30, 90, 20);
        jl_milli.setFont(font);
        jt_zeit.setBounds(95, 30, 50, 20);
        jt_zeit.setHorizontalAlignment(JTextField.RIGHT);
        jt_zeit.setFont(font);
    
    
        jb_zeit.setBounds(95, 60,50,20);
        jb_zeit.setFont(font);
        jb_zeit.addMouseListener(this);
    
    
        jp_zeit.setLayout(null);
        jp_zeit.setBounds(620, 245,150,100);
           jp_zeit.setBorder(BorderFactory.createLineBorder( Color.black ));
        jp_zeit.add(jl_zeit);
        jp_zeit.add(jl_milli);
        jp_zeit.add(jt_zeit);
        jp_zeit.add(jb_zeit);
        
        font=new Font("Arial",Font.BOLD,20);
        jb_neu.setBounds(650, 510,100,40);
        jb_neu.setFont(font);
        jb_neu.addMouseListener(this);
    
    
        jb_start.setBounds(650, 560,100,40);
        jb_start.setFont(font);
        jb_start.addMouseListener(this);
        
        jl_zyklus.setBounds(200, 620, 90, 30);
        jl_zyklus.setFont(font);
        jl_zyklus1.setBounds(295, 620, 50, 30);
        jl_zyklus1.setHorizontalAlignment(JLabel.RIGHT);
        jl_zyklus1.setFont(font);
    
    
        
        
        jp_hauptpanel.setLayout(null);
        jp_hauptpanel.setBounds(5, 5,590,590);
           jp_hauptpanel.setBorder(BorderFactory.createLineBorder( Color.black ));
           jp_hauptpanel.add(jp_spielfeld);
           jp_hauptpanel.add(jp_dimension);
           jp_hauptpanel.add(jp_zufall);
           jp_hauptpanel.add(jp_zeit);
           jp_hauptpanel.add(jb_neu);
           jp_hauptpanel.add(jb_start);
           jp_hauptpanel.add(jl_zyklus);
           jp_hauptpanel.add(jl_zyklus1);
           
           
        jframe.add(jp_hauptpanel);
        jframe.setVisible(true);
        }
    
    
    void set_zufallsfelder() {
        try {
        Random zufall=new Random();
        int anzahl=Integer.parseInt(jt_zufall.getText());
        
        if(anzahl>zeilen*spalten/2)throw new MehrRandomFelderalsMatrixfelder();
        
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++)
                matrix[i][j]=false;
        
        for(int i=0;i<anzahl+1;i++) {
            matrix[zufall.nextInt(zeilen)][ zufall.nextInt(spalten)]= true;
        }
        
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++)
                if(matrix[i][j])jb_matrix[i][j].setBackground(Color.BLUE);
                else jb_matrix[i][j].setBackground(color);
        } catch(Exception e) {
            
            if(e.getMessage().equals("Die Anzahl der Randomfelder ist größer, als die Anzahl der Matrixfelder")) {
                JOptionPane.showMessageDialog(null,"Anzahl > Anzahl Felder Spielfeld","Maximal x*y/2", JOptionPane.INFORMATION_MESSAGE);
                jt_zufall.setText(Integer.toString(20));
            }
            else {
                JOptionPane.showMessageDialog(null,"Bitte Zahl eingeben","Fehlerhafte Eingabe", JOptionPane.INFORMATION_MESSAGE);
                jt_zufall.setText(Integer.toString(20));
            }
        }
    }
    
    
    public void set_feld(int zeile, int spalte, boolean zustand) {
        matrix[zeile][spalte]=zustand;
        if(matrix[zeile][spalte])jb_matrix[zeile][spalte].setBackground(Color.BLUE);
        else jb_matrix[zeile][spalte].setBackground(color);
    }
    
    
    public boolean get_feld(int zeile, int spalte) {
        return matrix[zeile][spalte];
    }
    
    
    public void set_zyklus(int i) {
        jl_zyklus1.setText(Integer.toString(i));
    }
    
    
    public void set_start(boolean zustand) {
        start=zustand;
    }
    
    
    public void set_neu(boolean zustand) {
        neu=zustand;
    }
    
    
    void reset_spielfeld() {
        set_neu(true);
        jl_zyklus1.setText(Integer.toString(0));
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++) {
                matrix[i][j]=false;
                jb_matrix[i][j].setBackground(color);
            }
        set_start(false);
    }
    
    
    public boolean get_start() {
        return start;
    }
    
    
    public boolean get_neu() {
        return neu;
    }
    void set_milli() {
        try {
        milli=Integer.parseInt(jt_zeit.getText());
        if(milli<0) {
            milli=milli*(-1);
            jt_zeit.setText(Integer.toString(milli));
        }
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null,"Bitte Zahl eingeben","Fehlerhafte Eingabe", JOptionPane.INFORMATION_MESSAGE);
            jt_zeit.setText(Integer.toString(milli));
        }
    }
    
    
    public int get_milli(){
        return milli;
    }
    
    
    public int get_zeilen() {
        return zeilen;
    }
    
    
    public int get_spalten() {
        return spalten;
    }
    
    
    void set_spielfeld() {
        
        try {
        zeilen=Integer.parseInt(jt_x.getText());
        spalten=Integer.parseInt(jt_y.getText());
        
        if(zeilen>3&&spalten>3&&zeilen<100&&spalten<100) {
        
        set_start(false);
        
        jp_spielfeld.removeAll();
        jp_hauptpanel.remove(jp_spielfeld);
        
        jframe.revalidate();
        jframe.repaint();
        
        jb_matrix=new JButton[zeilen][spalten];
        matrix=new boolean[zeilen][spalten];
    
    
        for(int i=0;i<zeilen;i++)
               for(int j=0;j<spalten;j++){
                   matrix[i][j]=false;
                   jb_matrix[i][j]=new JButton();
                   jb_matrix[i][j].addMouseListener(this);
                   jb_matrix[i][j].setFocusable(false);
               }
             
            jp_spielfeld=new JPanel();
            jp_spielfeld.revalidate();
            jp_spielfeld.repaint();
    
    
            jp_spielfeld.setBounds(5, 5, 600, 600);
               jp_spielfeld.setLayout(new java.awt.GridLayout(zeilen, spalten));
               jp_spielfeld.setBorder(BorderFactory.createLineBorder( Color.black ));
                
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++){
                jp_spielfeld.add(jb_matrix[i][j]);
            }
        
        jp_hauptpanel.add(jp_spielfeld);
        jframe.validate();
        }
        else {
            JOptionPane.showMessageDialog(null,"Dimension muss > 3 und < 100 sein","Fehlerhafte Dimension", JOptionPane.INFORMATION_MESSAGE);
            zeilen=matrix.length;spalten=matrix[0].length;
            jt_x.setText(Integer.toString(zeilen));
            jt_y.setText(Integer.toString(spalten));
        }
        } catch(Exception e) {
            JOptionPane.showMessageDialog(null,"Dimension muss  eine ganze Zahl sein","Ganze Zahlen von 3 bis 100", JOptionPane.INFORMATION_MESSAGE);
            zeilen=matrix.length;spalten=matrix[0].length;
            jt_x.setText(Integer.toString(zeilen));
            jt_y.setText(Integer.toString(spalten));
        }
    }
            
    private void beenden()    {    
        jframe.setVisible(false);
        jframe.dispose();
        System.exit(0);
    }
    
    
    /*Wenn Window schließen durch X erfolgt, wird
     * Fenster mit beenden() geschlossen
     */    
    class WindowClosingAdapter     extends WindowAdapter {
          public void windowClosing(WindowEvent event)
          {beenden();}
    }
    
    
    @Override
    public void mouseClicked(MouseEvent arg0){
            
        if(arg0.getSource() == this.jb_zufall){
            set_zufallsfelder();
        }
    
    
        if(arg0.getSource() == this.jb_dim){
            set_spielfeld();
        }
        
        if(arg0.getSource() == this.jb_zeit){
            set_milli();
        }
        
        if(arg0.getSource() == this.jb_start){
            set_start(true);
        }
    
    
        if(arg0.getSource() == this.jb_neu){
            reset_spielfeld();
        }
    
    
        
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++){
                if(arg0.getSource() == this.jb_matrix[i][j]){
                    if(matrix[i][j]) {
                        matrix[i][j]=false;
                        jb_matrix[i][j].setBackground(color);
                    }
                    else {
                        matrix[i][j]=true;
                        jb_matrix[i][j].setBackground(Color.BLUE);
                    }
                }
            }
        }
    
    
    @Override
    public void mouseEntered(MouseEvent arg0) {
        // TODO Auto-generated method stub
    }
    
    
    @Override
    public void mouseExited(MouseEvent arg0) {
        // TODO Auto-generated method stub
    }
    
    
    @Override
    public void mousePressed(MouseEvent arg0) {
        // TODO Auto-generated method stub
    }
    
    
    @Override
    public void mouseReleased(MouseEvent arg0) {
    
    
        
    }
    
    
    }
    
    
    class MehrRandomFelderalsMatrixfelder extends Exception
    {
        MehrRandomFelderalsMatrixfelder()
        {
            super("Die Anzahl der Randomfelder ist größer, als die Anzahl der Matrixfelder");
        }
    }
    Stiller Leser ist offline Geändert von Stiller Leser (17.06.2018 um 21:10 Uhr)

  2. #2 Zitieren
    Pretty Pink Pony Princess  Avatar von Multithread
    Registriert seit
    Jun 2010
    Ort
    Crystal Empire
    Beiträge
    11.228
    Kleine Herausforderung:
    Das Spielfeld soll Unendlich Gross sein.
    Ziel ist es auf einem beliebigen Startfeld etwas zu setzen und am ende zu schauen wie Sich das ganze weiterentwickelt. ua. ohne das Gleiter und Schiffe, welche davonfliegen 'verloren' gehen.

    Schau mal ob du solch eine Implementation hinbekommst

    Ich werde die Tage ebenfalls eine solche Implementation machen.
    [Bild: AMD_Threadripper.png] Bei Hardware gibt es keine eigene Meinung, bei Hardware zählen nur die Fakten.


    Probleme mit der Haarpracht? Starres Haar ohne Glanz? TressFX schafft Abhilfe. Ja, TressFX verhilft auch Ihnen zu schönem und Geschmeidigen Haar.
    [Bild: i6tfHoa3ooSEraFH63.png]
    Multithread ist offline

  3. #3 Zitieren
    Auserwählter
    Registriert seit
    Jul 2017
    Beiträge
    6.514
    Hm, unendlich groß ist natürlich ein Wort. Und wenn sich dann welche in unterschiedlichen Richtungen fortbewegen, wird es nicht so leicht sein, alle zu verfolgen. Aber grundsätzlich, die sich bewegenden Teile sind nicht all zu groß, da kann man immer ein neues Feld bereitstellen. Mal sehen.
    Stiller Leser ist offline

  4. #4 Zitieren
    Auserwählter
    Registriert seit
    Jul 2017
    Beiträge
    6.514
    Also folgender Vorschlag:

    Unendlich fand ich ein wenig blöd, weil überall fast nichts passiert Ich habe das jetzt so gelöst, dass wenn links überschritten wird, es rechts weiter geht und umgekehrt und wenn es oben nicht weiter geht, unten weiter läuft und umgekehrt.

    Desweiteren habe ich die Maske etwas vergrößert und der Startwert ist jetzt 60 x 60 Zellen.

    Änderung der Methode boolean Zug in der Klasse GameofLife:

    Code:
    boolean zug() {        
     int zaehler=0;
    //neue Matrix und tausch Matrix. Diese ist um 10 Zeilen und Spalten größer, als die eigentliche Matrix. Die eigentliche Matrix wird in die Mitte kopiert, so dass außen jeweils 5 Zeilen und //Spalten frei sind.
            boolean [][]matrix1=new boolean[zeilen+10][spalten+10];
            boolean [][]tausch1=new boolean[zeilen+10][spalten+10];
            boolean geändert=false;
            
            for(int i=0;i<zeilen+10;i++)
                for(int j=0;j<spalten+10;j++)
                    matrix1[i][j]=false;
            
            for(int i=0;i<zeilen;i++)
                for(int j=0;j<spalten;j++) {
                    matrix1[i+5][j+5]=matrix[i][j];
                }
    
    //in den 5 freien Zeilen oben werden die 5 letzten Zeilen von der Hauptmatrix kopiert. In den 5 freien Zeilen unten die 5 ersten der Hauptmatrix.
    //Bei den Spalten passiert selbiges, natürlich mit den ersten und letzten 5 Spalten.
    // Sinn ist es, einen endloslauf zu ermöglichen. Alles was die Hauptmatrix beispielsweise nach oben verlässt, kommt von unten wieder rein.
    
            for(int i=0;i<zeilen;i++) {
                matrix1[i+5][0]=matrix[i][spalten-5];
                matrix1[i+5][1]=matrix[i][spalten-4];
                matrix1[i+5][2]=matrix[i][spalten-3];
                matrix1[i+5][3]=matrix[i][spalten-2];
                matrix1[i+5][4]=matrix[i][spalten-1];
    
    
                matrix1[i+5][spalten+10-1]=matrix[i][4];
                matrix1[i+5][spalten+10-2]=matrix[i][3];
                matrix1[i+5][spalten+10-3]=matrix[i][2];
                matrix1[i+5][spalten+10-4]=matrix[i][1];
                matrix1[i+5][spalten+10-5]=matrix[i][0];
            }
            
            for(int i=0;i<spalten;i++) {
                matrix1[0][i+5]=matrix[zeilen-5][i];
                matrix1[1][i+5]=matrix[zeilen-4][i];
                matrix1[2][i+5]=matrix[zeilen-3][i];
                matrix1[3][i+5]=matrix[zeilen-2][i];
                matrix1[4][i+5]=matrix[zeilen-1][i];
    
    
                matrix1[zeilen+10-1][i+5]=matrix[4][i];
                matrix1[zeilen+10-2][i+5]=matrix[3][i];
                matrix1[zeilen+10-3][i+5]=matrix[2][i];
                matrix1[zeilen+10-4][i+5]=matrix[1][i];
                matrix1[zeilen+10-5][i+5]=matrix[0][i];
            }
            
            for(int i=0;i<zeilen+10;i++) {
                for(int j=0;j<spalten+10;j++) {
                    tausch1[i][j]=matrix1[i][j];
                }
            }
            
            for(int i=0;i<zeilen+10;i++) {
                for (int j=0;j<spalten+10;j++) {
                    if(i-1>-1) {//zeile über zelle
                        if(matrix1[i-1][j])zaehler++;
                        if(j-1>-1)if(matrix1[i-1][j-1])zaehler++;
                        if(j+1<spalten+10)if(matrix1[i-1][j+1])zaehler++;
                        }
                    //zeile der zelle
                    if(j-1>-1)if(matrix1[i][j-1])zaehler++;
                     if(j+1<spalten+10)if(matrix1[i][j+1])zaehler++;
                    
                     if(i+1<zeilen+10) {//zeile unter zelle
                        if(matrix1[i+1][j])zaehler++;
                        if(j-1>-1)if(matrix1[i+1][j-1])zaehler++;
                        if(j+1<spalten+10)if(matrix1[i+1][j+1])zaehler++;
                    }
                    if(matrix1[i][j]) {
                        if(zaehler>1&&zaehler<4)tausch1[i][j]=true;
                        else tausch1[i][j]=false;
                    }
                    else if(zaehler==3)tausch1[i][j]=true;
    
    
                    zaehler=0;
                }
            }
            
            for(int i=0;i<zeilen;i++)
                for(int j=0;j<spalten;j++) {
                    if(matrix[i][j]!=tausch1[i+5][j+5])geändert=true;
                    matrix[i][j]=tausch1[i+5][j+5];
                }
            return geändert;
        }
    Änderung der Klasse Fenster:
    Code:
    package Fenster;
    
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Toolkit;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.util.Random;
    
    
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    
    
    
    
    public class Fenster implements MouseListener{
            
    //globale Konstanten
    final static int FENSTERBREITE=1070;
    final static int FENSTERHOEHE=950;
                
    JFrame jframe;
    JPanel jp=new JPanel();
    JPanel jp_hauptpanel=new JPanel();
    JPanel jp_dimension=new JPanel();
    JPanel jp_zeit=new JPanel();
    JPanel jp_zufall=new JPanel();
    JPanel jp_spielfeld=new JPanel();
    JButton[][] jb_matrix;
    JButton jb_dim=new JButton("Ok");
    JButton jb_zeit=new JButton("Ok");
    JButton jb_zufall=new JButton("Ok");
    JButton jb_start=new JButton("Start");
    JButton jb_neu=new JButton("Neu");
    JTextField jt_x=new JTextField("60");
    JTextField jt_y=new JTextField("60");
    JTextField jt_zeit=new JTextField("500");
    JTextField jt_zufall=new JTextField("20");
    JLabel jl_dim=new JLabel("Spielfelddimension");
    JLabel jl_zeit=new JLabel("Zeit");
    JLabel jl_milli=new JLabel("Millisekunden");
    JLabel jl_zeilen=new JLabel("Anzahl Zeilen");
    JLabel jl_spalten=new JLabel("Anzahl Spalten");
    JLabel jl_zufall=new JLabel("Belegung per Zufall");
    JLabel jl_wieviel_felder=new JLabel("Wieviele Felder");
    JLabel jl_zyklus=new JLabel("Zyklus :");
    JLabel jl_zyklus1=new JLabel("0");
    
    
    boolean start=false, neu=false;
    int zeilen=60; int spalten=60;
    int milli=500;
    Color color;
    boolean [][] matrix;
                
    public    Fenster(){
    
    
        jframe=new JFrame("Game of Life");
        JFrame.setDefaultLookAndFeelDecorated(true);
    
    
        jframe.pack();
                
        jframe.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                
    
    
        jframe.setBounds(Toolkit.getDefaultToolkit().getScreenSize().width/2 - FENSTERBREITE/2, 
                         Toolkit.getDefaultToolkit().getScreenSize().height/2-FENSTERHOEHE/2, 
                         FENSTERBREITE, FENSTERHOEHE);
                
        jframe.setResizable(false);
                
        //Listener fuer Window- und key_events hinzufuegen
        jframe.addWindowListener(new WindowClosingAdapter());
                
        jframe.setLayout(new java.awt.GridLayout(1, 1));
        Font font=new Font("Arial",Font.PLAIN,10);
        
        jb_matrix=new JButton[zeilen][spalten];
                
        matrix=new boolean[zeilen][spalten];
        for(int i=0;i<zeilen;i++)
               for(int j=0;j<spalten;j++){
                   matrix[i][j]=false;
                   jb_matrix[i][j]=new JButton();
                   jb_matrix[i][j].addMouseListener(this);
                   jb_matrix[i][j].setFocusable(false);
               }
        
        color=jb_matrix[0][0].getBackground();
                
               jp_spielfeld=new JPanel();
               jp_spielfeld.setBounds(5, 5, 850, 850);
               jp_spielfeld.setLayout(new java.awt.GridLayout(zeilen, spalten));
               jp_spielfeld.setBorder(BorderFactory.createLineBorder( Color.black ));
                
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++){
                jp_spielfeld.add(jb_matrix[i][j]);
            }
        jl_dim.setBounds(3, 3, 100, 20);
        jl_dim.setFont(font);
        
        jl_zeilen.setBounds(3, 30, 90, 20);
        jl_zeilen.setFont(font);
        jt_x.setBounds(95, 30, 50, 20);
        jt_x.setHorizontalAlignment(JTextField.RIGHT);
        jt_x.setFont(font);
    
    
        jl_spalten.setBounds(3, 55, 90, 20);
        jl_spalten.setFont(font);
        jt_y.setBounds(95, 55, 50, 20);
        jt_y.setHorizontalAlignment(JTextField.RIGHT);
        jt_y.setFont(font);
    
    
        jb_dim.setBounds(95, 90,50,20);
        jb_dim.setFont(font);
        jb_dim.addMouseListener(this);
    
    
        
        jp_dimension.setLayout(null);
        jp_dimension.setBounds(860, 5,190,130);
           jp_dimension.setBorder(BorderFactory.createLineBorder( Color.black ));
           jp_dimension.add(jl_dim);
           jp_dimension.add(jl_zeilen);
           jp_dimension.add(jt_x);
           jp_dimension.add(jl_spalten);
           jp_dimension.add(jt_y);
           jp_dimension.add(jb_dim);
    
    
        jl_zufall.setBounds(3, 3, 100, 20);
        jl_zufall.setFont(font);
        
        jl_wieviel_felder.setBounds(3, 30, 90, 20);
        jl_wieviel_felder.setFont(font);
        jt_zufall.setBounds(95, 30, 50, 20);
        jt_zufall.setHorizontalAlignment(JTextField.RIGHT);
        jt_zufall.setFont(font);
    
    
        jb_zufall.setBounds(95, 60,50,20);
        jb_zufall.setFont(font);
        jb_zufall.addMouseListener(this);
    
    
        jp_zufall.setLayout(null);
        jp_zufall.setBounds(860, 140,190,100);
           jp_zufall.setBorder(BorderFactory.createLineBorder( Color.black ));
        jp_zufall.add(jl_zufall);
        jp_zufall.add(jl_wieviel_felder);
        jp_zufall.add(jt_zufall);
        jp_zufall.add(jb_zufall);
        
        jl_zeit.setBounds(3, 3, 100, 20);
        jl_zeit.setFont(font);
        
        jl_milli.setBounds(3, 30, 90, 20);
        jl_milli.setFont(font);
        jt_zeit.setBounds(95, 30, 50, 20);
        jt_zeit.setHorizontalAlignment(JTextField.RIGHT);
        jt_zeit.setFont(font);
    
    
        jb_zeit.setBounds(95, 60,50,20);
        jb_zeit.setFont(font);
        jb_zeit.addMouseListener(this);
    
    
        jp_zeit.setLayout(null);
        jp_zeit.setBounds(860, 245,190,100);
           jp_zeit.setBorder(BorderFactory.createLineBorder( Color.black ));
        jp_zeit.add(jl_zeit);
        jp_zeit.add(jl_milli);
        jp_zeit.add(jt_zeit);
        jp_zeit.add(jb_zeit);
        
        font=new Font("Arial",Font.BOLD,20);
        jb_neu.setBounds(FENSTERBREITE-125, 765,100,40);
        jb_neu.setFont(font);
        jb_neu.addMouseListener(this);
    
    
        jb_start.setBounds(FENSTERBREITE-125, 810,100,40);
        jb_start.setFont(font);
        jb_start.addMouseListener(this);
        
        jl_zyklus.setBounds(FENSTERBREITE/2-100, FENSTERHOEHE-80, 90, 30);
        jl_zyklus.setFont(font);
        jl_zyklus1.setBounds(FENSTERBREITE/2-100+100+5, FENSTERHOEHE-80, 50, 30);
        jl_zyklus1.setHorizontalAlignment(JLabel.RIGHT);
        jl_zyklus1.setFont(font);
    
    
        
        
        jp_hauptpanel.setLayout(null);
        jp_hauptpanel.setBounds(5, 5,1065,945);
           jp_hauptpanel.setBorder(BorderFactory.createLineBorder( Color.black ));
           jp_hauptpanel.add(jp_spielfeld);
           jp_hauptpanel.add(jp_dimension);
           jp_hauptpanel.add(jp_zufall);
           jp_hauptpanel.add(jp_zeit);
           jp_hauptpanel.add(jb_neu);
           jp_hauptpanel.add(jb_start);
           jp_hauptpanel.add(jl_zyklus);
           jp_hauptpanel.add(jl_zyklus1);
           
           
        jframe.add(jp_hauptpanel);
        jframe.setVisible(true);
        }
    
    
    void set_zufallsfelder() {
        try {
        Random zufall=new Random();
        int anzahl=Integer.parseInt(jt_zufall.getText());
        
        if(anzahl>zeilen*spalten/2)throw new MehrRandomFelderalsMatrixfelder();
        
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++)
                matrix[i][j]=false;
        
        for(int i=0;i<anzahl+1;i++) {
            matrix[zufall.nextInt(zeilen)][ zufall.nextInt(spalten)]= true;
        }
        
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++)
                if(matrix[i][j])jb_matrix[i][j].setBackground(Color.BLUE);
                else jb_matrix[i][j].setBackground(color);
        } catch(Exception e) {
            
            if(e.getMessage().equals("Die Anzahl der Randomfelder ist größer, als die Anzahl der Matrixfelder")) {
                JOptionPane.showMessageDialog(null,"Anzahl > Anzahl Felder Spielfeld","Maximal x*y/2", JOptionPane.INFORMATION_MESSAGE);
                jt_zufall.setText(Integer.toString(20));
            }
            else {
                JOptionPane.showMessageDialog(null,"Bitte Zahl eingeben","Fehlerhafte Eingabe", JOptionPane.INFORMATION_MESSAGE);
                jt_zufall.setText(Integer.toString(20));
            }
        }
    }
    
    
    public void set_feld(int zeile, int spalte, boolean zustand) {
        matrix[zeile][spalte]=zustand;
        if(matrix[zeile][spalte])jb_matrix[zeile][spalte].setBackground(Color.BLUE);
        else jb_matrix[zeile][spalte].setBackground(color);
    }
    
    
    public boolean get_feld(int zeile, int spalte) {
        return matrix[zeile][spalte];
    }
    
    
    public void set_zyklus(int i) {
        jl_zyklus1.setText(Integer.toString(i));
    }
    
    
    public void set_start(boolean zustand) {
        start=zustand;
    }
    
    
    public void set_neu(boolean zustand) {
        neu=zustand;
    }
    
    
    void reset_spielfeld() {
        set_neu(true);
        jl_zyklus1.setText(Integer.toString(0));
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++) {
                matrix[i][j]=false;
                jb_matrix[i][j].setBackground(color);
            }
        set_start(false);
    }
    
    
    public boolean get_start() {
        return start;
    }
    
    
    public boolean get_neu() {
        return neu;
    }
    void set_milli() {
        try {
        milli=Integer.parseInt(jt_zeit.getText());
        if(milli<0) {
            milli=milli*(-1);
            jt_zeit.setText(Integer.toString(milli));
        }
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null,"Bitte Zahl eingeben","Fehlerhafte Eingabe", JOptionPane.INFORMATION_MESSAGE);
            jt_zeit.setText(Integer.toString(milli));
        }
    }
    
    
    public int get_milli(){
        return milli;
    }
    
    
    public int get_zeilen() {
        return zeilen;
    }
    
    
    public int get_spalten() {
        return spalten;
    }
    
    
    void set_spielfeld() {
        
        try {
        zeilen=Integer.parseInt(jt_x.getText());
        spalten=Integer.parseInt(jt_y.getText());
        
        if(zeilen>3&&spalten>3&&zeilen<100&&spalten<100) {
        
        set_start(false);
        
        jp_spielfeld.removeAll();
        jp_hauptpanel.remove(jp_spielfeld);
        
        jframe.revalidate();
        jframe.repaint();
        
        jb_matrix=new JButton[zeilen][spalten];
        matrix=new boolean[zeilen][spalten];
    
    
        for(int i=0;i<zeilen;i++)
               for(int j=0;j<spalten;j++){
                   matrix[i][j]=false;
                   jb_matrix[i][j]=new JButton();
                   jb_matrix[i][j].addMouseListener(this);
                   jb_matrix[i][j].setFocusable(false);
               }
             
            jp_spielfeld=new JPanel();
            jp_spielfeld.revalidate();
            jp_spielfeld.repaint();
    
    
            jp_spielfeld.setBounds(5, 5, 850, 850);
               jp_spielfeld.setLayout(new java.awt.GridLayout(zeilen, spalten));
               jp_spielfeld.setBorder(BorderFactory.createLineBorder( Color.black ));
                
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++){
                jp_spielfeld.add(jb_matrix[i][j]);
            }
        
        jp_hauptpanel.add(jp_spielfeld);
        jframe.validate();
        }
        else {
            JOptionPane.showMessageDialog(null,"Dimension muss > 3 und < 100 sein","Fehlerhafte Dimension", JOptionPane.INFORMATION_MESSAGE);
            zeilen=matrix.length;spalten=matrix[0].length;
            jt_x.setText(Integer.toString(zeilen));
            jt_y.setText(Integer.toString(spalten));
        }
        } catch(Exception e) {
            JOptionPane.showMessageDialog(null,"Dimension muss  eine ganze Zahl sein","Ganze Zahlen von 3 bis 100", JOptionPane.INFORMATION_MESSAGE);
            zeilen=matrix.length;spalten=matrix[0].length;
            jt_x.setText(Integer.toString(zeilen));
            jt_y.setText(Integer.toString(spalten));
        }
    }
            
    private void beenden()    {    
        jframe.setVisible(false);
        jframe.dispose();
        System.exit(0);
    }
    
    
    /*Wenn Window schließen durch X erfolgt, wird
     * Fenster mit beenden() geschlossen
     */    
    class WindowClosingAdapter     extends WindowAdapter {
          public void windowClosing(WindowEvent event)
          {beenden();}
    }
    
    
    @Override
    public void mouseClicked(MouseEvent arg0){
            
        if(arg0.getSource() == this.jb_zufall){
            set_zufallsfelder();
        }
    
    
        if(arg0.getSource() == this.jb_dim){
            set_spielfeld();
        }
        
        if(arg0.getSource() == this.jb_zeit){
            set_milli();
        }
        
        if(arg0.getSource() == this.jb_start){
            set_start(true);
        }
    
    
        if(arg0.getSource() == this.jb_neu){
            reset_spielfeld();
        }
    
    
        
        for(int i=0;i<zeilen;i++)
            for(int j=0;j<spalten;j++){
                if(arg0.getSource() == this.jb_matrix[i][j]){
                    if(matrix[i][j]) {
                        matrix[i][j]=false;
                        jb_matrix[i][j].setBackground(color);
                    }
                    else {
                        matrix[i][j]=true;
                        jb_matrix[i][j].setBackground(Color.BLUE);
                    }
                }
            }
        }
    
    
    @Override
    public void mouseEntered(MouseEvent arg0) {
        // TODO Auto-generated method stub
    }
    
    
    @Override
    public void mouseExited(MouseEvent arg0) {
        // TODO Auto-generated method stub
    }
    
    
    @Override
    public void mousePressed(MouseEvent arg0) {
        // TODO Auto-generated method stub
    }
    
    
    @Override
    public void mouseReleased(MouseEvent arg0) {
    
    
        
    }
    
    
    }
    
    
    class MehrRandomFelderalsMatrixfelder extends Exception
    {
        MehrRandomFelderalsMatrixfelder()
        {
            super("Die Anzahl der Randomfelder ist größer, als die Anzahl der Matrixfelder");
        }
    }
    Stiller Leser ist offline Geändert von Stiller Leser (19.06.2018 um 11:04 Uhr) Grund: //

  5. #5 Zitieren
    Pretty Pink Pony Princess  Avatar von Multithread
    Registriert seit
    Jun 2010
    Ort
    Crystal Empire
    Beiträge
    11.228
    Hier mal mein Anfang:
    FeldPosition:
    Code:
     public struct FieldPosition
        { 
            public FieldPosition(long inFromLeft, long inFromTop)
            {
                FromLeft = inFromLeft;
                FromTop = inFromTop;
            }
            public long FromLeft;
            public long FromTop;
    
            public override int GetHashCode()
            {
                return (int)(FromLeft ^ FromTop);
            }
        }
    Damit haben wir eine einfache Struktur um eine 2 Dimensionale ganzzahlige Position darzustellen.

    Und der Hauptteil: mein (beinahe*) Unentlich grosses Spielfeld:
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /// <summary>
        /// Spielefeld: Dictionary mit allen 
        /// </summary>
        public class Field : HashSet<FieldPosition>
        {
            //Handhaben ob wir was Töten, oder am leben lassen:D
            public Action<Field, FieldPosition, bool>[] WhatToDo = new Action<Field, FieldPosition, bool>[]
            {
                ((inField, inPos,inState)=> {if(inState){inField.FieldsToKill.Add(inPos); } }),     //0 Lebende Nachbarn
                ((inField, inPos,inState)=> {if(inState){inField.FieldsToKill.Add(inPos); } }),     //1 Lebende Nachbarn
                ((inField, inPos,inState)=> {}),                                                    //2 Lebende Nachbarn
                ((inField, inPos,inState)=> {if(!inState){inField.FieldsToLiving.Add(inPos); } }),  //3 Lebende Nachbarn
                ((inField, inPos,inState)=> {if(inState){inField.FieldsToKill.Add(inPos); } }),     //4 Lebende Nachbarn
                ((inField, inPos,inState)=> {if(inState){inField.FieldsToKill.Add(inPos); } }),     //5 Lebende Nachbarn
                ((inField, inPos,inState)=> {if(inState){inField.FieldsToKill.Add(inPos); } }),     //6 Lebende Nachbarn
                ((inField, inPos,inState)=> {if(inState){inField.FieldsToKill.Add(inPos); } }),     //7 Lebende Nachbarn
                ((inField, inPos,inState)=> {if(inState){inField.FieldsToKill.Add(inPos); } }),     //8 Lebende Nachbarn
            };
    
            /// <summary>
            /// Wird benötigt, um änderungen nach einem Durchlauf zurückzuschreiben
            /// </summary>
            private List<FieldPosition> FieldsToKill = new List<FieldPosition>(50);
            private List<FieldPosition> FieldsToLiving = new List<FieldPosition>(50);
    
            /// <summary>
            /// Wir müssen 'Tote' Felder ebenfalls Prüfen, wenn Sie neben einem Lebenden Standen.
            /// </summary>
            private Dictionary<FieldPosition, IntClass> DeadFieldLiveNeighbor = new Dictionary<FieldPosition, IntClass>();
    
            /// <summary>
            /// Lebt die Ausgewählte Zelle?
            /// </summary>
            /// <returns></returns>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public bool IsCurrentlyAlive(long inFromLeft, long inFromTop)
            {
                return Contains(new FieldPosition(inFromLeft,inFromTop ));
            }
    
            public void Next()
            {
                //Vorheriges aufräumen
                FieldsToKill.Clear();
                FieldsToLiving.Clear();
                DeadFieldLiveNeighbor.Clear();
    
                foreach (var tmpPosition in this)
                {
                    HandleNeighbors(tmpPosition);
                }
    
                //Tote Zellen Handhaben
                foreach(var tmpDeadCellKp in DeadFieldLiveNeighbor)
                {
                    WhatToDo[tmpDeadCellKp.Value.Value](this, tmpDeadCellKp.Key, false);
                }
    
                //Anwenden auf das Spielfeld
                foreach (var tmpFieldToKill in FieldsToKill)
                {
                    Remove(tmpFieldToKill);
                }
                foreach (var tmpFieldToLive in FieldsToLiving)
                {
                    Add(tmpFieldToLive);
                }
    
                //History schreiben, wenn gewünscht
                //_history.Add(new Tuple<FieldPosition[], FieldPosition[]>(FieldsToKill.ToArray(), FieldsToLiving.ToArray()));
            }
    
            /// <summary>
            /// Handhaben wie viele Nachvarn leben
            /// </summary>
            /// <param name="inPosition"></param>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            private void HandleNeighbors(FieldPosition inPosition)
            {
                var tmpLiving = 0;
                if (HandleNeighborForLiveCell(inPosition.FromLeft - 1, inPosition.FromTop - 1))
                {
                    tmpLiving++;
                }
                if (HandleNeighborForLiveCell(inPosition.FromLeft, inPosition.FromTop - 1))
                {
                    tmpLiving++;
                }
                if (HandleNeighborForLiveCell(inPosition.FromLeft + 1, inPosition.FromTop - 1))
                {
                    tmpLiving++;
                }
                if (HandleNeighborForLiveCell(inPosition.FromLeft - 1, inPosition.FromTop))
                {
                    tmpLiving++;
                }
                if (HandleNeighborForLiveCell(inPosition.FromLeft + 1, inPosition.FromTop))
                {
                    tmpLiving++;
                }
                if (HandleNeighborForLiveCell(inPosition.FromLeft - 1, inPosition.FromTop + 1))
                {
                    tmpLiving++;
                }
                if (HandleNeighborForLiveCell(inPosition.FromLeft, inPosition.FromTop + 1))
                {
                    tmpLiving++;
                }
                if (HandleNeighborForLiveCell(inPosition.FromLeft + 1, inPosition.FromTop + 1))
                {
                    tmpLiving++;
                }
    
                //Handhabung
                WhatToDo[tmpLiving](this, inPosition, true);
            }
    
            /// <summary>
            /// Nachbar einer Lebenden Zelle handhaben
            /// </summary>
            /// <returns></returns>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public bool HandleNeighborForLiveCell(long inFromLeft, long inFromTop)
            {
                var tmpField = new FieldPosition( inFromLeft,inFromTop);
                var tmpAlive= Contains(tmpField);
                if (!tmpAlive)
                {
                    //Tote nachbarszelle verändern
                    if(!DeadFieldLiveNeighbor.TryGetValue(tmpField, out IntClass Count))
                    {
                        Count = new IntClass();
                        DeadFieldLiveNeighbor.Add(tmpField, Count);
                    }
                    Count.Value++;
                }
                return tmpAlive;
            }
    
            private History _history = new History();
        }

    Inklusive der Möglichkeit alle änderungen zu Historisieren.

    Verwendung des Feldes:
    Spoiler:(zum lesen bitte Text markieren)
    Code:
     var tmpField = new Field();
                tmpField.Add(new FieldPosition(0, 0));
                tmpField.Add(new FieldPosition(2, 0));
                tmpField.Add(new FieldPosition(1, 1));
                tmpField.Add(new FieldPosition(2, 1));
                tmpField.Add(new FieldPosition(1, 2));
                for (var tmpI = 0; tmpI < 1000*1000; tmpI++)
                {
                    tmpField.Next();
                }


    Der Code ist zwar C#, aber Hashset gibt es sicher, Generics soweit Ich weiss auch, aber beim Tuple bin Ich mir nicht sicher (ist eine Generische Klasse, welche 1-21 Parameter akzeptiert)

    * Spielfeldgrenzen sind
    +9 223 372 036 854 775 807 und
    - 9 223 372 036 854 775 808
    Ja, das sind sehr grosse Zahlen

    C# Erklärungen:
    Field -> Das HashSet beinhaltet alle Zellen, welche im Aktuellen Zyklus leben.
    WhatToDo -> Ich habe ein Array mit Funktionen gemacht, welche abhandeln was bei einer bestimten Position an Lebenden Nachbarn geschehen soll. Da Spart mit ein Switch Case(If) an Zwei Stellen im Code und vereinfacht dort die Abhandlung. Etwas anderes als 23/3 ist möglich, es muss nur diese Liste angepasst werden.
    FieldsToKill&FieldsToLiving -> Hier merke Ich mir, wie Ich das Feld anpassen muss. Ich könnte auch mit Zwei Feldern arbeiten, Ich glaube aber nicht das es hier sinn macht.
    [MethodImpl(MethodImplOptions.AggressiveInlining)] -> Ich teile dem Compiler mit, das er den Inhalt diese Methode an alle Stellen einfügen soll, wo Ich die Funktion aufrufe. Gibt im Java sicher etwas ähnliches. Spart mit bei jedem Methodenaufruf ca. 7ns
    HandleNeighborForLiveCell -> Hier Prüfe Ich ob eine Zelle Lebt (Nachbarzelle einer Lebenden) und Füge ggf. dem Counter einer Toten Zelle an, das Sie eine Lebende als Nachbar hat.
    HandleNeighbors -> Alle Nachbarn einer Lebenden Zelle durchgehen und die anzahl Lebenden Nachbarn anwenden.
    DeadFieldLiveNeighbor -> Tote Felder mit Lebenden Nachbarn. Wird benötigt, um Tote Felder zu beleben, ohne nochmals Prüfen zu müssen, ob Sie genügend Lebende Nachbarn haben.


    @Jabu: was hältst du von meinem Code?
    Grosses Verbesserungspotential, oder Brauchbare Umsetzung?

    Zeitlich: ca. 10s für 1'000'000 Zyklen eines einfachen Gleiters.
    Ich kann also ca 700k Lebende Zellen pro Sekunde abhandeln.
    @Stiller Lesen: Wie viele Zyklen Packt deine Version Pro Sekunde? bei 10*10 und bei 60*60 wäre für mich Interessant.
    [Bild: AMD_Threadripper.png] Bei Hardware gibt es keine eigene Meinung, bei Hardware zählen nur die Fakten.


    Probleme mit der Haarpracht? Starres Haar ohne Glanz? TressFX schafft Abhilfe. Ja, TressFX verhilft auch Ihnen zu schönem und Geschmeidigen Haar.
    [Bild: i6tfHoa3ooSEraFH63.png]
    Multithread ist offline Geändert von Multithread (18.06.2018 um 23:09 Uhr)

  6. #6 Zitieren
    Auserwählter
    Registriert seit
    Jul 2017
    Beiträge
    6.514
    Also erstmal:
    Das ist nicht unendlich. Im Prinzip ist es das gleiche, als wenn es ein 60*60 Feld ist. Irgendwann ist Ende. Es kommt halt nur etwas später.

    Dann macht es bei mir keinen Sinn zu messen. Dafür ist es nicht ausgelegt. Im Gegenteil. Man soll ja die Änderungen sehen. Pro Zug wird das Programm um 500 Millisekunden unterbrochen. Das kann ich zwar ändern, aber letztendlich geht es mir darum, dass man halt die Änderungen sieht.

    Deins ist sozusagen eine komplett andere Aufgabenstellung. Wobei es natürlich sehr interessant ist, was da für ein Durchfluss möglich ist.

    Hm, ich habe Schwierigkeiten, deinen C# Code zu lesen. Ist das der ganze Code?
    Stiller Leser ist offline

  7. #7 Zitieren
    Pretty Pink Pony Princess  Avatar von Multithread
    Registriert seit
    Jun 2010
    Ort
    Crystal Empire
    Beiträge
    11.228
    Dir ist schon bewusst, das dies 9 Milionen Milionen Milionen Felder in JEDE Richtung sind, welche Ich abdecken kann?
    Ja, es ist nicht Unendlich, aber fast. Für Echte Unendlichkeit, müsste Ich die beiden long werte in der FeldPosition durch BigInteger ersetzen. Dieser kann theoretisch Unendlich Grosse Zahlen darstellen.

    Selbst mit short anstelle von long geht das Spielfeld noch 32k in jede Richtung. Dürfte für die meisten Anwendungen dann auch Ausreichen.
    Ja, es geht um Veränderung, ich finde es aber auch Interessant wie sich zb. ein Spielfeld nach 10k oder mehr Zügen verändert, bzw. möglicherweise auch in ein Gleichgewicht gependelt hat


    Ja, das ist der ganze Code.
    Wo hast du Schwierigkeiten? die stellen kann Ich sonst genauer erklären.
    [Bild: AMD_Threadripper.png] Bei Hardware gibt es keine eigene Meinung, bei Hardware zählen nur die Fakten.


    Probleme mit der Haarpracht? Starres Haar ohne Glanz? TressFX schafft Abhilfe. Ja, TressFX verhilft auch Ihnen zu schönem und Geschmeidigen Haar.
    [Bild: i6tfHoa3ooSEraFH63.png]
    Multithread ist offline

  8. #8 Zitieren
    Auserwählter
    Registriert seit
    Jul 2017
    Beiträge
    6.514
    Code:
    private Dictionary<FieldPosition, IntClass> DeadFieldLiveNeighbor = new Dictionary<FieldPosition, IntClass>();
    Code:
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    Was passiert da genau. Ist lange her, dass ich mit C gearbeitet habe.
    Stiller Leser ist offline

  9. #9 Zitieren
    Pretty Pink Pony Princess  Avatar von Multithread
    Registriert seit
    Jun 2010
    Ort
    Crystal Empire
    Beiträge
    11.228
    Zitat Zitat von Stiller Leser Beitrag anzeigen
    Code:
    private Dictionary<FieldPosition, IntClass> DeadFieldLiveNeighbor = new Dictionary<FieldPosition, IntClass>();
    In Java: HashMap
    Ich erstelle eine Hashmap wo Ich mir jedes Nachbarfeld eines Lebenden merke. Und die Anzahl lebender Nachbarn.
    Dadurch kann Ich diese Map an ende Iterieren und alle Felder, welche genau 3 Nachbarn haben in Lebende verwandeln

    Zitat Zitat von Stiller Leser Beitrag anzeigen
    Code:
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    Hierbei handelt es sich um ein Compiler Attribut.
    Damit kann Ich den Compiler steuern das er mir eine 'grosse' methode macht, anstelle von vielen kleinen.
    [Bild: AMD_Threadripper.png] Bei Hardware gibt es keine eigene Meinung, bei Hardware zählen nur die Fakten.


    Probleme mit der Haarpracht? Starres Haar ohne Glanz? TressFX schafft Abhilfe. Ja, TressFX verhilft auch Ihnen zu schönem und Geschmeidigen Haar.
    [Bild: i6tfHoa3ooSEraFH63.png]
    Multithread ist offline

  10. #10 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.322
    Zitat Zitat von Multithread Beitrag anzeigen
    Hier mal mein Anfang: [...]
    Nicht schlecht, Herr Specht (und das auch noch so schnell)...

    @Jabu: was hältst du von meinem Code?
    Grosses Verbesserungspotential, oder Brauchbare Umsetzung?
    Vorab: Ich bin kein C#-Experte. Du hattest den Schwerpunkt wohl auf eine dynamische Lösung mit großen Freiheiten gelegt, weswegen sich sicherlich nicht dieselbe Performance wie bei einer statischeren Lösung erreichen lässt. Unter Einbeziehung dieser Voraussetzungen müsste das schon ziemlich gut sein.


    Gefunden habe ich trotzdem etwas, sind aber nur Kleinigkeiten:

    Für dein struct FieldPosition gilt das Equals, welches auf einem System.Object verwendet wird, wodurch HashSet<T> und Konsorten ganz schön lahm sind, denn es erfolgt ein Boxing, bei dem FieldPosition in einem System.Object geschachtelt und auf dem verwalteten Heap abgelegt wird. Dieser Aufwand ist für die Laufzeit-Polymorphie und Weiteres nötig. Normalerweise ist noch Reflexion mit drin, aber der Teil soll bei Werttypen glücklicherweise übersprungen werden. Die CLR rödelt also unnütz herum.

    Was man dagegen tun könnte:

    Von dieser naheliegenden Idee sollte man aus mehrerlei Gründen absehen (zu viel Polymorphie; Grundsätzlich: Downcast könnte fehlschlagen, null ist möglich (was beides gefährlich ist, aber bei dir nicht vorkommt)):
    Code:
    public override bool Equals(object other)
    {
        var fieldPos = (FieldPosition)other;
        return (FromLeft == fieldPos.FromLeft) && (FromTop == fieldPos.FromTop);
    }
    Weil es um Performance geht, wäre das^, obwohl es schon sehr viel brächte, suboptimal und erst recht dann, wenn du Sicherheit (die du aktuell nicht brauchst) auch noch einbaust.

    Zu deinen fixen Typen (was gut ist) passt wohl dieses (was zudem sicherer ist):
    Code:
    public struct FieldPosition : IEquatable<FieldPosition>
    {
        [...]
        public bool Equals(FieldPosition other)
        {
            return (FromLeft == other.FromLeft) && (FromTop == other.FromTop);
        }
    }
    Man beachte, dass nur noch implementiert und nicht überschrieben wird. Damit sollte der unnötige Ballast beim internen Überprüfen nach Hashvergleich weg sein.

    Was bringt es bei dir? Ich wette, ungefähr eine Halbierung der Zeiten.


    Kleinvieh macht auch Mist:

    Deine interessante Lösung mit dem Array, welches die Funktionen referenziert, hat doch einiges an Overhead. Dieses ist schneller (beim Hinzufügen genügt ein Fall):
    Code:
    switch (tmpLiving) {
        case 0:case 1:case 4:case 5:case 6:case 7:case 8:
            FieldsToKill.Add(inPosition);
            break;
    }
    Ich habe es vorsichtshalber erwähnt, obwohl du meintest, dass du das nicht drin haben wolltest, denn so schlimm ist es auch wieder nicht. Außerdem zeigt es klarer an, was der Code eigentlich soll. Es läuft letztendlich nur auf diese beiden Standardaktionen oder gar nichts hinaus, wobei die eine Standardaktion mit der anderen nichts zu tun hat, weswegen die Vermischung bloß verwirrt. Aber nimm das bitte nicht als Kritik, ich weiß doch, wie gerne man experimentiert und wie alles im Fluss ist, mal so und mal anders.

    Dann noch eine Kleinigkeit, vergleiche das mal mit deiner Funktion:
    Code:
    public bool HandleNeighborForLiveCell(long inFromLeft, long inFromTop)
    {
        var tmpField = new FieldPosition(inFromLeft, inFromTop);
    
        if (Contains(tmpField))
            return true;
    
        if (!DeadFieldLiveNeighbor.TryGetValue(tmpField, out IntClass Count))
        {
            Count = new IntClass();
            DeadFieldLiveNeighbor.Add(tmpField, Count);
        }
        Count.Value++;
        return false;
    }
    Es wird auf die Variable, welche den Fluss gesteuert hat, nicht mehr für den Rückgabewert zugegriffen, sondern es wird ein fixer Wert zurückgegeben, welcher sich aus dem Fluss ergibt und sich im sowieso gerade gelesenen Codesegment befindet. Es muss kein Stack-Offset mehr verrechnet werden. Normalerweise ist das etwas performanter.
    Hinzugefügt: Falls das Inlining klappt, kann man auf ein Wegfallen eines konditionalen Sprungs und das Zusammenfassen bzw. Eliminieren von Sprunganweisungen hoffen. Wenn der Compiler genügend clever ist, ist meine Maßnahme unnötig. Man hat keine Garantie, dass das Inlining tatsächlich erfolgt oder dass der Compiler genügend clever ist.

    Mit allem zusammen könnte dein Code etwa zweieinhalbmal so schnell werden.
    jabu ist offline Geändert von jabu (21.06.2018 um 21:24 Uhr) Grund: hoffentlich nun etwas verständlicher

  11. #11 Zitieren
    Pretty Pink Pony Princess  Avatar von Multithread
    Registriert seit
    Jun 2010
    Ort
    Crystal Empire
    Beiträge
    11.228
    Zitat Zitat von jabu Beitrag anzeigen
    Nicht schlecht, Herr Specht (und das auch noch so schnell)...
    Gerade so Sachen, wo man mit etwas überlegen (und nicht mit stur Probieren) weiterkommen kann, bin Ich doch manchmal recht gut
    Meist mache Ich den Code am ende ja Komplexer als er sein müsste, hier hat mir das doch geholfen.
    Und Ich wusste bereits wie man solche Unendlich Felder aufbauen kann, bzw. was man vermeiden sollte.

    Zitat Zitat von jabu Beitrag anzeigen
    Vorab: Ich bin kein C#-Experte. Du hattest den Schwerpunkt wohl auf eine dynamische Lösung mit großen Freiheiten gelegt, weswegen sich sicherlich nicht dieselbe Performance wie bei einer statischeren Lösung erreichen lässt. Unter Einbeziehung dieser Voraussetzungen müsste das schon ziemlich gut sein.
    Was meinst du mit Performance einer Statischen Lösung?
    Ja, auf einem gut gefüllten Feld bin Ich sicher bedeutend langsamer als reines Prüfen via Array.
    Sobald aber die Lücken grösse werden, dürfte Ich das Array auch bald mal überholen.

    Zitat Zitat von jabu Beitrag anzeigen
    Für dein struct FieldPosition gilt das Equals, welches auf einem System.Object verwendet wird, wodurch HashSet<T> und Konsorten ganz schön lahm sind, denn es erfolgt ein Boxing, bei dem FieldPosition in einem System.Object geschachtelt und auf dem verwalteten Heap abgelegt wird. Dieser Aufwand ist für die Laufzeit-Polymorphie und Weiteres nötig. Normalerweise ist noch Reflexion mit drin, aber der Teil soll bei Werttypen glücklicherweise übersprungen werden. Die CLR rödelt also unnütz herum.

    Was bringt es bei dir? Ich wette, ungefähr eine Halbierung der Zeiten.
    Von 7,3 auf 3,7s.
    Mit dem Equals Override sind es 4,5s.
    Ich wusste nicht, das die Hashtable(+Dict) auch das Equals verwenden. Für das nächste mal weiss Ich es.
    Und IEquatable<T> Kannte Ich noch nicht, nur IComparable<T>, das kann Ich ggf. in Zukunft mal wieder nutzen

    Bin bei uns inner Firma für die Performance zuständig. Dort sind aber meist ganz andere Probleme zu lösen (aka verhindern das Ich für 1k Objekte auch 1k mal die DB abfrage....)

    Zitat Zitat von jabu Beitrag anzeigen

    Kleinvieh macht auch Mist:

    Deine interessante Lösung mit dem Array, welches die Funktionen referenziert, hat doch einiges an Overhead. Dieses ist schneller (beim Hinzufügen genügt ein Fall):
    Code:
    switch (tmpLiving) {
        case 0:case 1:case 4:case 5:case 6:case 7:case 8:
            FieldsToKill.Add(inPosition);
            break;
    }
    Switch Case bringt nahe 0 an Performancegewinn.
    von 3.74 auf 3.66s
    Ein If auf 3 und !=3 !=2 bringt nochmals gleich viel Zugewinn (auf 3.58s). Und mit je 2 If's mehr (andere Game of Life Struktur) bin Ich sogar langsamer als mit dem Lambda Array

    Der Grund dürfte in der Natur von C# und Lambda liegen.
    Nachdem er Code einmal Kompiliert wurde, verhält sich dieses Array wie ein Array eben, nur das kein Wert zurückgegeben wird, sonder ein Pointer auf eine Funktion (aka Delegate).
    der JIT dürfte da recht viel an Magie machen können was Intergration anbelangt.

    Und ja, den Performance Impact habe Ich von Anfang an gemessen. Ich musste ja sicherstellen das dies die Zeit nicht um 900% erhöht

    Zitat Zitat von jabu Beitrag anzeigen

    Dann noch eine Kleinigkeit, vergleiche das mal mit deiner Funktion:
    Code:
    public bool HandleNeighborForLiveCell(long inFromLeft, long inFromTop)
    {
        var tmpField = new FieldPosition(inFromLeft, inFromTop);
    
        if (Contains(tmpField))
            return true;
    
        if (!DeadFieldLiveNeighbor.TryGetValue(tmpField, out IntClass Count))
        {
            Count = new IntClass();
            DeadFieldLiveNeighbor.Add(tmpField, Count);
        }
        Count.Value++;
        return false;
    }
    Es wird auf die Variable, welche den Fluss gesteuert hat, nicht mehr für den Rückgabewert zugegriffen, sondern es wird ein fixer Wert zurückgegeben, welcher sich aus dem Fluss ergibt und sich im sowieso gerade gelesenen Codesegment befindet. Es muss kein Stack-Offset mehr verrechnet werden. Normalerweise ist das etwas performanter.
    Hinzugefügt: Falls das Inlining klappt, kann man auf ein Wegfallen eines konditionalen Sprungs und das Zusammenfassen bzw. Eliminieren von Sprunganweisungen hoffen. Wenn der Compiler genügend clever ist, ist meine Maßnahme unnötig. Man hat keine Garantie, dass das Inlining tatsächlich erfolgt oder dass der Compiler genügend clever ist.

    Mit allem zusammen könnte dein Code etwa zweieinhalbmal so schnell werden.
    Holy Sh**
    Das mit denn Statischen Rückgabewerten bringt >50ms auf alles. Das Ist bedeutend Mehr als Ich erwartet habe.

    Schneller als 3,5s Läuft der Code aber auch mir allen Änderungen zusammen nicht.
    PS: Wenn Ich mein Element auf int ändere, komme Ich auf 3,15s herunter. Wieso weiss Ich nicht, Ich brauche beidemal 13MB an Speicher.


    Dafür kann Ich dir sagen zu was der Compiler alles zusammen Optimiert hat:
    Der Code sieht genauso aus wie oben

    Alles in Allem also ziemlich genau 2,5mal schneller als am Anfang
    Dabei dachte Ich, ich sei schon recht gut was die Performance angeht.
    PS: Anscheinend ist 32 Bit Code rund 10% schneller als 64Bit Code.
    Und ohne 'Code Optimieren', ist der Code auch nur noch halb so schnell.


    was hat eigentlich dein Ansatz so für Geschwindigkeiten? Also wie viele Felder kannst du Pro Sekunde Prüfen?
    Und wie schnell ist der Code, wenn er in einer Nativen Sprache Geschieben und ausgeführt wird?
    Angeblich ist der JIT Code ja nur unwesentlich langsamer als guter, vorkompilierter, Code.
    [Bild: AMD_Threadripper.png] Bei Hardware gibt es keine eigene Meinung, bei Hardware zählen nur die Fakten.


    Probleme mit der Haarpracht? Starres Haar ohne Glanz? TressFX schafft Abhilfe. Ja, TressFX verhilft auch Ihnen zu schönem und Geschmeidigen Haar.
    [Bild: i6tfHoa3ooSEraFH63.png]
    Multithread ist offline Geändert von Multithread (21.06.2018 um 23:39 Uhr)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •