# Waterpouring Problem Java - DRINGEND HILFE!!!



## btl1903 (13. Dez 2017)

Hallo! Habe in der Uni eine Programmieraufgabe, aber ich verstehe nicht genau, was ich machen soll. Es geht um das WaterPouring Problem, aber wir müssen das Problem generell machen, sodass es nicht nur für Wasser anwendbar ist, sondern allgemein. 
Das Problem1 ist das originale WaterPouring Problem, der Code funktioniert, aber wir müssen hier ein interface implementieren. Im interface gibt es eine Methode solve(.....) mit mehreren Parametern (daher anders als die vorhandene solve(int goal) methode in der Klasse). Ich verstehe jetzt nicht, was ich in der neuen solve methode machen muss. Kann mir bitte jemand helfen??? 
Hier ist das interface:

```
import java.io.PrintStream;

/** Interface for Problem 1 */
public interface P1 {

    /**
     * Solves problem 1 (two empty canisters of given capacity)
     *
     * Example: System.out.println(p1.solve(5, 9, 8, System.out)); --> 6
     *
     * @param xCapacity
     *            the capacity of canister X
     * @param yCapacity
     *            the capacity of canister Y
     * @param goal
     *            the goal we want to achieve
     * @param out
     *            a printstream to write the path to the goal (should be a single line)
     * @return the number of actions in the shortest path to the goal
     */
    public int solve(int xCapacity, int yCapacity, int goal, PrintStream out);
}
```

Und hier ist die Klasse:

```
import assignment8_int.P1;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/** water pouring problem. based on the python code of peter norvig (see below) */
public class PureWaterPouring implements P1 {

    private final int xCapacity;
    private final int yCapacity;

    private int[] initState = new int[] { 0, 0 };
   
    public PureWaterPouring() {
        this.xCapacity=0;
        this.yCapacity=0;
    }

    public PureWaterPouring(int xCapacity, int yCapacity) {
        this.xCapacity = xCapacity;
        this.yCapacity = yCapacity;
    }

    private boolean containsGoal(int[] state, int goal) {
        return state[0] == goal || state[1] == goal;
    }

    private boolean isAlreadyExplored(int[] state, Set<int[]> explored) {
        for (int[] entry : explored) {
            if (entry[0] == state[0] && entry[1] == state[1]) {
                return true;
            }
        }
        return false;
    }

    public Collection<?> solve(int goal) {
        if (containsGoal(initState, goal)) {
            return Arrays.asList(initState);
        }
        Set<int[]> explored = new HashSet<>();
        LinkedList<LinkedList<?>> frontier = new LinkedList<>(); /* note: not only the states are relevant, we also want to know, how we got there -> consider Move */
        frontier.push(new LinkedList<>(Arrays.asList(initState)));
        while (!frontier.isEmpty()) {
            LinkedList<?> path = frontier.pop();
            int[] state = (int[]) path.get(path.size() - 1); // state of last path
            for (Entry<int[], String> e : getSuccessors(state[0], state[1]).entrySet()) {
                int[] succState = e.getKey();
                String succAction = e.getValue();
                if (!isAlreadyExplored(succState, explored)) {
                    explored.add(succState);
                    LinkedList<Object> path2 = new LinkedList<>(path); // copy path
                    path2.addLast(succAction);
                    path2.addLast(succState);
                    if (containsGoal(succState, goal)) {
                        return path2;
                    } else {
                        frontier.add(path2);
                    }
                }
            }
        }
        return Collections.emptyList();
    }

    private int[] toState(int x, int y) {
        return new int[] { x, y };
    }

    private Map<int[], String> getSuccessors(int x, int y) {
        assert (x <= xCapacity && y <= yCapacity);
        Map<int[], String> successors = new HashMap<>();
        successors.put((y + x <= yCapacity) ? toState(0, y + x) : toState(x - (yCapacity - y), y + (yCapacity - y)), "from_X_to_Y");
        successors.put((x + y <= xCapacity) ? toState(x + y, 0) : toState(x + (xCapacity - x), y - (xCapacity - x)), "from_Y_to_X");
        successors.put(toState(xCapacity, y), "fill_X");
        successors.put(toState(x, yCapacity), "fill_Y");
        successors.put(toState(0, y), "empty_X");
        successors.put(toState(x, 0), "empty_Y");
        return successors;
    }

    public static void main(String[] args) {
        PureWaterPouring wp = new PureWaterPouring(4, 9);
        Collection<?> solution = wp.solve(6);
        if (solution.size() > 0) {
            for (Object o : solution) {
                if (o instanceof int[]) {
                    int[] state = (int[]) o;
                    System.out.print(state[0] + "," + state[1] + " ");
                } else {
                    System.out.print(o + " ");
                }
            }
            System.out.println();
        } else {
            System.out.println("no solution");
        }
    }

    @Override
    public int solve(int xCapacity, int yCapacity, int goal, PrintStream out) {
        // TODO Auto-generated method stub
        return 0;
    }
}
```


----------



## btl1903 (13. Dez 2017)

Das ist die Aufgabenstellung, die ich auch nicht so verstehe.

```
Take the provided implementation for the pouring problem (PureWaterPouring).

Come up with a good software architecture for it (also introduce new classes/types in order to increase the readability of the code). It shall support different problems (but of the same kind of course) with minimal compile-time adaptation. The idea is that the core of the software should become a minimal framework. A new problem should require writing new classes, but not changing existing code (Open-Closed-Principle).

Be sure that the framework-code (i.e., "the algorithm") does not depend on any problem-specific information. In particular not on the information that the state has integers.

Note that the current code uses a HashSet and calls its contains()-method. The javadoc of HashSet.contains() states: "Returns true if this collection contains the specified element. More formally, returns true if and only if this collection contains at least one element e such that (o==null ? e==null : o.equals(e))." So if you replace the int[] that is put into the hashset with your own class (e.g. MyState), make sure that your equals()-method works as intended. If not overriden, the equals()-method is inherited from the Object class (which checks whether the two objects are the same, i.e., share the same memory location). Intuitively, two state objects for Problem1, e.g., are equal, if their x- and y- integer values are the same.

Further note, that the javadoc of the Object.equals() method says: "Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes."

Think about other problems that can be solved with the framework.
```


----------



## mrBrown (13. Dez 2017)

btl1903 hat gesagt.:


> Das Problem1 ist das originale WaterPouring Problem, der Code funktioniert, aber wir müssen hier ein interface implementieren. Im interface gibt es eine Methode solve(.....) mit mehreren Parametern (daher anders als die vorhandene solve(int goal) methode in der Klasse). Ich verstehe jetzt nicht, was ich in der neuen solve methode machen muss. Kann mir bitte jemand helfen???


Die Klasse soll dieses Interface implementieren und die neue goal-Methode als einzige öffentliche Methode bereitstellen. Das Problem soll man dann über diese Methode und nicht über die bisherige Variante mit parametisiertem Konstruktor und der Methode mit einem Parameter lösen.



btl1903 hat gesagt.:


> Das ist die Aufgabenstellung, die ich auch nicht so verstehe.


Du sollst den Algorithmus so implementieren, das er generisch erweitert werden kann - unter anderem, indem du den State nicht mehr als int darstellst, sondern dir eine andere geeignete Darstellung überlegst.


----------

