initial commit

This commit is contained in:
Dominic 2019-11-29 19:27:56 +01:00
commit c74d331b66
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
17 changed files with 1699 additions and 0 deletions

147
tut6/src/BoolTreeNode.java Normal file
View file

@ -0,0 +1,147 @@
public class BoolTreeNode
{
private String variable;
private BoolTreeNode child1;
private BoolTreeNode child2;
private BoolTreeNode(String variableInput)
{
variable = variableInput;
}
private BoolTreeNode(BoolTreeNode negated)
{
child1 = negated;
}
private BoolTreeNode(BoolTreeNode kind1, BoolTreeNode kind2)
{
child1 = kind1;
child2 = kind2;
}
public static BoolTreeNode boolTreeTrueNode()
{
return new BoolTreeNode("true");
}
public static BoolTreeNode boolTreeFalseNode()
{
return new BoolTreeNode("false");
}
public static BoolTreeNode boolTreeVariableNode(String variableInput)
{
if (variableInput == null || variableInput.length() == 0 || variableInput.equals("true") || variableInput.equals("false"))
{
Utils.error("ungueltiger Name der Variablen");
return null;
}
return new BoolTreeNode(variableInput);
}
public static BoolTreeNode boolTreeNotNode(BoolTreeNode negated)
{
return new BoolTreeNode(negated);
}
public static BoolTreeNode boolTreeAndNode(BoolTreeNode child1, BoolTreeNode child2)
{
return new BoolTreeNode(child1, child2);
}
public int depth()
{
if (child2 != null) // konjunktionsknoten
{
int depth1 = child1.depth();
int depth2 = child2.depth();
return Utils.max(depth1, depth2) + 1;
}
if (child1 != null) // negationsknoten
{
return child1.depth() + 1;
}
// variablenknoten
return 0;
}
public boolean isLeaf()
{
return (depth() == 0);
}
public boolean isTrueLeaf()
{
return isLeaf() && variable.equals("true");
}
public boolean isFalseLeaf()
{
return isLeaf() && variable.equals("false");
}
public boolean isNegation()
{
return (child1 != null && child2 == null);
}
public boolean isConjunction()
{
return (child1 != null && child2 != null);
}
/**
* Wertet den durch diesen Baum dargestellten Booleschen Ausdruck aus.
*
* @param trueVars Die Namen aller Variablen, die true sind.
* @return Den Wert des Ausdruckes.
*/
public boolean evaluate(String ...trueVars)
{
if (isLeaf()) // variablenknoten
return Utils.evaluateVariable(variable, trueVars);
if (isConjunction()) // konjunktionsknoten
return child1.evaluate(trueVars) && child2.evaluate(trueVars);
// negationsknoten
return !child1.evaluate(trueVars);
}
/**
* Entfernt doppelte Negationen aus dem Baum.
*
* @return true wenn eine doppelte Negation gefunden wurde und entfernt wurde.
*/
public boolean removeDoubleNegations()
{
if (isLeaf())
return false;
if (isConjunction())
return child1.removeDoubleNegations() | child2.removeDoubleNegations();
// negationsknoten
if (!child1.isNegation())
return false;
BoolTreeNode grandchild = child1.child1;
variable = grandchild.variable;
child1 = grandchild.child1;
child2 = grandchild.child2;
child1.removeDoubleNegations();
child2.removeDoubleNegations();
return true;
}
public static void main(String args[])
{
BoolTreeNode tree = boolTreeAndNode(
boolTreeNotNode(boolTreeNotNode(boolTreeVariableNode("a"))),
boolTreeNotNode(boolTreeNotNode(boolTreeVariableNode("b"))));
System.out.println(tree.removeDoubleNegations());
System.out.println("fertig");
}
}

734
tut6/src/Canvas.java Normal file
View file

@ -0,0 +1,734 @@
/*
* HINWEIS:
*
* Sie brauchen den Java-Code, der in dieser Datei steht, nicht zu lesen oder zu
* verstehen. Alle Hinweise, die zur Verwendung der Datei noetig sind, koennen Sie
* aus den jeweiligen Aufgabentexten entnehmen.
*/
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
/**
* User interface for a Logo-like language. Allows to see the painting process step-by-step.
*/
public class Canvas {
/**
* The color brown.
*/
public static final Color BROWN = new Color(160, 82, 45);
/**
* The color green.
*/
public static final Color GREEN = Color.GREEN;
/**
* Adds the current position to the specified bounds.
* @param g The graphics object to draw on.
* @param boundsParam The bounds of the canvas.
*/
private static void addCurrentPos(Graphics2D g, Rectangle boundsParam) {
if (boundsParam != null) {
Canvas.addToBounds(new Point2D.Float(0f, 0f), boundsParam, g);
}
}
/**
* Adds a point to the bounds, transformed as in the current graphics object.
* @param point The point to add to the bounds.
* @param boundsParam The bounds.
* @param g The graphics object storing affine transformations.
*/
private static void addToBounds(Point2D point, Rectangle boundsParam, Graphics2D g) {
boundsParam.add(g.getTransform().transform(point, null));
}
/**
* Adds a rectangle to the bounds, transformed as in the current graphics object.
* @param r The rectangle to add to the bounds.
* @param boundsParam The bounds.
* @param g The graphics object storing affine transformations.
*/
private static void addToBounds(Rectangle2D r, Rectangle boundsParam, Graphics2D g) {
double maxX = r.getMaxX();
double maxY = r.getMaxY();
double minX = r.getMinX();
double minY = r.getMinY();
Canvas.addToBounds(new Point2D.Double(maxX, maxY), boundsParam, g);
Canvas.addToBounds(new Point2D.Double(maxX, minY), boundsParam, g);
Canvas.addToBounds(new Point2D.Double(minX, maxY), boundsParam, g);
Canvas.addToBounds(new Point2D.Double(minX, minY), boundsParam, g);
}
/**
* The bounds of the canvas.
*/
protected Rectangle bounds;
/**
* The actions to be executed on the canvas.
*/
private ArrayList<Canvas.GraphicAction> actions = new ArrayList<>();
/**
* The actual drawing on the canvas.
*/
private final JComponent drawing = new JPanel() {
/**
* For serialization.
*/
private static final long serialVersionUID = -1665573331455268961L;
@Override
public Dimension getPreferredSize() {
synchronized (Canvas.this) {
return Canvas.this.bounds == null ? new Dimension(100, 100) : Canvas.this.bounds.getSize();
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
synchronized (Canvas.this) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Rectangle clipBounds = g.getClipBounds();
g2.setColor(Color.WHITE);
g2.fill(clipBounds);
g2.setColor(Color.BLACK);
AffineTransform t = g2.getTransform();
int drawCounter;
// do we have current bounds?
if (Canvas.this.bounds == null) {
Rectangle newBounds = new Rectangle();
Canvas.this.transformations.clear();
drawCounter = 0;
for (GraphicAction a : Canvas.this.actions) {
a.replay(g2, false, newBounds);
if (a.drawsSomething()) {
drawCounter++;
}
}
Canvas.this.bounds = new Rectangle(newBounds);
}
// move the drawing inside the screen
GraphicAction init = new Move(20 - Canvas.this.bounds.x, 20 - Canvas.this.bounds.y);
// draw all lines
g2.setTransform(t);
Canvas.this.transformations.clear();
drawCounter = 0;
init.replay(g2, true, null);
for (GraphicAction a : Canvas.this.actions) {
boolean draw = !(a instanceof DrawTextLabel);
a.replay(g2, draw, null);
if (a.drawsSomething()) {
drawCounter++;
}
if (drawCounter >= Canvas.this.renderMaxDraws) {
break;
}
}
// draw all labels
g2.setTransform(t);
Canvas.this.transformations.clear();
drawCounter = 0;
init.replay(g2, true, null);
for (GraphicAction a : Canvas.this.actions) {
boolean draw = (a instanceof DrawTextLabel);
a.replay(g2, draw, null);
if (a.drawsSomething()) {
drawCounter++;
}
if (drawCounter >= Canvas.this.renderMaxDraws) {
break;
}
}
}
}
};
/**
* The number of actions actually drawing something. Used to step forward and backward through the painting process.
*/
private int draws;
/**
* Listener to execute the paint actions.
*/
private final ActionListener handler = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case "start":
Canvas.this.renderMaxDraws = 0;
break;
case "next":
Canvas.this.renderMaxDraws++;
break;
case "back":
Canvas.this.renderMaxDraws--;
break;
case "end":
Canvas.this.renderMaxDraws = Canvas.this.draws;
break;
}
Canvas.this.step.setText("Schritt: " + Canvas.this.renderMaxDraws);
Canvas.this.drawing.repaint();
}
};
/**
* Current step in the stepwise view of the painting process.
*/
private int renderMaxDraws = 0;
/**
* Label for showing the current step.
*/
private final JLabel step = new JLabel("Schritt: " + this.renderMaxDraws);
/**
* Used to (re-)store positions and orientations on the canvas.
*/
private final Stack<AffineTransform> transformations = new Stack<>();
/**
* The frame to display the canvas.
*/
private final JFrame ui = new JFrame() {
/**
* For serialization.
*/
private static final long serialVersionUID = 8620900696432559397L;
{
// set up components
final JScrollPane scrollPane = new JScrollPane(Canvas.this.drawing);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
final JPanel panel = new JPanel();
final JButton startButton = new JButton("Anfang");
startButton.setActionCommand("start");
startButton.addActionListener(Canvas.this.handler);
final JButton backButton = new JButton("Zurueck");
backButton.setActionCommand("back");
backButton.addActionListener(Canvas.this.handler);
final JButton forwardButton = new JButton("Vor");
forwardButton.setActionCommand("next");
forwardButton.addActionListener(Canvas.this.handler);
final JButton endButton = new JButton("Ende");
endButton.setActionCommand("end");
endButton.addActionListener(Canvas.this.handler);
// configure frame
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// set up layout
GroupLayout jPanel1Layout = new GroupLayout(panel);
panel.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(
GroupLayout.Alignment.LEADING
).addGap(0, 158, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(
GroupLayout.Alignment.LEADING
).addGap(0, 36, Short.MAX_VALUE)
);
GroupLayout layout = new GroupLayout(this.getContentPane());
this.getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(
GroupLayout.Alignment.LEADING
).addGroup(
GroupLayout.Alignment.TRAILING,
layout.createSequentialGroup().addContainerGap().addGroup(
layout.createParallelGroup(
GroupLayout.Alignment.TRAILING
).addComponent(
scrollPane,
GroupLayout.Alignment.LEADING,
GroupLayout.DEFAULT_SIZE,
458,
Short.MAX_VALUE
).addGroup(
GroupLayout.Alignment.LEADING,
layout.createSequentialGroup().addComponent(
startButton
).addGap(
6,
6,
6
).addComponent(
backButton
).addGap(
6,
6,
6
).addComponent(
forwardButton
).addGap(
6,
6,
6
).addComponent(
endButton
).addGap(
18,
18,
18
).addComponent(
Canvas.this.step
).addPreferredGap(
LayoutStyle.ComponentPlacement.RELATED
).addComponent(
panel,
GroupLayout.DEFAULT_SIZE,
GroupLayout.DEFAULT_SIZE,
Short.MAX_VALUE
)
)
).addContainerGap()
)
);
layout.setVerticalGroup(
layout.createParallelGroup(
GroupLayout.Alignment.LEADING
).addGroup(
GroupLayout.Alignment.TRAILING,
layout.createSequentialGroup().addContainerGap().addComponent(
scrollPane,
GroupLayout.DEFAULT_SIZE,
400,
Short.MAX_VALUE
).addPreferredGap(
LayoutStyle.ComponentPlacement.RELATED
).addGroup(
layout.createParallelGroup(
GroupLayout.Alignment.TRAILING
).addComponent(
panel,
GroupLayout.PREFERRED_SIZE,
GroupLayout.DEFAULT_SIZE,
GroupLayout.PREFERRED_SIZE
).addGroup(
layout.createParallelGroup(
GroupLayout.Alignment.BASELINE
).addComponent(
startButton
).addComponent(
backButton
).addComponent(
forwardButton
).addComponent(
endButton
).addComponent(
Canvas.this.step
)
)
).addContainerGap()
)
);
// make frame visible
this.pack();
this.setVisible(true);
}
};
/**
* Choose the specified color for further painting.
* @param c The color to choose.
*/
public void chooseColor(Color c) {
this.addAction(new ChooseColor(c));
}
/**
* Draws a line of length {@code length} in the current direction. The current position is moved to the end of the
* line.
* @param length The length of the line to draw.
*/
public void drawForward(int length) {
this.addAction(new DrawForward(length));
}
/**
* Draws a box with the text {@code text} at the current position.
* @param text The text to draw.
*/
public void drawTextLabel(String text) {
this.addAction(new DrawTextLabel(text));
}
/**
* Moves the current position by {@code x} units to the right and {@code y} units down according to the current
* orientation (so if the orientation is rotated by 180 degrees, the move goes left and up instead of right and
* down). This does not draw anything.
* @param x The measure to go right.
* @param y The measure to go down.
*/
public void move(double x, double y) {
this.addAction(new Move(x, y));
}
/**
* Moves the current position by {@code length} units in the current direction without drawing anything.
* @param length The measure to move the current position.
*/
public void moveForward(int length) {
this.addAction(new MoveForward(length));
}
/**
* Sets the current position and orientation to the top-most stored position and orientation. See {@link #push()}.
*/
public void pop() {
this.addAction(new Pop());
}
/**
* Stores the current position and orientation.
* By a subsequent {@link #pop()}, this position and orientation can be restored.
*/
public void push() {
this.addAction(new Push());
}
/**
* Refreshes the shown frame.
*/
public void refresh() {
synchronized (this) {}
this.drawing.revalidate();
this.ui.revalidate();
this.ui.repaint();
}
/**
* Turns the current orientation by {@code degrees} degrees (360 degrees form a circle) clockwise.
* Negative values turn counter-clockwise.
* @param degrees The degrees to turn the orientation.
*/
public void rotate(int degrees) {
this.addAction(new Rotate(degrees));
}
/**
* Draws a filled square of the specified length {@code length} at the current position and with the current
* orientation.
* @param length The length of the square to draw.
*/
public void square(double length) {
this.addAction(new DrawSquare(length));
}
/**
* Adds the specified action to the list of actions to be executed and updates the corresponding counter. Moreover,
* the current bounds are deleted.
* @param action The action to add.
*/
private void addAction(GraphicAction action) {
synchronized (this) {
this.actions.add(action);
if (action.drawsSomething()) {
this.draws++;
}
this.bounds = null;
}
}
/**
* Action to choose a color.
*/
private class ChooseColor extends GraphicAction {
/**
* The color to choose.
*/
private final Color color;
/**
* @param c The color to choose.
*/
ChooseColor(Color c) {
this.color = c;
}
@Override
public boolean drawsSomething() {
return false;
}
@Override
void replay(Graphics2D g, boolean draw, Rectangle boundsParam) {
g.setColor(this.color);
}
}
/**
* Action to draw a line forward.
*/
private class DrawForward extends MoveForward {
/**
* @param length The length of the line to draw.
*/
DrawForward(int length) {
super(length);
}
@Override
void replay(Graphics2D g, boolean draw, Rectangle boundsParam) {
if (draw) {
g.drawLine(0, 0, 0, this.length);
}
super.replay(g, draw, boundsParam);
}
}
/**
* Action to draw a square.
*/
private class DrawSquare extends GraphicAction {
/**
* The length of the square.
*/
private final double length;
/**
* @param length The length of the square.
*/
DrawSquare(double length) {
this.length = length;
}
@Override
void replay(Graphics2D g, boolean draw, Rectangle boundsParam) {
double hl = this.length / 2;
Rectangle2D r = new Rectangle2D.Double();
r.setFrame(-hl, -hl, this.length, this.length);
g.fill(r);
if (boundsParam != null) {
Canvas.addToBounds(r, boundsParam, g);
}
}
}
/**
* Action to draw a text label.
*/
private class DrawTextLabel extends GraphicAction {
/**
* The text of the label.
*/
private final String text;
/**
* @param text The text of the label.
*/
DrawTextLabel(String text) {
this.text = text;
}
@Override
void replay(Graphics2D g, boolean draw, Rectangle boundsParam) {
AffineTransform origTrans = g.getTransform();
Point2D center = origTrans.transform(new Point2D.Double(0, 0), null);
FontRenderContext frc = g.getFontRenderContext();
Font f = g.getFont();
TextLayout tl = new TextLayout(this.text, f, frc);
double w = tl.getBounds().getWidth();
double h = tl.getBounds().getHeight();
// move the text to the center of the box
AffineTransform trans = new AffineTransform();
trans.setToTranslation(Math.round(center.getX() - w / 2), Math.round(center.getY() + h / 2));
g.setTransform(trans);
// draw the box
Rectangle r = new Rectangle(0, (int)-h, (int)w, (int)h);
if (draw) {
Shape textShape = tl.getOutline(new AffineTransform());
g.setColor(Color.BLACK);
r.grow(4, 4);
g.setColor(Color.WHITE);
g.fill(r);
g.setColor(Color.BLACK);
g.draw(r);
g.fill(textShape);
}
if (boundsParam != null) {
Canvas.addToBounds(r, boundsParam, g);
}
// restore original orientation
g.setTransform(origTrans);
}
}
/**
* An action for our canvas.
*/
private abstract class GraphicAction {
/**
* @return True if this action actually draws something. False otherwise. Needs to be overridden by actions not
* drawing something.
*/
public boolean drawsSomething() {
return true;
}
/**
* The drawing method used in this canvas.
* @param g The graphics object to draw on.
* @param draw Flag to indicate whether the drawing action should actually be displayed.
* @param boundsParam The bounds of the canvas.
*/
abstract void replay(Graphics2D g, boolean draw, Rectangle boundsParam);
}
/**
* Action for moving the current position.
*/
private class Move extends GraphicAction {
/**
* The measure to move right.
*/
private final double x;
/**
* The measure to move down.
*/
private final double y;
/**
* @param x The measure to move right.
* @param y The measure to move down.
*/
Move(double x, double y) {
this.x = x;
this.y = y;
}
@Override
public boolean drawsSomething() {
return false;
}
@Override
void replay(Graphics2D g, boolean draw, Rectangle boundsParam) {
g.translate(this.x, this.y);
if (boundsParam != null) {
Canvas.addToBounds(new Point2D.Double(this.x, this.y), boundsParam, g);
}
}
}
/**
* Action for moving forward.
*/
private class MoveForward extends GraphicAction {
/**
* The number of units to move forward.
*/
final int length;
/**
* @param length The number of units to move forward.
*/
MoveForward(int length) {
this.length = length;
}
@Override
public boolean drawsSomething() {
return false;
}
@Override
void replay(Graphics2D g, boolean draw, Rectangle boundsParam) {
Canvas.addCurrentPos(g, boundsParam);
AffineTransform t = g.getTransform();
t.translate(0, this.length);
g.setTransform(t);
Canvas.addCurrentPos(g, boundsParam);
}
}
/**
* Action for restoring a position and orientation.
*/
private class Pop extends GraphicAction {
@Override
void replay(Graphics2D g, boolean draw, Rectangle boundsParam) {
g.setTransform(Canvas.this.transformations.pop());
}
}
/**
* Action for storing the current position and orientation.
*/
private class Push extends GraphicAction {
@Override
void replay(Graphics2D g, boolean draw, Rectangle boundsParam) {
Canvas.this.transformations.push(g.getTransform());
}
}
/**
* Action for rotation the current orientation.
*/
private class Rotate extends GraphicAction {
/**
* The degrees to turn the current orientation.
*/
final int degree;
/**
* @param degree The degrees to turn the current orientation.
*/
Rotate(int degree) {
this.degree = degree;
}
@Override
public boolean drawsSomething() {
return false;
}
@Override
void replay(Graphics2D g, boolean draw, Rectangle boundsParam) {
AffineTransform t = g.getTransform();
t.rotate(this.degree / 180.0 * Math.PI);
g.setTransform(t);
}
}
}

83
tut6/src/Squares.java Normal file
View file

@ -0,0 +1,83 @@
/**
* Program for drawing a square fractal.
*/
public class Squares
{
/**
* @param args Contains the parameters for the drawing. The first
* (mandatory) is the recursion level. The second (optional)
* is the base length of the first square. The default value
* for this length is 100 if it is not specified. Each
* parameter must be positive.
*/
public static void main(String args[])
{
int level;
int length = 100;
switch (args.length)
{
case 2:
length = Integer.parseInt(args[1]);
// fall-through
case 1:
level = Integer.parseInt(args[0]);
break;
default:
System.out.println(
"Es muessen zwischen 1 und 2 Parameter angegeben werden "
+ "(Level und eventuell Basislaenge)!"
);
return;
}
if (level < 1)
{
System.out.println("Das Rekursionslevel muss positiv sein!");
return;
}
if (length < 1)
{
System.out.println("Die Basislaenge muss positiv sein!");
return;
}
Canvas c = new Canvas();
Squares.paintFractal(c, level, length);
c.refresh();
}
/**
* Draws a square fractal with the specified recursion level and base length
* on the specified canvas.
*
* @param c The canvas to draw the tree on.
* @param level The current recursion level.
* @param length The current length.
*/
private static void paintFractal(Canvas c, int level, double length)
{
if (level <= 0)
return;
c.square(length);
// oben links
c.move(-length/2, -length/2);
paintFractal(c, level-1, length/2);
// oben rechts
c.move(length, 0);
paintFractal(c, level-1, length/2);
// unten rechts
c.move(0, length);
paintFractal(c, level-1, length/2);
// unten links
c.move(-length, 0);
paintFractal(c, level-1, length/2);
// zurueck zum mittelpunkt
c.move(length/2, -length/2);
}
}

69
tut6/src/Utils.java Normal file
View file

@ -0,0 +1,69 @@
import java.awt.*;
public class Utils {
private Utils(){}
/**
* Evaluiert eine Variable bei mit wahr angenommenen Variablen
* @param elem der Name der zu evaluierenden Variable oder true oder false
* @param strings die Namen genau der Variablen, die für diese Evalutaion als wahr angenommen werden
* @return true, wenn die Variable zu true evaluiert wird, sonst false
*/
public static boolean evaluateVariable(String elem, String... strings) {
if (elem.equals("true")) {
//variable is constant true
return true;
} else if (elem.equals("false")) {
//variable is constant false
return false;
} else {
return contains(elem,strings);
}
}
/**
* Gibt zurück, ob elem in strings enthalten ist
* @param elem der String, nach dem gesucht werden soll
* @param strings die Strings, die durchsucht werden sollen
* @return wenn elem in strings enthalten ist, sonst false
*/
public static boolean contains(String elem, String... strings) {
if (strings == null) {
//strings is null, elem cannot be contained
return false;
}
for (String string : strings) {
if (string.equals(elem)) {
//elem is in strings
return true;
}
}
//elem has not been found in strings
return false;
}
/**
* Gibt eine Fehlermeldung aus.
* @param msg die Fehlermeldung, die ausgegeben werden soll
*/
public static void error(String msg) {
System.err.println(msg);
}
/**
* Berechnet das Maximum der Argumente.
* @param args die Werte, deren Maximum bestimmt werden soll
* @return den maximalen Wert aller Argumente
*/
public static int max(int... args) {
if (args.length == 0) {
error("Called max without arguments!");
}
int res = args[0];
for (int i = 1; i < args.length; i++) {
res = Math.max(res, args[i]);
}
return res;
}
}