From 0ad31dcca37df9891ed5d5b70f12a966fc821c6d Mon Sep 17 00:00:00 2001
From: Gregor Kleen <gkleen@yggdrasil.li>
Date: Thu, 3 Dec 2015 04:34:54 +0000
Subject: EiP - 07

---
 .../eip/blaetter/07/H7-1A/de/lmu/tcs/Ansicht.java  |  64 ++++
 .../07/H7-1A/de/lmu/tcs/GraphicsWindow.java        | 393 +++++++++++++++++++++
 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Main.java  |  25 ++
 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Param.java |  25 ++
 .../eip/blaetter/07/H7-1A/de/lmu/tcs/Position.java |  27 ++
 .../eip/blaetter/07/H7-1A/de/lmu/tcs/Spieler.java  |  80 +++++
 .../blaetter/07/H7-1A/de/lmu/tcs/Spielfeld.java    | 198 +++++++++++
 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Zelle.java |  35 ++
 .../eip/blaetter/07/H7-1B/de/lmu/tcs/Ansicht.java  |  64 ++++
 .../07/H7-1B/de/lmu/tcs/GraphicsWindow.java        | 393 +++++++++++++++++++++
 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Main.java  |  25 ++
 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Param.java |  26 ++
 .../eip/blaetter/07/H7-1B/de/lmu/tcs/Position.java |  27 ++
 .../eip/blaetter/07/H7-1B/de/lmu/tcs/Spieler.java  |  79 +++++
 .../blaetter/07/H7-1B/de/lmu/tcs/Spielfeld.java    | 198 +++++++++++
 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Zelle.java |  47 +++
 .../eip/blaetter/07/H7-1C/de/lmu/tcs/Ansicht.java  |  99 ++++++
 .../07/H7-1C/de/lmu/tcs/GraphicsWindow.java        | 393 +++++++++++++++++++++
 .../eip/blaetter/07/H7-1C/de/lmu/tcs/Hexagon.java  |  76 ++++
 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Main.java  |  25 ++
 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Param.java |  25 ++
 .../eip/blaetter/07/H7-1C/de/lmu/tcs/Position.java |  31 ++
 .../eip/blaetter/07/H7-1C/de/lmu/tcs/Spieler.java  |  81 +++++
 .../blaetter/07/H7-1C/de/lmu/tcs/Spielfeld.java    | 205 +++++++++++
 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Zelle.java |  47 +++
 ws2015/eip/blaetter/07/de/lmu/tcs/Ansicht.java     |  64 ++++
 .../eip/blaetter/07/de/lmu/tcs/GraphicsWindow.java | 393 +++++++++++++++++++++
 ws2015/eip/blaetter/07/de/lmu/tcs/Main.java        |  25 ++
 ws2015/eip/blaetter/07/de/lmu/tcs/Param.java       |  26 ++
 ws2015/eip/blaetter/07/de/lmu/tcs/Position.java    |  27 ++
 ws2015/eip/blaetter/07/de/lmu/tcs/Spieler.java     |  79 +++++
 ws2015/eip/blaetter/07/de/lmu/tcs/Spielfeld.java   | 198 +++++++++++
 ws2015/eip/blaetter/07/de/lmu/tcs/Zelle.java       |  47 +++
 ws2015/eip/blaetter/07/manifest                    |   3 +
 34 files changed, 3550 insertions(+)
 create mode 100644 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Ansicht.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/GraphicsWindow.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Main.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Param.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Position.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Spieler.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Spielfeld.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Zelle.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Ansicht.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/GraphicsWindow.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Main.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Param.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Position.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Spieler.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Spielfeld.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Zelle.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Ansicht.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/GraphicsWindow.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Hexagon.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Main.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Param.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Position.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Spieler.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Spielfeld.java
 create mode 100644 ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Zelle.java
 create mode 100644 ws2015/eip/blaetter/07/de/lmu/tcs/Ansicht.java
 create mode 100644 ws2015/eip/blaetter/07/de/lmu/tcs/GraphicsWindow.java
 create mode 100644 ws2015/eip/blaetter/07/de/lmu/tcs/Main.java
 create mode 100644 ws2015/eip/blaetter/07/de/lmu/tcs/Param.java
 create mode 100644 ws2015/eip/blaetter/07/de/lmu/tcs/Position.java
 create mode 100644 ws2015/eip/blaetter/07/de/lmu/tcs/Spieler.java
 create mode 100644 ws2015/eip/blaetter/07/de/lmu/tcs/Spielfeld.java
 create mode 100644 ws2015/eip/blaetter/07/de/lmu/tcs/Zelle.java
 create mode 100644 ws2015/eip/blaetter/07/manifest

diff --git a/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Ansicht.java b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Ansicht.java
new file mode 100644
index 0000000..f643974
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Ansicht.java
@@ -0,0 +1,64 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+
+/**
+ * View
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Ansicht {
+
+    private final GraphicsWindow fenster;
+    private final int max_x; //Breite
+    private final int max_y; //Höhe
+    private final int skalierung;
+
+
+    public Ansicht(int x, int y, int skalierung) {
+        this.max_x = x;
+        this.max_y = y;
+        this.skalierung = skalierung;
+        this.fenster = new GraphicsWindow(max_x * skalierung, max_y * skalierung);
+    }
+
+    public void zeichenZelle(Zelle zelle) {
+        Position pos = zelle.getPosition();
+        Rectangle box = new Rectangle(pos.getX() * skalierung, pos.getY() * skalierung, skalierung - 1, skalierung - 1);
+        if (zelle.istLebendig()) {
+            fenster.setColor(Param.FARBE_LEBENDIG);
+        } else {
+            fenster.setColor(Param.FARBE_TOT);
+        }
+        fenster.fill(box);
+    }
+
+    public void zeichneSpielfeld(Zelle[][] feld) {
+        fenster.clear();
+
+//        for (int x = 0; x < max_x; x++) {
+//            for (int y = 0; y < max_y; y++) {
+//                zeichenZelle(feld[x][y]);
+//        }
+//      Äquivalente Alternative ohne explizite Indizes:
+        for (Zelle[] zeile : feld) {
+            for (Zelle zelle : zeile) {
+                zeichenZelle(zelle);
+            }
+        }
+    }
+
+    public Position getClick() {
+        Point point = fenster.mouseClick();
+        Position result =  new Position(point.x / skalierung, point.y /skalierung);
+        return  result;
+    }
+
+    public void sleep(long delay) {
+        fenster.sleep(delay);
+    }
+
+    public void setText(String message) {
+        fenster.setText(message);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/GraphicsWindow.java b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/GraphicsWindow.java
new file mode 100644
index 0000000..a1f90bf
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/GraphicsWindow.java
@@ -0,0 +1,393 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+import java.util.ArrayList;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.Timer;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.MouseEvent;
+import java.awt.geom.RectangularShape;
+import java.awt.geom.GeneralPath;
+
+/**
+ Eine Klasse zu pädagogischen Zwecken.
+ Erlaubt die Eingabe von Punktkoordinaten
+ mittels Mausklicks, das Zeichnen einfacher
+ 2D Objekte (java.awt.Shape), sowie die
+ Ausgabe von Texten in einer Statuszeile.
+ @version 3.043
+ @author Martin Hofmann und die EiP-Teams verschiedener Jahre
+ */
+
+public class GraphicsWindow {
+
+    private int width;
+    private int height;
+    private JFrame dasFenster;
+    private static int fensterZahl;
+    private static int fensterNr;
+    private Label label;
+    private GraphicsWindowPanel panel;
+    private Point mousePos;
+    private Color activeColor = Color.BLACK;
+    final private Color backColor = Color.WHITE;
+    MyMouseAdapter mouseListener;
+
+    /**
+     Erzeugt ein Fenster der Größe 640 auf 480 mit Textausgabe, Mauseingabe und Grafikausgabe.
+     */
+    public GraphicsWindow() {
+        this(640, 480);
+    }
+
+    /**
+     Erzeugt ein Fenster in vorgegebener Größe mit Textausgabe, Mauseingabe und Grafikausgabe.
+     @param width Breite des Fensters
+     @param height Höhe des Fensters
+     */
+    public GraphicsWindow(int width, int height) {
+        this.width  = width;
+        this.height = height;
+        dasFenster  = new JFrame();
+        dasFenster.setTitle("Grafikfenster " + ++fensterNr);
+        fensterZahl++;
+        dasFenster.setLocationByPlatform(true);
+        dasFenster.setSize(width,height+50);
+        dasFenster.getContentPane().setPreferredSize(new Dimension(width, height+50));
+        dasFenster.pack();
+        dasFenster.addWindowListener(new WindowAdapter(){
+            public void windowClosing(WindowEvent e) {
+                dasFenster.dispose(); // nicht gleich alle Fenster abschiessen
+                if (--fensterZahl<1) System.exit(0);
+            }
+        });
+
+        label = new Label("Statuszeile...");
+        label.setFont(new Font("Helvetica", Font.PLAIN, 12));
+        dasFenster.getContentPane().add(label,"North" );
+        panel = new GraphicsWindowPanel();
+        //panel.setBackground(Color.cyan);
+        panel.addCommand(new SetColor(activeColor));
+        dasFenster.getContentPane().add(panel,"Center");
+        mousePos = new Point();
+        mouseListener = new MyMouseAdapter();
+        panel.addMouseListener(mouseListener);
+        clear();
+        dasFenster.setVisible(true);
+    }
+
+    /**
+     Gibt eine Zeichenkette oben im Fenster aus.
+     @param text diese Zeichenkette
+     */
+    public void setText(String text) {
+        label.setText(text);
+    }
+    /**
+     Liest den oben im Fenster angezeigten Text aus.
+     @return den Text
+     */
+    public String getText() {
+        return label.getText();
+    }
+    /**
+     Wartet auf einen Mausklick. Die Methode blockiert das
+     aufrufende Programm solange bis der Mausklick erfolgt ist.
+     @return die Koordinaten des angeklickten Punkts
+     */
+
+    public Point mouseClick() {
+        try{
+            synchronized(mouseListener){mouseListener.wait();}
+        }
+        catch(InterruptedException e){
+            e.printStackTrace();
+        }
+        return mousePos;
+    }
+
+    class MyMouseAdapter extends MouseAdapter {
+
+        /**
+         Beendet das Warten auf den Mausklick und verwertet die Koordinaten.
+         Diese Methode ist nicht für den Anwender bestimmt.
+         */
+
+        synchronized public void mouseClicked(MouseEvent e){
+            mousePos = e.getPoint();
+            notifyAll();
+        }
+    }
+
+
+    /**
+     Schaltet die Zeichenfarbe auf die Hintergrundfarbe um. Dies ist
+     das Mittel, um gezeichnete Linien wieder zu löschen.
+     */
+    public void switchToBackgroundColor(){
+        activeColor = backColor;
+        panel.addCommand(new SwitchToBackgroundColor(activeColor));
+        panel.repaint();
+    }
+
+    /**
+     Schaltet die Zeichenfarbe auf Schwarz um.
+     */
+    public void switchToForegroundColor(){
+        activeColor = Color.BLACK;
+        panel.addCommand(new SetColor(activeColor));
+        panel.repaint();
+    }
+
+
+    /** Liefert die aktuelle Zeichenfarbe.
+     @return die aktuelle Zeichenfarbe des GraphicsWindow. */
+    public Color getColor() {
+        // return panel.getGraphics().getColor(); // getGraphics() has unpleasant side-effects. :(
+                /* Fixed by adding another instance variable activeColor for now. */
+        return activeColor;
+    }
+
+    /**
+     Zeichnet eine Linie in der aktuellen Zeichenfarbe.
+     @param x Anfangspunkt
+     @param y Endpunkt
+     */
+    public void drawLine(Point x, Point y){
+        // Odering points reduces the amount of graphical artifacts in rendering the same object in different ways
+        Point x1 = x;
+        Point y1 = y;
+        if ((x.x > y.x) || ((x.x == y.x) && (x.y > y.y))) {
+            x1 = y;
+            y1 = x;
+        }
+        panel.addCommand(new DrawLine(x1,y1));
+        panel.repaint();
+    }
+
+    /**
+     Zeichnet einen Punkt in der aktuellen Zeichenfarbe.
+     @param p Punkt
+     */
+    public void drawPoint(Point p){
+        drawLine(p, p);
+    }
+
+    /**
+     Zeichnet einen Punkt in der aktuellen Zeichenfarbe.
+     @param p Punkt
+     */
+    public void drawStringAt(String s, Point p){
+        Command c = new DrawString(s,p);
+        panel.addCommand(c);
+        panel.repaint();
+    }
+
+    /**
+     Zeichnet ein geometrisches Objekt.
+     */
+    public void draw(Shape s) {
+        panel.addCommand(new Draw(s));
+        panel.repaint();
+    }
+
+    /**
+     Füllt ein geometrisches Objekt aus.
+     */
+    public void fill(Shape s) {
+        panel.addCommand(new Fill(s));
+        panel.repaint();
+    }
+
+    /** Das aufrufende Programm wird für ein gegebene Zeitspanne blockiert.
+     @param millis Die Zeitspanne in Millisekunden*/
+    public void sleep(long millis) {
+        try {Thread.sleep(millis);} catch (Exception e){}
+    }
+
+    /** Setzt die Zeichenfarbe. */
+    public void setColor(Color d) {
+        activeColor = d;
+        panel.addCommand(new SetColor(activeColor));
+        panel.repaint();
+    }
+
+    /**
+     Setzt die Zeichenfarbe auf einen Grauwert
+     @param shade Grauwert zwischen 0(schwarz) und 255(weiß)
+     */
+    public void setGrayColor(int shade) {
+        setColor(new Color(shade, shade, shade));
+    }
+
+    /**
+     Setzt die Zeichenfarbe für die Mandelbrot-Aufgabe
+     @param n Anzahl der Iterationen, die durch die Farbe symboliziert werdem soll
+     */
+    public void setMandelColor(int n) {
+        float r = (float) Math.min(1.0,((double) n / 9.0) );
+        float g = (float) Math.min(1.0,((double) n / 99.0) );
+        float b = (float) Math.min(1.0,((double) n / 999.0) );
+        setColor(new Color(r, g, b));
+    }
+
+    /** Löscht das Bild */
+    public void clear() {
+//        Color oldActive = activeColor;
+        panel.clearAll();
+//        this.switchToBackgroundColor();
+//        fill(new Rectangle(0,0,width,height));
+//        setColor(oldActive);
+    }
+
+    public void killIn(int secs) {
+        Timer t  = new Timer(1000*secs, new ActionListener(){
+            @Override
+            public void actionPerformed(ActionEvent e) {dasFenster.dispose();}
+        }
+        );
+        t.setRepeats(false);
+        t.start();
+    }
+}
+
+
+class GraphicsWindowPanel extends JPanel
+{
+    private static final long serialVersionUID = 1L;
+    private ArrayList<Command> cl = new ArrayList<Command>();
+
+    public void paintComponent(Graphics g)
+    {
+        super.paintComponent(g);
+        Graphics2D g2D = (Graphics2D)g;
+
+        ArrayList<Command> cl = this.cl; // Kopie wegen Nebenläufigkeit von Swing
+        int size = cl.size();
+        for (int i=0; i<size; i++) {
+            Command c = cl.get(i);
+            if (c != null) c.execute(g2D);
+        }
+    }
+
+    void addCommand(Command c)
+    {
+        cl.add(c);
+    }
+
+    void clearAll()
+    {
+//              try {
+//                      SwingUtilities.invokeAndWait(new Runnable() {
+//                              @Override
+//                              public void run() {
+        cl = new ArrayList<Command>();
+//                              }
+//                      });
+//              } catch (InterruptedException e) {
+//                      // TODO Auto-generated catch block
+//                      e.printStackTrace();
+//              } catch (InvocationTargetException e) {
+//                      // TODO Auto-generated catch block
+//                      e.printStackTrace();
+//              }
+    }
+}
+
+
+abstract class Command //implements Serializable
+{
+    abstract  void execute(Graphics2D g2D);
+
+    /** Clone a shape. This method is needed because Shape
+     * does not define clone(), although many shape classes do.
+     * Kopiert aus jsky-2.6 auf ftp.eso.org */
+    static Shape cloneShape(Shape s) {
+        // FIXME Add more specific shapes
+        if (s instanceof RectangularShape) {
+            return (RectangularShape) ((RectangularShape) s).clone();
+        } else {
+            return new GeneralPath(s);
+        }
+    }
+
+}
+
+class DrawLine extends Command {
+    Point von;
+    Point bis;
+    DrawLine(Point von, Point bis) {
+                /* Clonen der Punkte essentiell um Aliasingeffekte beim Redraw zu verhindern */
+        this.von = new Point(von);
+        this.bis = new Point(bis);
+    }
+    void execute(Graphics2D g2D)
+    {
+        g2D.drawLine(this.von.x,this.von.y,this.bis.x,this.bis.y);
+    }
+}
+
+class SwitchToForegroundColor extends Command {
+    SwitchToForegroundColor() {}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(Color.black);
+    }
+}
+
+class SwitchToBackgroundColor extends Command {
+    Color backcolor;
+    SwitchToBackgroundColor(Color backcolor) {this.backcolor = backcolor;}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(backcolor);
+    }
+}
+
+class SetColor extends Command {
+    Color color;
+    SetColor(Color color) {this.color = color;}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(this.color);
+    }
+}
+
+
+class Draw extends Command {
+    Shape shape;
+    Draw(Shape shape) {this.shape = cloneShape(shape);}
+    void execute(Graphics2D g2D) {
+        g2D.draw(this.shape);
+    }
+}
+
+class Fill extends Command {
+    Shape shape;
+    Fill(Shape shape) {this.shape = cloneShape(shape);}
+    void execute(Graphics2D g2D) {
+        g2D.fill(this.shape);
+    }
+}
+
+class DrawString extends Command {
+    String string;
+    Point position;
+    DrawString(String string, Point position) {this.string = string; this.position = position;}
+    @Override
+    void execute(Graphics2D g2D) {
+        g2D.drawString(string, position.x, position.y);
+    }
+}
+
+
+
+
+
+
+
+
+
diff --git a/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Main.java b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Main.java
new file mode 100644
index 0000000..4177aca
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Main.java
@@ -0,0 +1,25 @@
+package de.lmu.tcs;
+
+
+/**
+ * Game of Life nach der Idee von John Horton Conway
+ *
+ * Fallstudie für Objektorientiertes Design nach MVC Entwurfswuster
+ * im Rahmen der
+ * "Einführung in die Programmierung" WS2015/16
+ *
+ * Lehrstuhl für Theoretische Informatik
+ * LMU München
+ *
+ * Prof Martin Hofmann, Dr Steffen Jost
+ *
+ *  Created by jost on 24.11.15.
+ */
+public class Main {
+
+    public static void main(String[] args) {
+        Spieler spieler = new Spieler();
+        spieler.spielDurchführen();
+        System.exit(0);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Param.java b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Param.java
new file mode 100644
index 0000000..5b42421
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Param.java
@@ -0,0 +1,25 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+
+/**
+ * Sammlung aller extern festgelegten Konstanten
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Param {
+
+    // Konstanten für das Spiel
+    public static final int SPIEL_HÖHE   = 50;
+    public static final int SPIEL_BREITE = 80;
+
+    // Konstanten für die View
+    public static final Color FARBE_LEBENDIG = Color.RED;
+    public static final Color FARBE_TOT      = Color.WHITE;
+    public static final int   SKALIERUNG     = 10;
+
+    // Konstanten für Durchführung
+    public static final long  RUNDENZEIT = 120;
+    public static final int   RUNDENZAHL = 1000;
+
+}
diff --git a/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Position.java b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Position.java
new file mode 100644
index 0000000..546da7f
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Position.java
@@ -0,0 +1,27 @@
+package de.lmu.tcs;
+
+/**
+ * Model
+ *
+ * Immutable
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Position {
+
+    private final int x;
+    private final int y;
+
+    public Position(int x, int y) {
+        this.x = x;
+        this.y = y;
+    }
+
+    public int getX() {
+        return this.x;
+    }
+
+    public int getY() {
+        return this.y;
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Spieler.java b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Spieler.java
new file mode 100644
index 0000000..12f2a0e
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Spieler.java
@@ -0,0 +1,80 @@
+package de.lmu.tcs;
+
+import java.util.ArrayList;
+
+/**
+ * Controller
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Spieler {
+
+    private final Spielfeld spiel;
+    private final Ansicht ansicht;
+
+    public Spieler() {
+        this.spiel   = new Spielfeld(Param.SPIEL_BREITE,Param.SPIEL_HÖHE);
+        this.ansicht = new Ansicht(  Param.SPIEL_BREITE,Param.SPIEL_HÖHE,Param.SKALIERUNG);
+        ansicht.zeichneSpielfeld(spiel.getFeld());
+        ansicht.setText("Außerhalb Spielfeld klicken zum Beenden");
+
+        // Benutzer setzt Anfangspostionen
+        boolean nichtzuende = true;
+        do {
+            Position p = ansicht.getClick();
+            Zelle zelle = new Zelle(p, Zelle.LEBENDIG);
+            nichtzuende = spiel.setZelle(zelle);
+            if (nichtzuende) {
+                ansicht.zeichenZelle(zelle);
+            }
+        } while (nichtzuende);
+    }
+
+    public void spielDurchführen() {
+        for (int runde=0; runde < Param.RUNDENZAHL; runde++){
+            this.rundeDurchführen();
+            ansicht.setText("Runde "+runde);
+            ansicht.sleep(Param.RUNDENZEIT);
+        }
+    }
+
+
+    public void rundeDurchführen() {
+        ArrayList<Zelle> änderungen = new ArrayList<Zelle>();
+        // Änderungen anhand altem Zustand feststellen
+        for (Zelle zelle : spiel.getZellen()) {
+//            ArrayList<Zelle> nachbarn = spiel.getNachbarn(zelle);
+            Zelle[] nachbarn = spiel.getNachbarnAryWrapped(zelle);
+            int lebendigeNachbarn = 0;
+            for (Zelle nachbar : nachbarn) {
+                if (nachbar.istLebendig()) lebendigeNachbarn++;
+            }
+            // if (zelle.istLebendig()) {
+            //     if (lebendigeNachbarn <= 1 || lebendigeNachbarn >=4) {
+            //         Zelle neu = new Zelle(zelle.getPosition(),Zelle.TOT);
+            //         änderungen.add(neu);
+            //     }
+            // } else { // eventuell zu einem if umbauen, welches Zustand ins Gegenteil verkehrt
+            //     if (lebendigeNachbarn == 3) {
+            //         Zelle neu = new Zelle(zelle.getPosition(),Zelle.LEBENDIG);
+            //         änderungen.add(neu);
+            //     }
+            // }
+	    Zelle neu;
+	    if (zelle.istLebendig() && lebendigeNachbarn % 2 == 0)
+		neu = new Zelle(zelle.getPosition(),Zelle.TOT);
+	    else if (! zelle.istLebendig() && lebendigeNachbarn % 2 == 1)
+		neu = new Zelle(zelle.getPosition(),Zelle.LEBENDIG);
+	    else
+		neu = null;
+	    if (neu != null)
+		änderungen.add(neu);
+        }
+        // Erkannte Änderungen nun einpflegen
+        for (Zelle zelle : änderungen) {
+            spiel.setZelle(zelle);
+            ansicht.zeichenZelle(zelle);
+        }
+    }
+
+}
diff --git a/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Spielfeld.java b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Spielfeld.java
new file mode 100644
index 0000000..7b9ec60
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Spielfeld.java
@@ -0,0 +1,198 @@
+package de.lmu.tcs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Model
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Spielfeld {
+
+    private final Zelle[][] feld;
+    private final int max_x; //Breite
+    private final int max_y; //Höhe
+
+    public Spielfeld(int breite, int höhe) {
+        this.max_x = breite;
+        this.max_y = höhe;
+        feld = new Zelle[this.max_x][this.max_y];
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                final Position p = new Position(x, y);
+                feld[x][y] = new Zelle(p, Zelle.TOT);
+            }
+        }
+    }
+
+    /**
+     * Liefert Zelle des Spielfelds an einer Position.
+     * @param p Position, der Zelle ausgelesen werden soll
+     * @return Zelle des Spielfelds an dieser Position, falls vorhanden; sonst null.
+     */
+    public Zelle getZelle(Position p) {
+        if (p.getX() >= 0 && p.getX() < max_x && p.getY() >= 0 && p.getY() < max_y) {
+            return feld[p.getX()][p.getY()];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Setzt eine gegebene Zelle ins Spielfeld ein.
+     * Überschreibt vorherige Zelle.
+     *
+     * @param zelle Einzusetzende Zelle
+     * @return Ob die Position der Zelle im Spielfeld enthalten ist (false bedeutuet ungültig).
+     */
+    public boolean setZelle(Zelle zelle) {
+        final Position p = zelle.getPosition();
+        if (p.getX() >= 0 && p.getX() < max_x && p.getY() >= 0 && p.getY() < max_y) {
+            feld[p.getX()][p.getY()] = zelle;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Liefert das gesamte Spielfeld direkt aus;
+     * nicht so schöne, da interne Repräsentierung offenbart wird
+     * und das Array von aussen verändert werden kann! Autsch!
+     *
+     * @return Alle Zellen des Felds im 2D array
+     */
+    public Zelle[][] getFeld() {
+        return feld;
+    }
+
+    /**
+     * BESSERE ALTERNATIVE zu getter-Methode getFeld():
+     * Liefert alle Zellen des Spielfeldes aus. Vorteile:
+     * 1) Interne Repräsentation bleibt versteckt.
+     * 2) Da die Zellen immutable sind, kann hier das
+     * Spielfeld auch nicht woanders manipuliert werden.
+     *
+     * @return Alle Zellen des Spielfeldes als ArrayList
+     */
+    public ArrayList<Zelle> getZellen() {
+        ArrayList<Zelle> result = new ArrayList<>(max_x*max_y);
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                result.add(feld[x][y]);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Genau wie getZellen, nur mit echtem Array anstatt ArrayList.
+     * Vorteile bleiben erhalten!
+     *
+     * @return Alle Zellen des Spielfeldes als Array
+     */
+    public Zelle[] getZellenAry() {
+        Zelle[] result = new Zelle[max_x*max_y];
+        int i = 0;
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                result[i] = feld[x][y];
+                i++;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle.
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public ArrayList<Zelle> getNachbarn(Zelle zelle) {
+        ArrayList<Zelle> result = new ArrayList<>();
+        Position pos = zelle.getPosition();
+        for (int x=-1; x<=1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle nachbar = this.getZelle(new Position(pos.getX() + x, pos.getY() + y));
+                    if (nachbar != null) {
+                        result.add(nachbar);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle.
+     * Variante von getNachbar mit Array anstatt ArrayList
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+   public Zelle[] getNachbarnAry(Zelle zelle) {
+        Position pos = zelle.getPosition();
+        int minx = Math.max(pos.getX() - 1, 0);
+        int maxx = Math.min(pos.getX() + 1, this.max_x);
+        int miny = Math.max(pos.getY() - 1, 0);
+        int maxy = Math.min(pos.getY() + 1, this.max_y);
+        Zelle[] result = new Zelle[maxx - minx * maxy - miny];
+        int i = 0;
+        for (int x = minx; x <= maxx; x++) {
+            for (int y = miny; y <= maxy; y++) {
+                if (x!=0 || y!=0) {
+                    result[i] = feld[x][y];
+                    i++;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle auf Wrap-Around Spielfeld..
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public ArrayList<Zelle> getNachbarnWrapped(Zelle zelle) {
+        ArrayList<Zelle> result = new ArrayList<Zelle>(8);
+        Position pos = zelle.getPosition();
+        for (int x = -1; x <= 1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle z =  getZelle(new Position((pos.getX() + x + max_x )% max_x, (pos.getY() + y + max_y) % max_y));
+                    result.add(z);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle auf Warap-Around Spielfeld.
+     * Variante von getNachbarWrapped mit Array anstatt ArrayList
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public Zelle[] getNachbarnAryWrapped(Zelle zelle) {
+        Zelle[] result = new Zelle[8];
+        Position pos = zelle.getPosition();
+        int i = 0;
+        for (int x = -1; x <= 1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle z =  getZelle(new Position((pos.getX() + x + max_x )% max_x, (pos.getY() + y + max_y) % max_y));
+                    result[i] = z;
+                    i++;
+                }
+            }
+        }
+        return result;
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Zelle.java b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Zelle.java
new file mode 100644
index 0000000..01ac446
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1A/de/lmu/tcs/Zelle.java
@@ -0,0 +1,35 @@
+package de.lmu.tcs;
+
+/**
+ * Model
+ *
+ * Immutable
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Zelle {
+
+    public final static int TOT=0;
+    public final static int LEBENDIG=1;
+
+    private final Position position;
+    private final int zustand;
+
+    public Zelle(Position position, int zustand) {
+        this.position = position;
+        this.zustand = zustand;
+    }
+
+    public Position getPosition() {
+        return position;
+    }
+
+    public boolean istLebendig() {
+        return zustand==LEBENDIG;
+    }
+
+    public boolean istTot() {
+        return zustand==TOT;
+    }
+
+}
diff --git a/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Ansicht.java b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Ansicht.java
new file mode 100644
index 0000000..49d3375
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Ansicht.java
@@ -0,0 +1,64 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+
+/**
+ * View
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Ansicht {
+
+    private final GraphicsWindow fenster;
+    private final int max_x; //Breite
+    private final int max_y; //Höhe
+    private final int skalierung;
+
+
+    public Ansicht(int x, int y, int skalierung) {
+        this.max_x = x;
+        this.max_y = y;
+        this.skalierung = skalierung;
+        this.fenster = new GraphicsWindow(max_x * skalierung, max_y * skalierung);
+    }
+
+    public void zeichenZelle(Zelle zelle) {
+        Position pos = zelle.getPosition();
+        Rectangle box = new Rectangle(pos.getX() * skalierung, pos.getY() * skalierung, skalierung - 1, skalierung - 1);
+        if (zelle.istTot()) {
+            fenster.setColor(Param.ZELLENFARBE[0]);
+        } else {
+            fenster.setColor(Param.ZELLENFARBE[Math.min(zelle.alter() + 1, Param.ZELLENFARBE.length - 1)]);
+        }
+        fenster.fill(box);
+    }
+
+    public void zeichneSpielfeld(Zelle[][] feld) {
+        fenster.clear();
+
+//        for (int x = 0; x < max_x; x++) {
+//            for (int y = 0; y < max_y; y++) {
+//                zeichenZelle(feld[x][y]);
+//        }
+//      Äquivalente Alternative ohne explizite Indizes:
+        for (Zelle[] zeile : feld) {
+            for (Zelle zelle : zeile) {
+                zeichenZelle(zelle);
+            }
+        }
+    }
+
+    public Position getClick() {
+        Point point = fenster.mouseClick();
+        Position result =  new Position(point.x / skalierung, point.y /skalierung);
+        return  result;
+    }
+
+    public void sleep(long delay) {
+        fenster.sleep(delay);
+    }
+
+    public void setText(String message) {
+        fenster.setText(message);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/GraphicsWindow.java b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/GraphicsWindow.java
new file mode 100644
index 0000000..a1f90bf
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/GraphicsWindow.java
@@ -0,0 +1,393 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+import java.util.ArrayList;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.Timer;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.MouseEvent;
+import java.awt.geom.RectangularShape;
+import java.awt.geom.GeneralPath;
+
+/**
+ Eine Klasse zu pädagogischen Zwecken.
+ Erlaubt die Eingabe von Punktkoordinaten
+ mittels Mausklicks, das Zeichnen einfacher
+ 2D Objekte (java.awt.Shape), sowie die
+ Ausgabe von Texten in einer Statuszeile.
+ @version 3.043
+ @author Martin Hofmann und die EiP-Teams verschiedener Jahre
+ */
+
+public class GraphicsWindow {
+
+    private int width;
+    private int height;
+    private JFrame dasFenster;
+    private static int fensterZahl;
+    private static int fensterNr;
+    private Label label;
+    private GraphicsWindowPanel panel;
+    private Point mousePos;
+    private Color activeColor = Color.BLACK;
+    final private Color backColor = Color.WHITE;
+    MyMouseAdapter mouseListener;
+
+    /**
+     Erzeugt ein Fenster der Größe 640 auf 480 mit Textausgabe, Mauseingabe und Grafikausgabe.
+     */
+    public GraphicsWindow() {
+        this(640, 480);
+    }
+
+    /**
+     Erzeugt ein Fenster in vorgegebener Größe mit Textausgabe, Mauseingabe und Grafikausgabe.
+     @param width Breite des Fensters
+     @param height Höhe des Fensters
+     */
+    public GraphicsWindow(int width, int height) {
+        this.width  = width;
+        this.height = height;
+        dasFenster  = new JFrame();
+        dasFenster.setTitle("Grafikfenster " + ++fensterNr);
+        fensterZahl++;
+        dasFenster.setLocationByPlatform(true);
+        dasFenster.setSize(width,height+50);
+        dasFenster.getContentPane().setPreferredSize(new Dimension(width, height+50));
+        dasFenster.pack();
+        dasFenster.addWindowListener(new WindowAdapter(){
+            public void windowClosing(WindowEvent e) {
+                dasFenster.dispose(); // nicht gleich alle Fenster abschiessen
+                if (--fensterZahl<1) System.exit(0);
+            }
+        });
+
+        label = new Label("Statuszeile...");
+        label.setFont(new Font("Helvetica", Font.PLAIN, 12));
+        dasFenster.getContentPane().add(label,"North" );
+        panel = new GraphicsWindowPanel();
+        //panel.setBackground(Color.cyan);
+        panel.addCommand(new SetColor(activeColor));
+        dasFenster.getContentPane().add(panel,"Center");
+        mousePos = new Point();
+        mouseListener = new MyMouseAdapter();
+        panel.addMouseListener(mouseListener);
+        clear();
+        dasFenster.setVisible(true);
+    }
+
+    /**
+     Gibt eine Zeichenkette oben im Fenster aus.
+     @param text diese Zeichenkette
+     */
+    public void setText(String text) {
+        label.setText(text);
+    }
+    /**
+     Liest den oben im Fenster angezeigten Text aus.
+     @return den Text
+     */
+    public String getText() {
+        return label.getText();
+    }
+    /**
+     Wartet auf einen Mausklick. Die Methode blockiert das
+     aufrufende Programm solange bis der Mausklick erfolgt ist.
+     @return die Koordinaten des angeklickten Punkts
+     */
+
+    public Point mouseClick() {
+        try{
+            synchronized(mouseListener){mouseListener.wait();}
+        }
+        catch(InterruptedException e){
+            e.printStackTrace();
+        }
+        return mousePos;
+    }
+
+    class MyMouseAdapter extends MouseAdapter {
+
+        /**
+         Beendet das Warten auf den Mausklick und verwertet die Koordinaten.
+         Diese Methode ist nicht für den Anwender bestimmt.
+         */
+
+        synchronized public void mouseClicked(MouseEvent e){
+            mousePos = e.getPoint();
+            notifyAll();
+        }
+    }
+
+
+    /**
+     Schaltet die Zeichenfarbe auf die Hintergrundfarbe um. Dies ist
+     das Mittel, um gezeichnete Linien wieder zu löschen.
+     */
+    public void switchToBackgroundColor(){
+        activeColor = backColor;
+        panel.addCommand(new SwitchToBackgroundColor(activeColor));
+        panel.repaint();
+    }
+
+    /**
+     Schaltet die Zeichenfarbe auf Schwarz um.
+     */
+    public void switchToForegroundColor(){
+        activeColor = Color.BLACK;
+        panel.addCommand(new SetColor(activeColor));
+        panel.repaint();
+    }
+
+
+    /** Liefert die aktuelle Zeichenfarbe.
+     @return die aktuelle Zeichenfarbe des GraphicsWindow. */
+    public Color getColor() {
+        // return panel.getGraphics().getColor(); // getGraphics() has unpleasant side-effects. :(
+                /* Fixed by adding another instance variable activeColor for now. */
+        return activeColor;
+    }
+
+    /**
+     Zeichnet eine Linie in der aktuellen Zeichenfarbe.
+     @param x Anfangspunkt
+     @param y Endpunkt
+     */
+    public void drawLine(Point x, Point y){
+        // Odering points reduces the amount of graphical artifacts in rendering the same object in different ways
+        Point x1 = x;
+        Point y1 = y;
+        if ((x.x > y.x) || ((x.x == y.x) && (x.y > y.y))) {
+            x1 = y;
+            y1 = x;
+        }
+        panel.addCommand(new DrawLine(x1,y1));
+        panel.repaint();
+    }
+
+    /**
+     Zeichnet einen Punkt in der aktuellen Zeichenfarbe.
+     @param p Punkt
+     */
+    public void drawPoint(Point p){
+        drawLine(p, p);
+    }
+
+    /**
+     Zeichnet einen Punkt in der aktuellen Zeichenfarbe.
+     @param p Punkt
+     */
+    public void drawStringAt(String s, Point p){
+        Command c = new DrawString(s,p);
+        panel.addCommand(c);
+        panel.repaint();
+    }
+
+    /**
+     Zeichnet ein geometrisches Objekt.
+     */
+    public void draw(Shape s) {
+        panel.addCommand(new Draw(s));
+        panel.repaint();
+    }
+
+    /**
+     Füllt ein geometrisches Objekt aus.
+     */
+    public void fill(Shape s) {
+        panel.addCommand(new Fill(s));
+        panel.repaint();
+    }
+
+    /** Das aufrufende Programm wird für ein gegebene Zeitspanne blockiert.
+     @param millis Die Zeitspanne in Millisekunden*/
+    public void sleep(long millis) {
+        try {Thread.sleep(millis);} catch (Exception e){}
+    }
+
+    /** Setzt die Zeichenfarbe. */
+    public void setColor(Color d) {
+        activeColor = d;
+        panel.addCommand(new SetColor(activeColor));
+        panel.repaint();
+    }
+
+    /**
+     Setzt die Zeichenfarbe auf einen Grauwert
+     @param shade Grauwert zwischen 0(schwarz) und 255(weiß)
+     */
+    public void setGrayColor(int shade) {
+        setColor(new Color(shade, shade, shade));
+    }
+
+    /**
+     Setzt die Zeichenfarbe für die Mandelbrot-Aufgabe
+     @param n Anzahl der Iterationen, die durch die Farbe symboliziert werdem soll
+     */
+    public void setMandelColor(int n) {
+        float r = (float) Math.min(1.0,((double) n / 9.0) );
+        float g = (float) Math.min(1.0,((double) n / 99.0) );
+        float b = (float) Math.min(1.0,((double) n / 999.0) );
+        setColor(new Color(r, g, b));
+    }
+
+    /** Löscht das Bild */
+    public void clear() {
+//        Color oldActive = activeColor;
+        panel.clearAll();
+//        this.switchToBackgroundColor();
+//        fill(new Rectangle(0,0,width,height));
+//        setColor(oldActive);
+    }
+
+    public void killIn(int secs) {
+        Timer t  = new Timer(1000*secs, new ActionListener(){
+            @Override
+            public void actionPerformed(ActionEvent e) {dasFenster.dispose();}
+        }
+        );
+        t.setRepeats(false);
+        t.start();
+    }
+}
+
+
+class GraphicsWindowPanel extends JPanel
+{
+    private static final long serialVersionUID = 1L;
+    private ArrayList<Command> cl = new ArrayList<Command>();
+
+    public void paintComponent(Graphics g)
+    {
+        super.paintComponent(g);
+        Graphics2D g2D = (Graphics2D)g;
+
+        ArrayList<Command> cl = this.cl; // Kopie wegen Nebenläufigkeit von Swing
+        int size = cl.size();
+        for (int i=0; i<size; i++) {
+            Command c = cl.get(i);
+            if (c != null) c.execute(g2D);
+        }
+    }
+
+    void addCommand(Command c)
+    {
+        cl.add(c);
+    }
+
+    void clearAll()
+    {
+//              try {
+//                      SwingUtilities.invokeAndWait(new Runnable() {
+//                              @Override
+//                              public void run() {
+        cl = new ArrayList<Command>();
+//                              }
+//                      });
+//              } catch (InterruptedException e) {
+//                      // TODO Auto-generated catch block
+//                      e.printStackTrace();
+//              } catch (InvocationTargetException e) {
+//                      // TODO Auto-generated catch block
+//                      e.printStackTrace();
+//              }
+    }
+}
+
+
+abstract class Command //implements Serializable
+{
+    abstract  void execute(Graphics2D g2D);
+
+    /** Clone a shape. This method is needed because Shape
+     * does not define clone(), although many shape classes do.
+     * Kopiert aus jsky-2.6 auf ftp.eso.org */
+    static Shape cloneShape(Shape s) {
+        // FIXME Add more specific shapes
+        if (s instanceof RectangularShape) {
+            return (RectangularShape) ((RectangularShape) s).clone();
+        } else {
+            return new GeneralPath(s);
+        }
+    }
+
+}
+
+class DrawLine extends Command {
+    Point von;
+    Point bis;
+    DrawLine(Point von, Point bis) {
+                /* Clonen der Punkte essentiell um Aliasingeffekte beim Redraw zu verhindern */
+        this.von = new Point(von);
+        this.bis = new Point(bis);
+    }
+    void execute(Graphics2D g2D)
+    {
+        g2D.drawLine(this.von.x,this.von.y,this.bis.x,this.bis.y);
+    }
+}
+
+class SwitchToForegroundColor extends Command {
+    SwitchToForegroundColor() {}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(Color.black);
+    }
+}
+
+class SwitchToBackgroundColor extends Command {
+    Color backcolor;
+    SwitchToBackgroundColor(Color backcolor) {this.backcolor = backcolor;}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(backcolor);
+    }
+}
+
+class SetColor extends Command {
+    Color color;
+    SetColor(Color color) {this.color = color;}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(this.color);
+    }
+}
+
+
+class Draw extends Command {
+    Shape shape;
+    Draw(Shape shape) {this.shape = cloneShape(shape);}
+    void execute(Graphics2D g2D) {
+        g2D.draw(this.shape);
+    }
+}
+
+class Fill extends Command {
+    Shape shape;
+    Fill(Shape shape) {this.shape = cloneShape(shape);}
+    void execute(Graphics2D g2D) {
+        g2D.fill(this.shape);
+    }
+}
+
+class DrawString extends Command {
+    String string;
+    Point position;
+    DrawString(String string, Point position) {this.string = string; this.position = position;}
+    @Override
+    void execute(Graphics2D g2D) {
+        g2D.drawString(string, position.x, position.y);
+    }
+}
+
+
+
+
+
+
+
+
+
diff --git a/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Main.java b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Main.java
new file mode 100644
index 0000000..4177aca
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Main.java
@@ -0,0 +1,25 @@
+package de.lmu.tcs;
+
+
+/**
+ * Game of Life nach der Idee von John Horton Conway
+ *
+ * Fallstudie für Objektorientiertes Design nach MVC Entwurfswuster
+ * im Rahmen der
+ * "Einführung in die Programmierung" WS2015/16
+ *
+ * Lehrstuhl für Theoretische Informatik
+ * LMU München
+ *
+ * Prof Martin Hofmann, Dr Steffen Jost
+ *
+ *  Created by jost on 24.11.15.
+ */
+public class Main {
+
+    public static void main(String[] args) {
+        Spieler spieler = new Spieler();
+        spieler.spielDurchführen();
+        System.exit(0);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Param.java b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Param.java
new file mode 100644
index 0000000..88f8248
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Param.java
@@ -0,0 +1,26 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+
+/**
+ * Sammlung aller extern festgelegten Konstanten
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Param {
+
+    // Konstanten für das Spiel
+    public static final int SPIEL_HÖHE   = 50;
+    public static final int SPIEL_BREITE = 80;
+
+    // Konstanten für die View
+    // public static final Color FARBE_LEBENDIG = Color.RED;
+    // public static final Color FARBE_TOT      = Color.WHITE;
+    public static final Color[] ZELLENFARBE = new Color[] {Color.WHITE, Color.RED, Color.ORANGE, Color.MAGENTA, Color.GREEN, Color.CYAN, Color.BLUE};
+    public static final int   SKALIERUNG     = 10;
+
+    // Konstanten für Durchführung
+    public static final long  RUNDENZEIT = 120;
+    public static final int   RUNDENZAHL = 1000;
+
+}
diff --git a/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Position.java b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Position.java
new file mode 100644
index 0000000..546da7f
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Position.java
@@ -0,0 +1,27 @@
+package de.lmu.tcs;
+
+/**
+ * Model
+ *
+ * Immutable
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Position {
+
+    private final int x;
+    private final int y;
+
+    public Position(int x, int y) {
+        this.x = x;
+        this.y = y;
+    }
+
+    public int getX() {
+        return this.x;
+    }
+
+    public int getY() {
+        return this.y;
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Spieler.java b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Spieler.java
new file mode 100644
index 0000000..98bca6e
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Spieler.java
@@ -0,0 +1,79 @@
+package de.lmu.tcs;
+
+import java.util.ArrayList;
+
+/**
+ * Controller
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Spieler {
+
+    private final Spielfeld spiel;
+    private final Ansicht ansicht;
+
+    public Spieler() {
+        this.spiel   = new Spielfeld(Param.SPIEL_BREITE,Param.SPIEL_HÖHE);
+        this.ansicht = new Ansicht(  Param.SPIEL_BREITE,Param.SPIEL_HÖHE,Param.SKALIERUNG);
+        ansicht.zeichneSpielfeld(spiel.getFeld());
+        ansicht.setText("Außerhalb Spielfeld klicken zum Beenden");
+
+        // Benutzer setzt Anfangspostionen
+        boolean nichtzuende = true;
+        do {
+            Position p = ansicht.getClick();
+            Zelle zelle = new Zelle(p, Zelle.LEBENDIG);
+            nichtzuende = spiel.setZelle(zelle);
+            if (nichtzuende) {
+                ansicht.zeichenZelle(zelle);
+            }
+        } while (nichtzuende);
+    }
+
+    public void spielDurchführen() {
+        for (int runde=0; runde < Param.RUNDENZAHL; runde++){
+            this.rundeDurchführen();
+            ansicht.setText("Runde "+runde);
+            ansicht.sleep(Param.RUNDENZEIT);
+        }
+    }
+
+
+    public void rundeDurchführen() {
+        ArrayList<Zelle> änderungen = new ArrayList<Zelle>();
+        // Änderungen anhand altem Zustand feststellen
+        for (Zelle zelle : spiel.getZellen()) {
+//            ArrayList<Zelle> nachbarn = spiel.getNachbarn(zelle);
+            Zelle[] nachbarn = spiel.getNachbarnAryWrapped(zelle);
+            int lebendigeNachbarn = 0;
+            for (Zelle nachbar : nachbarn) {
+                if (nachbar.istLebendig()) lebendigeNachbarn++;
+            }
+            // if (zelle.istLebendig()) {
+            //     if (lebendigeNachbarn <= 1 || lebendigeNachbarn >=4) {
+            //         Zelle neu = new Zelle(zelle.getPosition(),Zelle.TOT);
+            //         änderungen.add(neu);
+            //     }
+            // } else { // eventuell zu einem if umbauen, welches Zustand ins Gegenteil verkehrt
+            //     if (lebendigeNachbarn == 3) {
+            //         Zelle neu = new Zelle(zelle.getPosition(),Zelle.LEBENDIG);
+            //         änderungen.add(neu);
+            //     }
+            // }
+	    Zelle neu;
+	    if (zelle.istLebendig() && lebendigeNachbarn % 2 == 0)
+		neu = new Zelle(zelle.getPosition(),Zelle.TOT);
+	    else if (! zelle.istLebendig() && lebendigeNachbarn % 2 == 1)
+		neu = new Zelle(zelle.getPosition(),Zelle.LEBENDIG);
+	    else
+		neu = zelle.nachkommen();
+	    änderungen.add(neu);
+        }
+        // Erkannte Änderungen nun einpflegen
+        for (Zelle zelle : änderungen) {
+            spiel.setZelle(zelle);
+            ansicht.zeichenZelle(zelle);
+        }
+    }
+
+}
diff --git a/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Spielfeld.java b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Spielfeld.java
new file mode 100644
index 0000000..7b9ec60
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Spielfeld.java
@@ -0,0 +1,198 @@
+package de.lmu.tcs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Model
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Spielfeld {
+
+    private final Zelle[][] feld;
+    private final int max_x; //Breite
+    private final int max_y; //Höhe
+
+    public Spielfeld(int breite, int höhe) {
+        this.max_x = breite;
+        this.max_y = höhe;
+        feld = new Zelle[this.max_x][this.max_y];
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                final Position p = new Position(x, y);
+                feld[x][y] = new Zelle(p, Zelle.TOT);
+            }
+        }
+    }
+
+    /**
+     * Liefert Zelle des Spielfelds an einer Position.
+     * @param p Position, der Zelle ausgelesen werden soll
+     * @return Zelle des Spielfelds an dieser Position, falls vorhanden; sonst null.
+     */
+    public Zelle getZelle(Position p) {
+        if (p.getX() >= 0 && p.getX() < max_x && p.getY() >= 0 && p.getY() < max_y) {
+            return feld[p.getX()][p.getY()];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Setzt eine gegebene Zelle ins Spielfeld ein.
+     * Überschreibt vorherige Zelle.
+     *
+     * @param zelle Einzusetzende Zelle
+     * @return Ob die Position der Zelle im Spielfeld enthalten ist (false bedeutuet ungültig).
+     */
+    public boolean setZelle(Zelle zelle) {
+        final Position p = zelle.getPosition();
+        if (p.getX() >= 0 && p.getX() < max_x && p.getY() >= 0 && p.getY() < max_y) {
+            feld[p.getX()][p.getY()] = zelle;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Liefert das gesamte Spielfeld direkt aus;
+     * nicht so schöne, da interne Repräsentierung offenbart wird
+     * und das Array von aussen verändert werden kann! Autsch!
+     *
+     * @return Alle Zellen des Felds im 2D array
+     */
+    public Zelle[][] getFeld() {
+        return feld;
+    }
+
+    /**
+     * BESSERE ALTERNATIVE zu getter-Methode getFeld():
+     * Liefert alle Zellen des Spielfeldes aus. Vorteile:
+     * 1) Interne Repräsentation bleibt versteckt.
+     * 2) Da die Zellen immutable sind, kann hier das
+     * Spielfeld auch nicht woanders manipuliert werden.
+     *
+     * @return Alle Zellen des Spielfeldes als ArrayList
+     */
+    public ArrayList<Zelle> getZellen() {
+        ArrayList<Zelle> result = new ArrayList<>(max_x*max_y);
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                result.add(feld[x][y]);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Genau wie getZellen, nur mit echtem Array anstatt ArrayList.
+     * Vorteile bleiben erhalten!
+     *
+     * @return Alle Zellen des Spielfeldes als Array
+     */
+    public Zelle[] getZellenAry() {
+        Zelle[] result = new Zelle[max_x*max_y];
+        int i = 0;
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                result[i] = feld[x][y];
+                i++;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle.
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public ArrayList<Zelle> getNachbarn(Zelle zelle) {
+        ArrayList<Zelle> result = new ArrayList<>();
+        Position pos = zelle.getPosition();
+        for (int x=-1; x<=1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle nachbar = this.getZelle(new Position(pos.getX() + x, pos.getY() + y));
+                    if (nachbar != null) {
+                        result.add(nachbar);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle.
+     * Variante von getNachbar mit Array anstatt ArrayList
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+   public Zelle[] getNachbarnAry(Zelle zelle) {
+        Position pos = zelle.getPosition();
+        int minx = Math.max(pos.getX() - 1, 0);
+        int maxx = Math.min(pos.getX() + 1, this.max_x);
+        int miny = Math.max(pos.getY() - 1, 0);
+        int maxy = Math.min(pos.getY() + 1, this.max_y);
+        Zelle[] result = new Zelle[maxx - minx * maxy - miny];
+        int i = 0;
+        for (int x = minx; x <= maxx; x++) {
+            for (int y = miny; y <= maxy; y++) {
+                if (x!=0 || y!=0) {
+                    result[i] = feld[x][y];
+                    i++;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle auf Wrap-Around Spielfeld..
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public ArrayList<Zelle> getNachbarnWrapped(Zelle zelle) {
+        ArrayList<Zelle> result = new ArrayList<Zelle>(8);
+        Position pos = zelle.getPosition();
+        for (int x = -1; x <= 1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle z =  getZelle(new Position((pos.getX() + x + max_x )% max_x, (pos.getY() + y + max_y) % max_y));
+                    result.add(z);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle auf Warap-Around Spielfeld.
+     * Variante von getNachbarWrapped mit Array anstatt ArrayList
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public Zelle[] getNachbarnAryWrapped(Zelle zelle) {
+        Zelle[] result = new Zelle[8];
+        Position pos = zelle.getPosition();
+        int i = 0;
+        for (int x = -1; x <= 1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle z =  getZelle(new Position((pos.getX() + x + max_x )% max_x, (pos.getY() + y + max_y) % max_y));
+                    result[i] = z;
+                    i++;
+                }
+            }
+        }
+        return result;
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Zelle.java b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Zelle.java
new file mode 100644
index 0000000..a7c6ad6
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1B/de/lmu/tcs/Zelle.java
@@ -0,0 +1,47 @@
+package de.lmu.tcs;
+
+/**
+ * Model
+ *
+ * Immutable
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Zelle {
+
+    public final static int TOT=0;
+    public final static int LEBENDIG=1;
+
+    private final Position position;
+    private final int zustand;
+
+    public Zelle(Position position, int zustand) {
+        this.position = position;
+        this.zustand = zustand;
+    }
+
+    public Zelle(Zelle old) {
+	this.position = old.position;
+	this.zustand = old.zustand;
+    }
+
+    public Position getPosition() {
+        return position;
+    }
+
+    public boolean istLebendig() {
+        return zustand>=LEBENDIG;
+    }
+
+    public boolean istTot() {
+        return zustand==TOT;
+    }
+
+    public Zelle nachkommen() {
+	return this.istTot() ? (new Zelle(this)) : (new Zelle(position, zustand + 1));
+    }
+
+    public int alter() {
+	return this.istTot() ? -1 : (this.zustand - 1);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Ansicht.java b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Ansicht.java
new file mode 100644
index 0000000..c59cd31
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Ansicht.java
@@ -0,0 +1,99 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+
+/**
+ * View
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Ansicht {
+
+    private final GraphicsWindow fenster;
+    private final int max_x; //Breite
+    private final int max_y; //Höhe
+    private final int skalierung;
+
+
+    public Ansicht(int x, int y, int skalierung) {
+        this.max_x = x;
+        this.max_y = y;
+        this.skalierung = skalierung;
+	Point furthestCenter = centerByIndex(x, y);
+        this.fenster = new GraphicsWindow(
+					  (int) (furthestCenter.getX() + Math.sqrt(3) * 1/2 * (double) skalierung + (double) (y % 2) * Math.sqrt(3) * 1/2 * (double) skalierung)
+					  , (int) (furthestCenter.getY() + (double) skalierung / 2)
+					  );
+    }
+
+    public void zeichneZelle(Zelle zelle) {
+        Position pos = zelle.getPosition();
+        // Rectangle box = new Rectangle(pos.getX() * skalierung, pos.getY() * skalierung, skalierung - 1, skalierung - 1);
+	Polygon box = new Hexagon(centerByIndex(pos.getX(), pos.getY()), skalierung).asPolygon();
+	fenster.setColor(Color.GRAY);
+	fenster.draw(box);
+        if (zelle.istTot()) {
+            fenster.setColor(Param.ZELLENFARBE[0]);
+        } else {
+            fenster.setColor(Param.ZELLENFARBE[Math.min(zelle.alter() + 1, Param.ZELLENFARBE.length - 1)]);
+        }
+        fenster.fill(box);
+    }
+
+    public void zeichneSpielfeld(Zelle[][] feld) {
+        fenster.clear();
+
+//        for (int x = 0; x < max_x; x++) {
+//            for (int y = 0; y < max_y; y++) {
+//                zeichenZelle(feld[x][y]);
+//        }
+//      Äquivalente Alternative ohne explizite Indizes:
+        for (Zelle[] zeile : feld) {
+            for (Zelle zelle : zeile) {
+		if (zelle != null)
+		    zeichneZelle(zelle);
+            }
+        }
+    }
+
+    public Position getClick() {
+        Point point = fenster.mouseClick();
+	Point firstCenter = centerByIndex(0,0);
+        Position testStart =  new Position(
+					   (point.x - firstCenter.x) / ((int) (Math.sqrt(3) * (double) skalierung))
+					   , (point.y - firstCenter.y) / ((int) (1.5 * (double) skalierung))
+					   ); // bad guess -- P.S.: actually, now it's a pretty good guess
+	for (int d = 0; d < Math.max(max_x, max_y); d++) // and starting there we test everything (also, another extremely bad guess)
+	    for (int dx = -d; dx <= d; dx++)
+		for (int dy = -d; dy <= d; dy++)
+		    {
+			if (Math.abs(dx) < d && Math.abs(dy) < d)
+			    continue;
+			int x = testStart.getX() + dx;
+			int y = testStart.getY() + dy;
+			// zeichneZelle(new Zelle(new Position(x, y), Zelle.LEBENDIG));
+			// try {Thread.sleep(100);} catch (Exception e){}
+			Hexagon test = new Hexagon(centerByIndex(x, y), skalierung);
+			if (test.contains(point))
+			    return new Position(x, y);
+		    }
+
+        return new Position(-1, -1);
+    }
+
+    public void sleep(long delay) {
+        fenster.sleep(delay);
+    }
+
+    public void setText(String message) {
+        fenster.setText(message);
+    }
+
+    public Point centerByIndex(int x, int y)
+    {
+	return new Point(
+			 (int) (Math.sqrt(3) * ((double) skalierung) * (((double) x) + 1 + ((double) (y % 2)) / 2))
+			 , (int) (((double) skalierung) * (1 + 1.5 * ((double) y)))
+			 );
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/GraphicsWindow.java b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/GraphicsWindow.java
new file mode 100644
index 0000000..a1f90bf
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/GraphicsWindow.java
@@ -0,0 +1,393 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+import java.util.ArrayList;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.Timer;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.MouseEvent;
+import java.awt.geom.RectangularShape;
+import java.awt.geom.GeneralPath;
+
+/**
+ Eine Klasse zu pädagogischen Zwecken.
+ Erlaubt die Eingabe von Punktkoordinaten
+ mittels Mausklicks, das Zeichnen einfacher
+ 2D Objekte (java.awt.Shape), sowie die
+ Ausgabe von Texten in einer Statuszeile.
+ @version 3.043
+ @author Martin Hofmann und die EiP-Teams verschiedener Jahre
+ */
+
+public class GraphicsWindow {
+
+    private int width;
+    private int height;
+    private JFrame dasFenster;
+    private static int fensterZahl;
+    private static int fensterNr;
+    private Label label;
+    private GraphicsWindowPanel panel;
+    private Point mousePos;
+    private Color activeColor = Color.BLACK;
+    final private Color backColor = Color.WHITE;
+    MyMouseAdapter mouseListener;
+
+    /**
+     Erzeugt ein Fenster der Größe 640 auf 480 mit Textausgabe, Mauseingabe und Grafikausgabe.
+     */
+    public GraphicsWindow() {
+        this(640, 480);
+    }
+
+    /**
+     Erzeugt ein Fenster in vorgegebener Größe mit Textausgabe, Mauseingabe und Grafikausgabe.
+     @param width Breite des Fensters
+     @param height Höhe des Fensters
+     */
+    public GraphicsWindow(int width, int height) {
+        this.width  = width;
+        this.height = height;
+        dasFenster  = new JFrame();
+        dasFenster.setTitle("Grafikfenster " + ++fensterNr);
+        fensterZahl++;
+        dasFenster.setLocationByPlatform(true);
+        dasFenster.setSize(width,height+50);
+        dasFenster.getContentPane().setPreferredSize(new Dimension(width, height+50));
+        dasFenster.pack();
+        dasFenster.addWindowListener(new WindowAdapter(){
+            public void windowClosing(WindowEvent e) {
+                dasFenster.dispose(); // nicht gleich alle Fenster abschiessen
+                if (--fensterZahl<1) System.exit(0);
+            }
+        });
+
+        label = new Label("Statuszeile...");
+        label.setFont(new Font("Helvetica", Font.PLAIN, 12));
+        dasFenster.getContentPane().add(label,"North" );
+        panel = new GraphicsWindowPanel();
+        //panel.setBackground(Color.cyan);
+        panel.addCommand(new SetColor(activeColor));
+        dasFenster.getContentPane().add(panel,"Center");
+        mousePos = new Point();
+        mouseListener = new MyMouseAdapter();
+        panel.addMouseListener(mouseListener);
+        clear();
+        dasFenster.setVisible(true);
+    }
+
+    /**
+     Gibt eine Zeichenkette oben im Fenster aus.
+     @param text diese Zeichenkette
+     */
+    public void setText(String text) {
+        label.setText(text);
+    }
+    /**
+     Liest den oben im Fenster angezeigten Text aus.
+     @return den Text
+     */
+    public String getText() {
+        return label.getText();
+    }
+    /**
+     Wartet auf einen Mausklick. Die Methode blockiert das
+     aufrufende Programm solange bis der Mausklick erfolgt ist.
+     @return die Koordinaten des angeklickten Punkts
+     */
+
+    public Point mouseClick() {
+        try{
+            synchronized(mouseListener){mouseListener.wait();}
+        }
+        catch(InterruptedException e){
+            e.printStackTrace();
+        }
+        return mousePos;
+    }
+
+    class MyMouseAdapter extends MouseAdapter {
+
+        /**
+         Beendet das Warten auf den Mausklick und verwertet die Koordinaten.
+         Diese Methode ist nicht für den Anwender bestimmt.
+         */
+
+        synchronized public void mouseClicked(MouseEvent e){
+            mousePos = e.getPoint();
+            notifyAll();
+        }
+    }
+
+
+    /**
+     Schaltet die Zeichenfarbe auf die Hintergrundfarbe um. Dies ist
+     das Mittel, um gezeichnete Linien wieder zu löschen.
+     */
+    public void switchToBackgroundColor(){
+        activeColor = backColor;
+        panel.addCommand(new SwitchToBackgroundColor(activeColor));
+        panel.repaint();
+    }
+
+    /**
+     Schaltet die Zeichenfarbe auf Schwarz um.
+     */
+    public void switchToForegroundColor(){
+        activeColor = Color.BLACK;
+        panel.addCommand(new SetColor(activeColor));
+        panel.repaint();
+    }
+
+
+    /** Liefert die aktuelle Zeichenfarbe.
+     @return die aktuelle Zeichenfarbe des GraphicsWindow. */
+    public Color getColor() {
+        // return panel.getGraphics().getColor(); // getGraphics() has unpleasant side-effects. :(
+                /* Fixed by adding another instance variable activeColor for now. */
+        return activeColor;
+    }
+
+    /**
+     Zeichnet eine Linie in der aktuellen Zeichenfarbe.
+     @param x Anfangspunkt
+     @param y Endpunkt
+     */
+    public void drawLine(Point x, Point y){
+        // Odering points reduces the amount of graphical artifacts in rendering the same object in different ways
+        Point x1 = x;
+        Point y1 = y;
+        if ((x.x > y.x) || ((x.x == y.x) && (x.y > y.y))) {
+            x1 = y;
+            y1 = x;
+        }
+        panel.addCommand(new DrawLine(x1,y1));
+        panel.repaint();
+    }
+
+    /**
+     Zeichnet einen Punkt in der aktuellen Zeichenfarbe.
+     @param p Punkt
+     */
+    public void drawPoint(Point p){
+        drawLine(p, p);
+    }
+
+    /**
+     Zeichnet einen Punkt in der aktuellen Zeichenfarbe.
+     @param p Punkt
+     */
+    public void drawStringAt(String s, Point p){
+        Command c = new DrawString(s,p);
+        panel.addCommand(c);
+        panel.repaint();
+    }
+
+    /**
+     Zeichnet ein geometrisches Objekt.
+     */
+    public void draw(Shape s) {
+        panel.addCommand(new Draw(s));
+        panel.repaint();
+    }
+
+    /**
+     Füllt ein geometrisches Objekt aus.
+     */
+    public void fill(Shape s) {
+        panel.addCommand(new Fill(s));
+        panel.repaint();
+    }
+
+    /** Das aufrufende Programm wird für ein gegebene Zeitspanne blockiert.
+     @param millis Die Zeitspanne in Millisekunden*/
+    public void sleep(long millis) {
+        try {Thread.sleep(millis);} catch (Exception e){}
+    }
+
+    /** Setzt die Zeichenfarbe. */
+    public void setColor(Color d) {
+        activeColor = d;
+        panel.addCommand(new SetColor(activeColor));
+        panel.repaint();
+    }
+
+    /**
+     Setzt die Zeichenfarbe auf einen Grauwert
+     @param shade Grauwert zwischen 0(schwarz) und 255(weiß)
+     */
+    public void setGrayColor(int shade) {
+        setColor(new Color(shade, shade, shade));
+    }
+
+    /**
+     Setzt die Zeichenfarbe für die Mandelbrot-Aufgabe
+     @param n Anzahl der Iterationen, die durch die Farbe symboliziert werdem soll
+     */
+    public void setMandelColor(int n) {
+        float r = (float) Math.min(1.0,((double) n / 9.0) );
+        float g = (float) Math.min(1.0,((double) n / 99.0) );
+        float b = (float) Math.min(1.0,((double) n / 999.0) );
+        setColor(new Color(r, g, b));
+    }
+
+    /** Löscht das Bild */
+    public void clear() {
+//        Color oldActive = activeColor;
+        panel.clearAll();
+//        this.switchToBackgroundColor();
+//        fill(new Rectangle(0,0,width,height));
+//        setColor(oldActive);
+    }
+
+    public void killIn(int secs) {
+        Timer t  = new Timer(1000*secs, new ActionListener(){
+            @Override
+            public void actionPerformed(ActionEvent e) {dasFenster.dispose();}
+        }
+        );
+        t.setRepeats(false);
+        t.start();
+    }
+}
+
+
+class GraphicsWindowPanel extends JPanel
+{
+    private static final long serialVersionUID = 1L;
+    private ArrayList<Command> cl = new ArrayList<Command>();
+
+    public void paintComponent(Graphics g)
+    {
+        super.paintComponent(g);
+        Graphics2D g2D = (Graphics2D)g;
+
+        ArrayList<Command> cl = this.cl; // Kopie wegen Nebenläufigkeit von Swing
+        int size = cl.size();
+        for (int i=0; i<size; i++) {
+            Command c = cl.get(i);
+            if (c != null) c.execute(g2D);
+        }
+    }
+
+    void addCommand(Command c)
+    {
+        cl.add(c);
+    }
+
+    void clearAll()
+    {
+//              try {
+//                      SwingUtilities.invokeAndWait(new Runnable() {
+//                              @Override
+//                              public void run() {
+        cl = new ArrayList<Command>();
+//                              }
+//                      });
+//              } catch (InterruptedException e) {
+//                      // TODO Auto-generated catch block
+//                      e.printStackTrace();
+//              } catch (InvocationTargetException e) {
+//                      // TODO Auto-generated catch block
+//                      e.printStackTrace();
+//              }
+    }
+}
+
+
+abstract class Command //implements Serializable
+{
+    abstract  void execute(Graphics2D g2D);
+
+    /** Clone a shape. This method is needed because Shape
+     * does not define clone(), although many shape classes do.
+     * Kopiert aus jsky-2.6 auf ftp.eso.org */
+    static Shape cloneShape(Shape s) {
+        // FIXME Add more specific shapes
+        if (s instanceof RectangularShape) {
+            return (RectangularShape) ((RectangularShape) s).clone();
+        } else {
+            return new GeneralPath(s);
+        }
+    }
+
+}
+
+class DrawLine extends Command {
+    Point von;
+    Point bis;
+    DrawLine(Point von, Point bis) {
+                /* Clonen der Punkte essentiell um Aliasingeffekte beim Redraw zu verhindern */
+        this.von = new Point(von);
+        this.bis = new Point(bis);
+    }
+    void execute(Graphics2D g2D)
+    {
+        g2D.drawLine(this.von.x,this.von.y,this.bis.x,this.bis.y);
+    }
+}
+
+class SwitchToForegroundColor extends Command {
+    SwitchToForegroundColor() {}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(Color.black);
+    }
+}
+
+class SwitchToBackgroundColor extends Command {
+    Color backcolor;
+    SwitchToBackgroundColor(Color backcolor) {this.backcolor = backcolor;}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(backcolor);
+    }
+}
+
+class SetColor extends Command {
+    Color color;
+    SetColor(Color color) {this.color = color;}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(this.color);
+    }
+}
+
+
+class Draw extends Command {
+    Shape shape;
+    Draw(Shape shape) {this.shape = cloneShape(shape);}
+    void execute(Graphics2D g2D) {
+        g2D.draw(this.shape);
+    }
+}
+
+class Fill extends Command {
+    Shape shape;
+    Fill(Shape shape) {this.shape = cloneShape(shape);}
+    void execute(Graphics2D g2D) {
+        g2D.fill(this.shape);
+    }
+}
+
+class DrawString extends Command {
+    String string;
+    Point position;
+    DrawString(String string, Point position) {this.string = string; this.position = position;}
+    @Override
+    void execute(Graphics2D g2D) {
+        g2D.drawString(string, position.x, position.y);
+    }
+}
+
+
+
+
+
+
+
+
+
diff --git a/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Hexagon.java b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Hexagon.java
new file mode 100644
index 0000000..12f1031
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Hexagon.java
@@ -0,0 +1,76 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+
+class Hexagon {
+    private final Point center;
+    private final int sideLength;
+
+    public Hexagon(Point center2, int sideLength2)
+    {
+	this.center = center2;
+	this.sideLength = sideLength2;
+    }
+
+    public Point[] vertices()
+    {
+	Point vertex = new Point((int) (Math.sqrt(3) * ((double) sideLength) / 2), sideLength / 2);
+	Point[] relative = { new Point(0, sideLength)
+			     , vertex
+			     , mirrory(vertex)
+			     , new Point(0, -1 * sideLength)
+			     , mirrorx(mirrory(vertex))
+			     , mirrorx(vertex)
+	};
+
+	for (Point r : relative)
+	    r.translate(center.x, center.y);
+
+	return relative;
+    }
+
+    private static Point mirrorx(Point r)
+    {
+	return new Point(r.x * -1, r.y);
+    }
+
+    private static Point mirrory(Point r)
+    {
+	return new Point(r.x, r.y * -1);
+    }
+
+    public int height()
+    {
+	return 2 * sideLength;
+    }
+
+    public int width()
+    {
+	return (int) (Math.sqrt(3) * (double) sideLength);
+    }	
+
+    public boolean contains(Point r)
+    { // clever maths is clever (and very hexagon-specific)
+	int rx = Math.abs(r.x - center.x);
+	int ry = Math.abs(r.y - center.y);
+
+	if (rx > width() / 2 || ry > height())
+	    return false;
+	return width() * height() - height() * rx - height() * ry >= 0;
+    }
+
+    public Rectangle boundingBox()
+    {
+	Point uL = new Point(center);
+	uL.translate(-1 * width() / 2, -1 * height() / 2);
+	return new Rectangle(uL, new Dimension(width(), height()));
+    }
+
+    public Polygon asPolygon()
+    {
+	Polygon ret = new Polygon();
+	for (Point r : vertices())
+	    ret.addPoint(r.x, r.y);
+	return ret;
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Main.java b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Main.java
new file mode 100644
index 0000000..4177aca
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Main.java
@@ -0,0 +1,25 @@
+package de.lmu.tcs;
+
+
+/**
+ * Game of Life nach der Idee von John Horton Conway
+ *
+ * Fallstudie für Objektorientiertes Design nach MVC Entwurfswuster
+ * im Rahmen der
+ * "Einführung in die Programmierung" WS2015/16
+ *
+ * Lehrstuhl für Theoretische Informatik
+ * LMU München
+ *
+ * Prof Martin Hofmann, Dr Steffen Jost
+ *
+ *  Created by jost on 24.11.15.
+ */
+public class Main {
+
+    public static void main(String[] args) {
+        Spieler spieler = new Spieler();
+        spieler.spielDurchführen();
+        System.exit(0);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Param.java b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Param.java
new file mode 100644
index 0000000..9907909
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Param.java
@@ -0,0 +1,25 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+
+/**
+ * Sammlung aller extern festgelegten Konstanten
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Param {
+
+    // Konstanten für das Spiel
+    public static final int SPIEL_HÖHE   = 50;
+    public static final int SPIEL_BREITE = 80;
+
+    // Konstanten für die View
+    // public static final Color FARBE_LEBENDIG = Color.RED;
+    // public static final Color FARBE_TOT      = Color.WHITE;
+    public static final Color[] ZELLENFARBE = new Color[] {Color.WHITE, Color.RED, Color.ORANGE, Color.MAGENTA, Color.GREEN, Color.CYAN, Color.BLUE};
+    public static final int   SKALIERUNG     = 10;
+
+    // Konstanten für Durchführung
+    public static final long  RUNDENZEIT = 1000; // 120;
+    public static final int   RUNDENZAHL = 1000;
+}
diff --git a/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Position.java b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Position.java
new file mode 100644
index 0000000..9c98b77
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Position.java
@@ -0,0 +1,31 @@
+package de.lmu.tcs;
+
+/**
+ * Model
+ *
+ * Immutable
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Position {
+
+    private final int x;
+    private final int y;
+
+    public Position(int x, int y) {
+        this.x = x;
+        this.y = y;
+    }
+
+    public int getX() {
+        return this.x;
+    }
+
+    public int getY() {
+        return this.y;
+    }
+
+    public Position add(Position r) {
+	return new Position(this.x + r.x, this.y + r.y);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Spieler.java b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Spieler.java
new file mode 100644
index 0000000..a33a7db
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Spieler.java
@@ -0,0 +1,81 @@
+package de.lmu.tcs;
+
+import java.util.ArrayList;
+
+/**
+ * Controller
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Spieler {
+
+    private final Spielfeld spiel;
+    private final Ansicht ansicht;
+
+    public Spieler() {
+        this.spiel   = new Spielfeld(Param.SPIEL_BREITE,Param.SPIEL_HÖHE);
+        this.ansicht = new Ansicht(  Param.SPIEL_BREITE,Param.SPIEL_HÖHE,Param.SKALIERUNG);
+        ansicht.zeichneSpielfeld(spiel.getFeld());
+        ansicht.setText("Außerhalb Spielfeld klicken zum Beenden");
+
+        // Benutzer setzt Anfangspostionen
+        boolean nichtzuende = true;
+        do {
+            Position p = ansicht.getClick();
+            Zelle zelle = new Zelle(p, Zelle.LEBENDIG);
+            nichtzuende = spiel.setZelle(zelle);
+            if (nichtzuende) {
+                ansicht.zeichneZelle(zelle);
+            }
+        } while (nichtzuende);
+    }
+
+    public void spielDurchführen() {
+        for (int runde=0; runde < Param.RUNDENZAHL; runde++){
+            this.rundeDurchführen();
+            ansicht.setText("Runde "+runde);
+            ansicht.sleep(Param.RUNDENZEIT);
+        }
+    }
+
+
+    public void rundeDurchführen() {
+        ArrayList<Zelle> änderungen = new ArrayList<Zelle>();
+        // Änderungen anhand altem Zustand feststellen
+        for (Zelle zelle : spiel.getZellen()) {
+	    if (zelle == null)
+		continue;
+            ArrayList<Zelle> nachbarn = spiel.getNachbarn(zelle);
+            // Zelle[] nachbarn = spiel.getNachbarnAryWrapped(zelle);
+            int lebendigeNachbarn = 0;
+            for (Zelle nachbar : nachbarn) {
+                if (nachbar.istLebendig()) lebendigeNachbarn++;
+            }
+            // if (zelle.istLebendig()) {
+            //     if (lebendigeNachbarn <= 1 || lebendigeNachbarn >=4) {
+            //         Zelle neu = new Zelle(zelle.getPosition(),Zelle.TOT);
+            //         änderungen.add(neu);
+            //     }
+            // } else { // eventuell zu einem if umbauen, welches Zustand ins Gegenteil verkehrt
+            //     if (lebendigeNachbarn == 3) {
+            //         Zelle neu = new Zelle(zelle.getPosition(),Zelle.LEBENDIG);
+            //         änderungen.add(neu);
+            //     }
+            // }
+	    Zelle neu;
+	    if (zelle.istLebendig() && lebendigeNachbarn % 2 == 0)
+		neu = new Zelle(zelle.getPosition(),Zelle.TOT);
+	    else if (! zelle.istLebendig() && lebendigeNachbarn % 2 == 1)
+		neu = new Zelle(zelle.getPosition(),Zelle.LEBENDIG);
+	    else
+		neu = zelle.nachkommen();
+	    änderungen.add(neu);
+        }
+        // Erkannte Änderungen nun einpflegen
+        for (Zelle zelle : änderungen) {
+            spiel.setZelle(zelle);
+            ansicht.zeichneZelle(zelle);
+        }
+    }
+
+}
diff --git a/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Spielfeld.java b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Spielfeld.java
new file mode 100644
index 0000000..1044c1e
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Spielfeld.java
@@ -0,0 +1,205 @@
+package de.lmu.tcs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Model
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Spielfeld {
+
+    private final Zelle[][] feld;
+    private final int max_x; //Breite
+    private final int max_y; //Höhe
+
+    public Spielfeld(int breite, int höhe) {
+        this.max_x = breite;
+        this.max_y = höhe;
+        feld = new Zelle[this.max_x][this.max_y];
+	for (int y = 0; y < max_y; y++) {
+	    for (int x=0;x<max_x - (y % 2);x++) {
+                final Position p = new Position(x, y);
+                feld[x][y] = new Zelle(p, Zelle.TOT);
+            }
+        }
+    }
+
+    private boolean isValid(int x, int y)
+    {
+	return x >= 0 && x < max_x && y >= 0 && y < max_y;
+    }
+
+    /**
+     * Liefert Zelle des Spielfelds an einer Position.
+     * @param p Position, der Zelle ausgelesen werden soll
+     * @return Zelle des Spielfelds an dieser Position, falls vorhanden; sonst null.
+     */
+    public Zelle getZelle(Position p) {
+        if (isValid(p.getX(), p.getY())) {
+            return feld[p.getX()][p.getY()];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Setzt eine gegebene Zelle ins Spielfeld ein.
+     * Überschreibt vorherige Zelle.
+     *
+     * @param zelle Einzusetzende Zelle
+     * @return Ob die Position der Zelle im Spielfeld enthalten ist (false bedeutuet ungültig).
+     */
+    public boolean setZelle(Zelle zelle) {
+        final Position p = zelle.getPosition();
+        if (isValid(p.getX(), p.getY())) {
+            feld[p.getX()][p.getY()] = zelle;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Liefert das gesamte Spielfeld direkt aus;
+     * nicht so schöne, da interne Repräsentierung offenbart wird
+     * und das Array von aussen verändert werden kann! Autsch!
+     *
+     * @return Alle Zellen des Felds im 2D array
+     */
+    public Zelle[][] getFeld() {
+        return feld;
+    }
+
+    /**
+     * BESSERE ALTERNATIVE zu getter-Methode getFeld():
+     * Liefert alle Zellen des Spielfeldes aus. Vorteile:
+     * 1) Interne Repräsentation bleibt versteckt.
+     * 2) Da die Zellen immutable sind, kann hier das
+     * Spielfeld auch nicht woanders manipuliert werden.
+     *
+     * @return Alle Zellen des Spielfeldes als ArrayList
+     */
+    public ArrayList<Zelle> getZellen() {
+        ArrayList<Zelle> result = new ArrayList<>(max_x*max_y);
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                result.add(feld[x][y]);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Genau wie getZellen, nur mit echtem Array anstatt ArrayList.
+     * Vorteile bleiben erhalten!
+     *
+     * @return Alle Zellen des Spielfeldes als Array
+     */
+    public Zelle[] getZellenAry() {
+        Zelle[] result = new Zelle[max_x*max_y];
+        int i = 0;
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                result[i] = feld[x][y];
+                i++;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle.
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public ArrayList<Zelle> getNachbarn(Zelle zelle) {
+        ArrayList<Zelle> result = new ArrayList<>();
+	if (zelle == null)
+	    return result;
+        Position pos = zelle.getPosition();
+	Position[] offsets = { new Position(0, -1), new Position(1, -1)
+			       , new Position(-1, 0), new Position(1, 0)
+			       , new Position(0, 1), new Position (1, 1)
+	};
+        for (Position offset : offsets) {
+	    Zelle nachbar = this.getZelle(pos.add(offset));
+	    if (nachbar != null) {
+		result.add(nachbar);
+	    }
+        }
+        return result;
+    }
+
+   //  /**
+   //   * Berechnet alle Nachbarn einer Zelle.
+   //   * Variante von getNachbar mit Array anstatt ArrayList
+   //   *
+   //   * @param zelle deren Nachbarn berechnet werden sollen
+   //   * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+   //   */
+   // public Zelle[] getNachbarnAry(Zelle zelle) {
+   //      Position pos = zelle.getPosition();
+   //      int minx = Math.max(pos.getX() - 1, 0);
+   //      int maxx = Math.min(pos.getX() + 1, this.max_x);
+   //      int miny = Math.max(pos.getY() - 1, 0);
+   //      int maxy = Math.min(pos.getY() + 1, this.max_y);
+   //      Zelle[] result = new Zelle[maxx - minx * maxy - miny];
+   //      int i = 0;
+   //      for (int x = minx; x <= maxx; x++) {
+   //          for (int y = miny; y <= maxy; y++) {
+   //              if (x!=0 || y!=0) {
+   //                  result[i] = feld[x][y];
+   //                  i++;
+   //              }
+   //          }
+   //      }
+   //      return result;
+   //  }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle auf Wrap-Around Spielfeld..
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public ArrayList<Zelle> getNachbarnWrapped(Zelle zelle) {
+        ArrayList<Zelle> result = new ArrayList<Zelle>(8);
+        Position pos = zelle.getPosition();
+        for (int x = -1; x <= 1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle z =  getZelle(new Position((pos.getX() + x + max_x )% max_x, (pos.getY() + y + max_y) % max_y));
+                    result.add(z);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle auf Warap-Around Spielfeld.
+     * Variante von getNachbarWrapped mit Array anstatt ArrayList
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public Zelle[] getNachbarnAryWrapped(Zelle zelle) {
+        Zelle[] result = new Zelle[8];
+        Position pos = zelle.getPosition();
+        int i = 0;
+        for (int x = -1; x <= 1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle z =  getZelle(new Position((pos.getX() + x + max_x )% max_x, (pos.getY() + y + max_y) % max_y));
+                    result[i] = z;
+                    i++;
+                }
+            }
+        }
+        return result;
+    }
+}
diff --git a/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Zelle.java b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Zelle.java
new file mode 100644
index 0000000..a7c6ad6
--- /dev/null
+++ b/ws2015/eip/blaetter/07/H7-1C/de/lmu/tcs/Zelle.java
@@ -0,0 +1,47 @@
+package de.lmu.tcs;
+
+/**
+ * Model
+ *
+ * Immutable
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Zelle {
+
+    public final static int TOT=0;
+    public final static int LEBENDIG=1;
+
+    private final Position position;
+    private final int zustand;
+
+    public Zelle(Position position, int zustand) {
+        this.position = position;
+        this.zustand = zustand;
+    }
+
+    public Zelle(Zelle old) {
+	this.position = old.position;
+	this.zustand = old.zustand;
+    }
+
+    public Position getPosition() {
+        return position;
+    }
+
+    public boolean istLebendig() {
+        return zustand>=LEBENDIG;
+    }
+
+    public boolean istTot() {
+        return zustand==TOT;
+    }
+
+    public Zelle nachkommen() {
+	return this.istTot() ? (new Zelle(this)) : (new Zelle(position, zustand + 1));
+    }
+
+    public int alter() {
+	return this.istTot() ? -1 : (this.zustand - 1);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/de/lmu/tcs/Ansicht.java b/ws2015/eip/blaetter/07/de/lmu/tcs/Ansicht.java
new file mode 100644
index 0000000..49d3375
--- /dev/null
+++ b/ws2015/eip/blaetter/07/de/lmu/tcs/Ansicht.java
@@ -0,0 +1,64 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+
+/**
+ * View
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Ansicht {
+
+    private final GraphicsWindow fenster;
+    private final int max_x; //Breite
+    private final int max_y; //Höhe
+    private final int skalierung;
+
+
+    public Ansicht(int x, int y, int skalierung) {
+        this.max_x = x;
+        this.max_y = y;
+        this.skalierung = skalierung;
+        this.fenster = new GraphicsWindow(max_x * skalierung, max_y * skalierung);
+    }
+
+    public void zeichenZelle(Zelle zelle) {
+        Position pos = zelle.getPosition();
+        Rectangle box = new Rectangle(pos.getX() * skalierung, pos.getY() * skalierung, skalierung - 1, skalierung - 1);
+        if (zelle.istTot()) {
+            fenster.setColor(Param.ZELLENFARBE[0]);
+        } else {
+            fenster.setColor(Param.ZELLENFARBE[Math.min(zelle.alter() + 1, Param.ZELLENFARBE.length - 1)]);
+        }
+        fenster.fill(box);
+    }
+
+    public void zeichneSpielfeld(Zelle[][] feld) {
+        fenster.clear();
+
+//        for (int x = 0; x < max_x; x++) {
+//            for (int y = 0; y < max_y; y++) {
+//                zeichenZelle(feld[x][y]);
+//        }
+//      Äquivalente Alternative ohne explizite Indizes:
+        for (Zelle[] zeile : feld) {
+            for (Zelle zelle : zeile) {
+                zeichenZelle(zelle);
+            }
+        }
+    }
+
+    public Position getClick() {
+        Point point = fenster.mouseClick();
+        Position result =  new Position(point.x / skalierung, point.y /skalierung);
+        return  result;
+    }
+
+    public void sleep(long delay) {
+        fenster.sleep(delay);
+    }
+
+    public void setText(String message) {
+        fenster.setText(message);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/de/lmu/tcs/GraphicsWindow.java b/ws2015/eip/blaetter/07/de/lmu/tcs/GraphicsWindow.java
new file mode 100644
index 0000000..a1f90bf
--- /dev/null
+++ b/ws2015/eip/blaetter/07/de/lmu/tcs/GraphicsWindow.java
@@ -0,0 +1,393 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+import java.util.ArrayList;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.Timer;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.MouseEvent;
+import java.awt.geom.RectangularShape;
+import java.awt.geom.GeneralPath;
+
+/**
+ Eine Klasse zu pädagogischen Zwecken.
+ Erlaubt die Eingabe von Punktkoordinaten
+ mittels Mausklicks, das Zeichnen einfacher
+ 2D Objekte (java.awt.Shape), sowie die
+ Ausgabe von Texten in einer Statuszeile.
+ @version 3.043
+ @author Martin Hofmann und die EiP-Teams verschiedener Jahre
+ */
+
+public class GraphicsWindow {
+
+    private int width;
+    private int height;
+    private JFrame dasFenster;
+    private static int fensterZahl;
+    private static int fensterNr;
+    private Label label;
+    private GraphicsWindowPanel panel;
+    private Point mousePos;
+    private Color activeColor = Color.BLACK;
+    final private Color backColor = Color.WHITE;
+    MyMouseAdapter mouseListener;
+
+    /**
+     Erzeugt ein Fenster der Größe 640 auf 480 mit Textausgabe, Mauseingabe und Grafikausgabe.
+     */
+    public GraphicsWindow() {
+        this(640, 480);
+    }
+
+    /**
+     Erzeugt ein Fenster in vorgegebener Größe mit Textausgabe, Mauseingabe und Grafikausgabe.
+     @param width Breite des Fensters
+     @param height Höhe des Fensters
+     */
+    public GraphicsWindow(int width, int height) {
+        this.width  = width;
+        this.height = height;
+        dasFenster  = new JFrame();
+        dasFenster.setTitle("Grafikfenster " + ++fensterNr);
+        fensterZahl++;
+        dasFenster.setLocationByPlatform(true);
+        dasFenster.setSize(width,height+50);
+        dasFenster.getContentPane().setPreferredSize(new Dimension(width, height+50));
+        dasFenster.pack();
+        dasFenster.addWindowListener(new WindowAdapter(){
+            public void windowClosing(WindowEvent e) {
+                dasFenster.dispose(); // nicht gleich alle Fenster abschiessen
+                if (--fensterZahl<1) System.exit(0);
+            }
+        });
+
+        label = new Label("Statuszeile...");
+        label.setFont(new Font("Helvetica", Font.PLAIN, 12));
+        dasFenster.getContentPane().add(label,"North" );
+        panel = new GraphicsWindowPanel();
+        //panel.setBackground(Color.cyan);
+        panel.addCommand(new SetColor(activeColor));
+        dasFenster.getContentPane().add(panel,"Center");
+        mousePos = new Point();
+        mouseListener = new MyMouseAdapter();
+        panel.addMouseListener(mouseListener);
+        clear();
+        dasFenster.setVisible(true);
+    }
+
+    /**
+     Gibt eine Zeichenkette oben im Fenster aus.
+     @param text diese Zeichenkette
+     */
+    public void setText(String text) {
+        label.setText(text);
+    }
+    /**
+     Liest den oben im Fenster angezeigten Text aus.
+     @return den Text
+     */
+    public String getText() {
+        return label.getText();
+    }
+    /**
+     Wartet auf einen Mausklick. Die Methode blockiert das
+     aufrufende Programm solange bis der Mausklick erfolgt ist.
+     @return die Koordinaten des angeklickten Punkts
+     */
+
+    public Point mouseClick() {
+        try{
+            synchronized(mouseListener){mouseListener.wait();}
+        }
+        catch(InterruptedException e){
+            e.printStackTrace();
+        }
+        return mousePos;
+    }
+
+    class MyMouseAdapter extends MouseAdapter {
+
+        /**
+         Beendet das Warten auf den Mausklick und verwertet die Koordinaten.
+         Diese Methode ist nicht für den Anwender bestimmt.
+         */
+
+        synchronized public void mouseClicked(MouseEvent e){
+            mousePos = e.getPoint();
+            notifyAll();
+        }
+    }
+
+
+    /**
+     Schaltet die Zeichenfarbe auf die Hintergrundfarbe um. Dies ist
+     das Mittel, um gezeichnete Linien wieder zu löschen.
+     */
+    public void switchToBackgroundColor(){
+        activeColor = backColor;
+        panel.addCommand(new SwitchToBackgroundColor(activeColor));
+        panel.repaint();
+    }
+
+    /**
+     Schaltet die Zeichenfarbe auf Schwarz um.
+     */
+    public void switchToForegroundColor(){
+        activeColor = Color.BLACK;
+        panel.addCommand(new SetColor(activeColor));
+        panel.repaint();
+    }
+
+
+    /** Liefert die aktuelle Zeichenfarbe.
+     @return die aktuelle Zeichenfarbe des GraphicsWindow. */
+    public Color getColor() {
+        // return panel.getGraphics().getColor(); // getGraphics() has unpleasant side-effects. :(
+                /* Fixed by adding another instance variable activeColor for now. */
+        return activeColor;
+    }
+
+    /**
+     Zeichnet eine Linie in der aktuellen Zeichenfarbe.
+     @param x Anfangspunkt
+     @param y Endpunkt
+     */
+    public void drawLine(Point x, Point y){
+        // Odering points reduces the amount of graphical artifacts in rendering the same object in different ways
+        Point x1 = x;
+        Point y1 = y;
+        if ((x.x > y.x) || ((x.x == y.x) && (x.y > y.y))) {
+            x1 = y;
+            y1 = x;
+        }
+        panel.addCommand(new DrawLine(x1,y1));
+        panel.repaint();
+    }
+
+    /**
+     Zeichnet einen Punkt in der aktuellen Zeichenfarbe.
+     @param p Punkt
+     */
+    public void drawPoint(Point p){
+        drawLine(p, p);
+    }
+
+    /**
+     Zeichnet einen Punkt in der aktuellen Zeichenfarbe.
+     @param p Punkt
+     */
+    public void drawStringAt(String s, Point p){
+        Command c = new DrawString(s,p);
+        panel.addCommand(c);
+        panel.repaint();
+    }
+
+    /**
+     Zeichnet ein geometrisches Objekt.
+     */
+    public void draw(Shape s) {
+        panel.addCommand(new Draw(s));
+        panel.repaint();
+    }
+
+    /**
+     Füllt ein geometrisches Objekt aus.
+     */
+    public void fill(Shape s) {
+        panel.addCommand(new Fill(s));
+        panel.repaint();
+    }
+
+    /** Das aufrufende Programm wird für ein gegebene Zeitspanne blockiert.
+     @param millis Die Zeitspanne in Millisekunden*/
+    public void sleep(long millis) {
+        try {Thread.sleep(millis);} catch (Exception e){}
+    }
+
+    /** Setzt die Zeichenfarbe. */
+    public void setColor(Color d) {
+        activeColor = d;
+        panel.addCommand(new SetColor(activeColor));
+        panel.repaint();
+    }
+
+    /**
+     Setzt die Zeichenfarbe auf einen Grauwert
+     @param shade Grauwert zwischen 0(schwarz) und 255(weiß)
+     */
+    public void setGrayColor(int shade) {
+        setColor(new Color(shade, shade, shade));
+    }
+
+    /**
+     Setzt die Zeichenfarbe für die Mandelbrot-Aufgabe
+     @param n Anzahl der Iterationen, die durch die Farbe symboliziert werdem soll
+     */
+    public void setMandelColor(int n) {
+        float r = (float) Math.min(1.0,((double) n / 9.0) );
+        float g = (float) Math.min(1.0,((double) n / 99.0) );
+        float b = (float) Math.min(1.0,((double) n / 999.0) );
+        setColor(new Color(r, g, b));
+    }
+
+    /** Löscht das Bild */
+    public void clear() {
+//        Color oldActive = activeColor;
+        panel.clearAll();
+//        this.switchToBackgroundColor();
+//        fill(new Rectangle(0,0,width,height));
+//        setColor(oldActive);
+    }
+
+    public void killIn(int secs) {
+        Timer t  = new Timer(1000*secs, new ActionListener(){
+            @Override
+            public void actionPerformed(ActionEvent e) {dasFenster.dispose();}
+        }
+        );
+        t.setRepeats(false);
+        t.start();
+    }
+}
+
+
+class GraphicsWindowPanel extends JPanel
+{
+    private static final long serialVersionUID = 1L;
+    private ArrayList<Command> cl = new ArrayList<Command>();
+
+    public void paintComponent(Graphics g)
+    {
+        super.paintComponent(g);
+        Graphics2D g2D = (Graphics2D)g;
+
+        ArrayList<Command> cl = this.cl; // Kopie wegen Nebenläufigkeit von Swing
+        int size = cl.size();
+        for (int i=0; i<size; i++) {
+            Command c = cl.get(i);
+            if (c != null) c.execute(g2D);
+        }
+    }
+
+    void addCommand(Command c)
+    {
+        cl.add(c);
+    }
+
+    void clearAll()
+    {
+//              try {
+//                      SwingUtilities.invokeAndWait(new Runnable() {
+//                              @Override
+//                              public void run() {
+        cl = new ArrayList<Command>();
+//                              }
+//                      });
+//              } catch (InterruptedException e) {
+//                      // TODO Auto-generated catch block
+//                      e.printStackTrace();
+//              } catch (InvocationTargetException e) {
+//                      // TODO Auto-generated catch block
+//                      e.printStackTrace();
+//              }
+    }
+}
+
+
+abstract class Command //implements Serializable
+{
+    abstract  void execute(Graphics2D g2D);
+
+    /** Clone a shape. This method is needed because Shape
+     * does not define clone(), although many shape classes do.
+     * Kopiert aus jsky-2.6 auf ftp.eso.org */
+    static Shape cloneShape(Shape s) {
+        // FIXME Add more specific shapes
+        if (s instanceof RectangularShape) {
+            return (RectangularShape) ((RectangularShape) s).clone();
+        } else {
+            return new GeneralPath(s);
+        }
+    }
+
+}
+
+class DrawLine extends Command {
+    Point von;
+    Point bis;
+    DrawLine(Point von, Point bis) {
+                /* Clonen der Punkte essentiell um Aliasingeffekte beim Redraw zu verhindern */
+        this.von = new Point(von);
+        this.bis = new Point(bis);
+    }
+    void execute(Graphics2D g2D)
+    {
+        g2D.drawLine(this.von.x,this.von.y,this.bis.x,this.bis.y);
+    }
+}
+
+class SwitchToForegroundColor extends Command {
+    SwitchToForegroundColor() {}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(Color.black);
+    }
+}
+
+class SwitchToBackgroundColor extends Command {
+    Color backcolor;
+    SwitchToBackgroundColor(Color backcolor) {this.backcolor = backcolor;}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(backcolor);
+    }
+}
+
+class SetColor extends Command {
+    Color color;
+    SetColor(Color color) {this.color = color;}
+    void execute(Graphics2D g2D) {
+        g2D.setColor(this.color);
+    }
+}
+
+
+class Draw extends Command {
+    Shape shape;
+    Draw(Shape shape) {this.shape = cloneShape(shape);}
+    void execute(Graphics2D g2D) {
+        g2D.draw(this.shape);
+    }
+}
+
+class Fill extends Command {
+    Shape shape;
+    Fill(Shape shape) {this.shape = cloneShape(shape);}
+    void execute(Graphics2D g2D) {
+        g2D.fill(this.shape);
+    }
+}
+
+class DrawString extends Command {
+    String string;
+    Point position;
+    DrawString(String string, Point position) {this.string = string; this.position = position;}
+    @Override
+    void execute(Graphics2D g2D) {
+        g2D.drawString(string, position.x, position.y);
+    }
+}
+
+
+
+
+
+
+
+
+
diff --git a/ws2015/eip/blaetter/07/de/lmu/tcs/Main.java b/ws2015/eip/blaetter/07/de/lmu/tcs/Main.java
new file mode 100644
index 0000000..4177aca
--- /dev/null
+++ b/ws2015/eip/blaetter/07/de/lmu/tcs/Main.java
@@ -0,0 +1,25 @@
+package de.lmu.tcs;
+
+
+/**
+ * Game of Life nach der Idee von John Horton Conway
+ *
+ * Fallstudie für Objektorientiertes Design nach MVC Entwurfswuster
+ * im Rahmen der
+ * "Einführung in die Programmierung" WS2015/16
+ *
+ * Lehrstuhl für Theoretische Informatik
+ * LMU München
+ *
+ * Prof Martin Hofmann, Dr Steffen Jost
+ *
+ *  Created by jost on 24.11.15.
+ */
+public class Main {
+
+    public static void main(String[] args) {
+        Spieler spieler = new Spieler();
+        spieler.spielDurchführen();
+        System.exit(0);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/de/lmu/tcs/Param.java b/ws2015/eip/blaetter/07/de/lmu/tcs/Param.java
new file mode 100644
index 0000000..88f8248
--- /dev/null
+++ b/ws2015/eip/blaetter/07/de/lmu/tcs/Param.java
@@ -0,0 +1,26 @@
+package de.lmu.tcs;
+
+import java.awt.*;
+
+/**
+ * Sammlung aller extern festgelegten Konstanten
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Param {
+
+    // Konstanten für das Spiel
+    public static final int SPIEL_HÖHE   = 50;
+    public static final int SPIEL_BREITE = 80;
+
+    // Konstanten für die View
+    // public static final Color FARBE_LEBENDIG = Color.RED;
+    // public static final Color FARBE_TOT      = Color.WHITE;
+    public static final Color[] ZELLENFARBE = new Color[] {Color.WHITE, Color.RED, Color.ORANGE, Color.MAGENTA, Color.GREEN, Color.CYAN, Color.BLUE};
+    public static final int   SKALIERUNG     = 10;
+
+    // Konstanten für Durchführung
+    public static final long  RUNDENZEIT = 120;
+    public static final int   RUNDENZAHL = 1000;
+
+}
diff --git a/ws2015/eip/blaetter/07/de/lmu/tcs/Position.java b/ws2015/eip/blaetter/07/de/lmu/tcs/Position.java
new file mode 100644
index 0000000..546da7f
--- /dev/null
+++ b/ws2015/eip/blaetter/07/de/lmu/tcs/Position.java
@@ -0,0 +1,27 @@
+package de.lmu.tcs;
+
+/**
+ * Model
+ *
+ * Immutable
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Position {
+
+    private final int x;
+    private final int y;
+
+    public Position(int x, int y) {
+        this.x = x;
+        this.y = y;
+    }
+
+    public int getX() {
+        return this.x;
+    }
+
+    public int getY() {
+        return this.y;
+    }
+}
diff --git a/ws2015/eip/blaetter/07/de/lmu/tcs/Spieler.java b/ws2015/eip/blaetter/07/de/lmu/tcs/Spieler.java
new file mode 100644
index 0000000..98bca6e
--- /dev/null
+++ b/ws2015/eip/blaetter/07/de/lmu/tcs/Spieler.java
@@ -0,0 +1,79 @@
+package de.lmu.tcs;
+
+import java.util.ArrayList;
+
+/**
+ * Controller
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Spieler {
+
+    private final Spielfeld spiel;
+    private final Ansicht ansicht;
+
+    public Spieler() {
+        this.spiel   = new Spielfeld(Param.SPIEL_BREITE,Param.SPIEL_HÖHE);
+        this.ansicht = new Ansicht(  Param.SPIEL_BREITE,Param.SPIEL_HÖHE,Param.SKALIERUNG);
+        ansicht.zeichneSpielfeld(spiel.getFeld());
+        ansicht.setText("Außerhalb Spielfeld klicken zum Beenden");
+
+        // Benutzer setzt Anfangspostionen
+        boolean nichtzuende = true;
+        do {
+            Position p = ansicht.getClick();
+            Zelle zelle = new Zelle(p, Zelle.LEBENDIG);
+            nichtzuende = spiel.setZelle(zelle);
+            if (nichtzuende) {
+                ansicht.zeichenZelle(zelle);
+            }
+        } while (nichtzuende);
+    }
+
+    public void spielDurchführen() {
+        for (int runde=0; runde < Param.RUNDENZAHL; runde++){
+            this.rundeDurchführen();
+            ansicht.setText("Runde "+runde);
+            ansicht.sleep(Param.RUNDENZEIT);
+        }
+    }
+
+
+    public void rundeDurchführen() {
+        ArrayList<Zelle> änderungen = new ArrayList<Zelle>();
+        // Änderungen anhand altem Zustand feststellen
+        for (Zelle zelle : spiel.getZellen()) {
+//            ArrayList<Zelle> nachbarn = spiel.getNachbarn(zelle);
+            Zelle[] nachbarn = spiel.getNachbarnAryWrapped(zelle);
+            int lebendigeNachbarn = 0;
+            for (Zelle nachbar : nachbarn) {
+                if (nachbar.istLebendig()) lebendigeNachbarn++;
+            }
+            // if (zelle.istLebendig()) {
+            //     if (lebendigeNachbarn <= 1 || lebendigeNachbarn >=4) {
+            //         Zelle neu = new Zelle(zelle.getPosition(),Zelle.TOT);
+            //         änderungen.add(neu);
+            //     }
+            // } else { // eventuell zu einem if umbauen, welches Zustand ins Gegenteil verkehrt
+            //     if (lebendigeNachbarn == 3) {
+            //         Zelle neu = new Zelle(zelle.getPosition(),Zelle.LEBENDIG);
+            //         änderungen.add(neu);
+            //     }
+            // }
+	    Zelle neu;
+	    if (zelle.istLebendig() && lebendigeNachbarn % 2 == 0)
+		neu = new Zelle(zelle.getPosition(),Zelle.TOT);
+	    else if (! zelle.istLebendig() && lebendigeNachbarn % 2 == 1)
+		neu = new Zelle(zelle.getPosition(),Zelle.LEBENDIG);
+	    else
+		neu = zelle.nachkommen();
+	    änderungen.add(neu);
+        }
+        // Erkannte Änderungen nun einpflegen
+        for (Zelle zelle : änderungen) {
+            spiel.setZelle(zelle);
+            ansicht.zeichenZelle(zelle);
+        }
+    }
+
+}
diff --git a/ws2015/eip/blaetter/07/de/lmu/tcs/Spielfeld.java b/ws2015/eip/blaetter/07/de/lmu/tcs/Spielfeld.java
new file mode 100644
index 0000000..7b9ec60
--- /dev/null
+++ b/ws2015/eip/blaetter/07/de/lmu/tcs/Spielfeld.java
@@ -0,0 +1,198 @@
+package de.lmu.tcs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Model
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Spielfeld {
+
+    private final Zelle[][] feld;
+    private final int max_x; //Breite
+    private final int max_y; //Höhe
+
+    public Spielfeld(int breite, int höhe) {
+        this.max_x = breite;
+        this.max_y = höhe;
+        feld = new Zelle[this.max_x][this.max_y];
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                final Position p = new Position(x, y);
+                feld[x][y] = new Zelle(p, Zelle.TOT);
+            }
+        }
+    }
+
+    /**
+     * Liefert Zelle des Spielfelds an einer Position.
+     * @param p Position, der Zelle ausgelesen werden soll
+     * @return Zelle des Spielfelds an dieser Position, falls vorhanden; sonst null.
+     */
+    public Zelle getZelle(Position p) {
+        if (p.getX() >= 0 && p.getX() < max_x && p.getY() >= 0 && p.getY() < max_y) {
+            return feld[p.getX()][p.getY()];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Setzt eine gegebene Zelle ins Spielfeld ein.
+     * Überschreibt vorherige Zelle.
+     *
+     * @param zelle Einzusetzende Zelle
+     * @return Ob die Position der Zelle im Spielfeld enthalten ist (false bedeutuet ungültig).
+     */
+    public boolean setZelle(Zelle zelle) {
+        final Position p = zelle.getPosition();
+        if (p.getX() >= 0 && p.getX() < max_x && p.getY() >= 0 && p.getY() < max_y) {
+            feld[p.getX()][p.getY()] = zelle;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Liefert das gesamte Spielfeld direkt aus;
+     * nicht so schöne, da interne Repräsentierung offenbart wird
+     * und das Array von aussen verändert werden kann! Autsch!
+     *
+     * @return Alle Zellen des Felds im 2D array
+     */
+    public Zelle[][] getFeld() {
+        return feld;
+    }
+
+    /**
+     * BESSERE ALTERNATIVE zu getter-Methode getFeld():
+     * Liefert alle Zellen des Spielfeldes aus. Vorteile:
+     * 1) Interne Repräsentation bleibt versteckt.
+     * 2) Da die Zellen immutable sind, kann hier das
+     * Spielfeld auch nicht woanders manipuliert werden.
+     *
+     * @return Alle Zellen des Spielfeldes als ArrayList
+     */
+    public ArrayList<Zelle> getZellen() {
+        ArrayList<Zelle> result = new ArrayList<>(max_x*max_y);
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                result.add(feld[x][y]);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Genau wie getZellen, nur mit echtem Array anstatt ArrayList.
+     * Vorteile bleiben erhalten!
+     *
+     * @return Alle Zellen des Spielfeldes als Array
+     */
+    public Zelle[] getZellenAry() {
+        Zelle[] result = new Zelle[max_x*max_y];
+        int i = 0;
+        for (int x=0;x<max_x;x++) {
+            for (int y = 0; y < max_y; y++) {
+                result[i] = feld[x][y];
+                i++;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle.
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public ArrayList<Zelle> getNachbarn(Zelle zelle) {
+        ArrayList<Zelle> result = new ArrayList<>();
+        Position pos = zelle.getPosition();
+        for (int x=-1; x<=1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle nachbar = this.getZelle(new Position(pos.getX() + x, pos.getY() + y));
+                    if (nachbar != null) {
+                        result.add(nachbar);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle.
+     * Variante von getNachbar mit Array anstatt ArrayList
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+   public Zelle[] getNachbarnAry(Zelle zelle) {
+        Position pos = zelle.getPosition();
+        int minx = Math.max(pos.getX() - 1, 0);
+        int maxx = Math.min(pos.getX() + 1, this.max_x);
+        int miny = Math.max(pos.getY() - 1, 0);
+        int maxy = Math.min(pos.getY() + 1, this.max_y);
+        Zelle[] result = new Zelle[maxx - minx * maxy - miny];
+        int i = 0;
+        for (int x = minx; x <= maxx; x++) {
+            for (int y = miny; y <= maxy; y++) {
+                if (x!=0 || y!=0) {
+                    result[i] = feld[x][y];
+                    i++;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle auf Wrap-Around Spielfeld..
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public ArrayList<Zelle> getNachbarnWrapped(Zelle zelle) {
+        ArrayList<Zelle> result = new ArrayList<Zelle>(8);
+        Position pos = zelle.getPosition();
+        for (int x = -1; x <= 1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle z =  getZelle(new Position((pos.getX() + x + max_x )% max_x, (pos.getY() + y + max_y) % max_y));
+                    result.add(z);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Berechnet alle Nachbarn einer Zelle auf Warap-Around Spielfeld.
+     * Variante von getNachbarWrapped mit Array anstatt ArrayList
+     *
+     * @param zelle deren Nachbarn berechnet werden sollen
+     * @return alle Nachbarn von {@code zelle}, Anzahl Nachbarn variabel
+     */
+    public Zelle[] getNachbarnAryWrapped(Zelle zelle) {
+        Zelle[] result = new Zelle[8];
+        Position pos = zelle.getPosition();
+        int i = 0;
+        for (int x = -1; x <= 1; x++) {
+            for (int y = -1; y <= 1; y++) {
+                if (x!=0 || y!=0) {
+                    Zelle z =  getZelle(new Position((pos.getX() + x + max_x )% max_x, (pos.getY() + y + max_y) % max_y));
+                    result[i] = z;
+                    i++;
+                }
+            }
+        }
+        return result;
+    }
+}
diff --git a/ws2015/eip/blaetter/07/de/lmu/tcs/Zelle.java b/ws2015/eip/blaetter/07/de/lmu/tcs/Zelle.java
new file mode 100644
index 0000000..a7c6ad6
--- /dev/null
+++ b/ws2015/eip/blaetter/07/de/lmu/tcs/Zelle.java
@@ -0,0 +1,47 @@
+package de.lmu.tcs;
+
+/**
+ * Model
+ *
+ * Immutable
+ *
+ * Created by jost on 24.11.15.
+ */
+public class Zelle {
+
+    public final static int TOT=0;
+    public final static int LEBENDIG=1;
+
+    private final Position position;
+    private final int zustand;
+
+    public Zelle(Position position, int zustand) {
+        this.position = position;
+        this.zustand = zustand;
+    }
+
+    public Zelle(Zelle old) {
+	this.position = old.position;
+	this.zustand = old.zustand;
+    }
+
+    public Position getPosition() {
+        return position;
+    }
+
+    public boolean istLebendig() {
+        return zustand>=LEBENDIG;
+    }
+
+    public boolean istTot() {
+        return zustand==TOT;
+    }
+
+    public Zelle nachkommen() {
+	return this.istTot() ? (new Zelle(this)) : (new Zelle(position, zustand + 1));
+    }
+
+    public int alter() {
+	return this.istTot() ? -1 : (this.zustand - 1);
+    }
+}
diff --git a/ws2015/eip/blaetter/07/manifest b/ws2015/eip/blaetter/07/manifest
new file mode 100644
index 0000000..2e42f40
--- /dev/null
+++ b/ws2015/eip/blaetter/07/manifest
@@ -0,0 +1,3 @@
+H7-1A
+H7-1B
+H7-1C
\ No newline at end of file
-- 
cgit v1.2.3