From 0ad31dcca37df9891ed5d5b70f12a966fc821c6d Mon Sep 17 00:00:00 2001 From: Gregor Kleen 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 cl = new ArrayList(); + + public void paintComponent(Graphics g) + { + super.paintComponent(g); + Graphics2D g2D = (Graphics2D)g; + + ArrayList cl = this.cl; // Kopie wegen Nebenläufigkeit von Swing + int size = cl.size(); + for (int i=0; i(); +// } +// }); +// } 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 änderungen = new ArrayList(); + // Änderungen anhand altem Zustand feststellen + for (Zelle zelle : spiel.getZellen()) { +// ArrayList 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= 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 getZellen() { + ArrayList result = new ArrayList<>(max_x*max_y); + for (int x=0;x getNachbarn(Zelle zelle) { + ArrayList 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 getNachbarnWrapped(Zelle zelle) { + ArrayList result = new ArrayList(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 cl = new ArrayList(); + + public void paintComponent(Graphics g) + { + super.paintComponent(g); + Graphics2D g2D = (Graphics2D)g; + + ArrayList cl = this.cl; // Kopie wegen Nebenläufigkeit von Swing + int size = cl.size(); + for (int i=0; i(); +// } +// }); +// } 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 änderungen = new ArrayList(); + // Änderungen anhand altem Zustand feststellen + for (Zelle zelle : spiel.getZellen()) { +// ArrayList 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= 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 getZellen() { + ArrayList result = new ArrayList<>(max_x*max_y); + for (int x=0;x getNachbarn(Zelle zelle) { + ArrayList 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 getNachbarnWrapped(Zelle zelle) { + ArrayList result = new ArrayList(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 cl = new ArrayList(); + + public void paintComponent(Graphics g) + { + super.paintComponent(g); + Graphics2D g2D = (Graphics2D)g; + + ArrayList cl = this.cl; // Kopie wegen Nebenläufigkeit von Swing + int size = cl.size(); + for (int i=0; i(); +// } +// }); +// } 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 änderungen = new ArrayList(); + // Änderungen anhand altem Zustand feststellen + for (Zelle zelle : spiel.getZellen()) { + if (zelle == null) + continue; + ArrayList 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= 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 getZellen() { + ArrayList result = new ArrayList<>(max_x*max_y); + for (int x=0;x getNachbarn(Zelle zelle) { + ArrayList 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 getNachbarnWrapped(Zelle zelle) { + ArrayList result = new ArrayList(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 cl = new ArrayList(); + + public void paintComponent(Graphics g) + { + super.paintComponent(g); + Graphics2D g2D = (Graphics2D)g; + + ArrayList cl = this.cl; // Kopie wegen Nebenläufigkeit von Swing + int size = cl.size(); + for (int i=0; i(); +// } +// }); +// } 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 änderungen = new ArrayList(); + // Änderungen anhand altem Zustand feststellen + for (Zelle zelle : spiel.getZellen()) { +// ArrayList 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= 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 getZellen() { + ArrayList result = new ArrayList<>(max_x*max_y); + for (int x=0;x getNachbarn(Zelle zelle) { + ArrayList 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 getNachbarnWrapped(Zelle zelle) { + ArrayList result = new ArrayList(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