Skip to content

Commit

Permalink
Sync two bucket (#2877)
Browse files Browse the repository at this point in the history
  • Loading branch information
jagdish-15 authored Jan 17, 2025
1 parent 7edff84 commit 3f5c931
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 163 deletions.
11 changes: 9 additions & 2 deletions exercises/practice/two-bucket/.meta/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
],
"contributors": [
"FridaTveit",
"jagdish-15",
"jmrunkle",
"kahgoh",
"lemoncurry",
"LoadingBG",
"mirkoperillo",
"msomji",
"muzimuzhi",
Expand All @@ -15,13 +18,17 @@
],
"files": {
"solution": [
"src/main/java/TwoBucket.java"
"src/main/java/TwoBucket.java",
"src/main/java/Result.java",
"src/main/java/UnreachableGoalException.java"
],
"test": [
"src/test/java/TwoBucketTest.java"
],
"example": [
".meta/src/reference/java/TwoBucket.java"
".meta/src/reference/java/TwoBucket.java",
".meta/src/reference/java/Result.java",
".meta/src/reference/java/UnreachableGoalException.java"
],
"invalidator": [
"build.gradle"
Expand Down
24 changes: 24 additions & 0 deletions exercises/practice/two-bucket/.meta/src/reference/java/Result.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
final class Result {

private final int totalMoves;
private final String finalBucket;
private final int otherBucket;

Result(int totalMoves, String finalBuckets, int otherBucket) {
this.totalMoves = totalMoves;
this.finalBucket = finalBuckets;
this.otherBucket = otherBucket;
}

public int getTotalMoves() {
return totalMoves;
}

public String getFinalBucket() {
return finalBucket;
}

public int getOtherBucket() {
return otherBucket;
}
}
223 changes: 99 additions & 124 deletions exercises/practice/two-bucket/.meta/src/reference/java/TwoBucket.java
Original file line number Diff line number Diff line change
@@ -1,149 +1,124 @@
import java.util.ArrayList;
import java.util.Objects;
import java.util.List;
import java.util.Map;

class TwoBucket {
final class TwoBucket {

private int totalMoves = Integer.MAX_VALUE;
private String finalBucket = "";
private int otherBucket = Integer.MAX_VALUE;

private class State {
int moves;
int bucketOne;
int bucketTwo;

State (int moves, int bucketOne, int bucketTwo) {
this.moves = moves;
this.bucketOne = bucketOne;
this.bucketTwo = bucketTwo;
}

@Override
public boolean equals(Object o) {
State otherState = (State) o;
return this.moves == otherState.moves &&
this.bucketOne == otherState.bucketOne &&
this.bucketTwo == otherState.bucketTwo;
}

@Override
public int hashCode() {
return Objects.hash(moves, bucketOne, bucketTwo);
}
}

private State finalState;

private int bucketOneCap;
private int bucketTwoCap;
private int desiredLiters;
private String startBucket;
private final List<Map.Entry<Integer, Integer>> statesReached = new ArrayList<>();

TwoBucket(int bucketOneCap, int bucketTwoCap, int desiredLiters, String startBucket) {
this.bucketOneCap = bucketOneCap;
this.bucketTwoCap = bucketTwoCap;
this.desiredLiters = desiredLiters;
this.startBucket = startBucket;

finalState = computeFinalState();
checkIfImpossible(desiredLiters, bucketOneCap, bucketTwoCap);

fillBuckets(
startBucket.equals("one") ? bucketOneCap : 0,
bucketOneCap,
startBucket.equals("two") ? bucketTwoCap : 0,
bucketTwoCap,
desiredLiters,
1,
startBucket
);
}

private ArrayList<State> getAdjacentStates (State state) {
ArrayList<State> adjacentStates = new ArrayList<State>();

//Empty bucket one
adjacentStates.add(new State(state.moves + 1, 0, state.bucketTwo));

//Empty bucket two
adjacentStates.add(new State(state.moves + 1, state.bucketOne, 0));

//Fill bucket one
adjacentStates.add(new State(state.moves + 1, bucketOneCap, state.bucketTwo));

//Fill bucket two
adjacentStates.add(new State(state.moves + 1, state.bucketOne, bucketTwoCap));

//pour from bucket one to bucket two
if (state.bucketOne + state.bucketTwo > bucketTwoCap) {
adjacentStates.add(new State(state.moves + 1,
state.bucketOne - (bucketTwoCap - state.bucketTwo),
bucketTwoCap));
} else {
adjacentStates.add(new State(state.moves + 1, 0, state.bucketOne + state.bucketTwo));
private void fillBuckets(
int bucketOne,
int bucketOneCap,
int bucketTwo,
int bucketTwoCap,
int desiredLiters,
int actionsTaken,
String startingBucket
) {
if (startingBucket.equals("one") && bucketOne == 0 && bucketTwo == bucketTwoCap
|| startingBucket.equals("two") && bucketTwo == 0 && bucketOne == bucketOneCap
|| statesReached.contains(Map.entry(bucketOne, bucketTwo))
|| bucketOne > bucketOneCap
|| bucketTwo > bucketTwoCap) {
return;
}

//pour from bucket two to bucket one
if (state.bucketTwo + state.bucketOne > bucketOneCap) {
adjacentStates.add(new State(state.moves + 1,
bucketOneCap,
state.bucketTwo - (bucketOneCap - state.bucketOne)));
} else {
adjacentStates.add(new State(state.moves + 1, state.bucketTwo + state.bucketOne, 0));
if (bucketOne == desiredLiters) {
if (actionsTaken < totalMoves) {
this.totalMoves = actionsTaken;
this.finalBucket = "one";
this.otherBucket = bucketTwo;
}
return;
}

return adjacentStates;
}

private boolean isValid(State state) {
if (state.bucketOne == bucketOneCap && state.bucketTwo == 0 && startBucket.equals("two")) {
return false;
} else if (state.bucketOne == 0 && state.bucketTwo == bucketTwoCap && startBucket.equals("two")) {
return false;
} else {
return true;
if (bucketTwo == desiredLiters) {
if (actionsTaken < totalMoves) {
this.totalMoves = actionsTaken;
this.finalBucket = "two";
this.otherBucket = bucketOne;
}
return;
}
}

private State computeFinalState() {
ArrayList<State> paths = new ArrayList<State>();
statesReached.add(Map.entry(bucketOne, bucketTwo));

State initialState;
if (startBucket.equals("one")) {
initialState = new State(1, bucketOneCap, 0);
} else {
initialState = new State(1, 0, bucketTwoCap);
if (bucketOne != 0) {
fillBuckets(0, bucketOneCap, bucketTwo, bucketTwoCap, desiredLiters, actionsTaken + 1, startingBucket);
}

if (initialState.bucketOne == desiredLiters || initialState.bucketTwo == desiredLiters) {
return initialState;
if (bucketTwo != 0) {
fillBuckets(bucketOne, bucketOneCap, 0, bucketTwoCap, desiredLiters, actionsTaken + 1, startingBucket);
}

paths.add(initialState);

for (int i = 0; i < 10000; i++) {
State currentState = paths.remove(0);
ArrayList<State> adjacentStates = getAdjacentStates(currentState);
for (State state : adjacentStates) {
if (state.bucketOne == desiredLiters || state.bucketTwo == desiredLiters) {
return state;
}

if (!paths.contains(state) && isValid(state)) {
paths.add(state);
}
}
fillBuckets(
bucketOneCap, bucketOneCap, bucketTwo, bucketTwoCap, desiredLiters,
actionsTaken + 1, startingBucket
);
fillBuckets(
bucketOne, bucketOneCap, bucketTwoCap, bucketTwoCap, desiredLiters,
actionsTaken + 1, startingBucket
);

if (bucketOne + bucketTwo <= bucketTwoCap) {
fillBuckets(
0, bucketOneCap, bucketTwo + bucketOne, bucketTwoCap, desiredLiters,
actionsTaken + 1, startingBucket
);
} else {
fillBuckets(
bucketOne + bucketTwo - bucketTwoCap, bucketOneCap, bucketTwoCap, bucketTwoCap,
desiredLiters, actionsTaken + 1, startingBucket
);
}
if (bucketOne + bucketTwo <= bucketOneCap) {
fillBuckets(
bucketOne + bucketTwo, bucketOneCap, 0, bucketTwoCap, desiredLiters,
actionsTaken + 1, startingBucket
);
} else {
fillBuckets(
bucketOneCap, bucketOneCap, bucketTwo + bucketOne - bucketOneCap, bucketTwoCap,
desiredLiters, actionsTaken + 1, startingBucket
);
}

return null;
}

int getTotalMoves() {
return finalState.moves;
private void checkIfImpossible(int desiredLiters, int bucketOneCap, int bucketTwoCap) {
boolean exceedsCapacity = desiredLiters > bucketOneCap && desiredLiters > bucketTwoCap;
boolean invalidDivision = desiredLiters % gcd(bucketOneCap, bucketTwoCap) != 0;

if (exceedsCapacity || invalidDivision) {
throw new UnreachableGoalException();
}
}

String getFinalBucket() {
if (finalState.bucketOne == desiredLiters) {
return "one";
} else if (finalState.bucketTwo == desiredLiters) {
return "two";
} else {
return "No solution found in " + finalState.moves + " iterations!";
private int gcd(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}

int getOtherBucket() {
if (getFinalBucket().equals("one")) {
return finalState.bucketTwo;
} else if (getFinalBucket().equals("two")) {
return finalState.bucketOne;
} else {
return -1;
}
Result getResult() {
return new Result(totalMoves, finalBucket, otherBucket);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
public class UnreachableGoalException extends RuntimeException {

public UnreachableGoalException() {
super();
}

public UnreachableGoalException(String message) {
super(message);
}

public UnreachableGoalException(String message, Throwable cause) {
super(message, cause);
}
}
22 changes: 19 additions & 3 deletions exercises/practice/two-bucket/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# This is an auto-generated file. Regular comments will be removed when this
# file is regenerated. Regenerating will not touch any manually added keys,
# so comments can be added in a "comment" key.
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[a6f2b4ba-065f-4dca-b6f0-e3eee51cb661]
description = "Measure using bucket one of size 3 and bucket two of size 5 - start with bucket one"
Expand All @@ -19,3 +26,12 @@ description = "Measure one step using bucket one of size 1 and bucket two of siz

[eb329c63-5540-4735-b30b-97f7f4df0f84]
description = "Measure using bucket one of size 2 and bucket two of size 3 - start with bucket one and end with bucket two"

[449be72d-b10a-4f4b-a959-ca741e333b72]
description = "Not possible to reach the goal"

[aac38b7a-77f4-4d62-9b91-8846d533b054]
description = "With the same buckets but a different goal, then it is possible"

[74633132-0ccf-49de-8450-af4ab2e3b299]
description = "Goal larger than both buckets is impossible"
24 changes: 24 additions & 0 deletions exercises/practice/two-bucket/src/main/java/Result.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
final class Result {

private final int totalMoves;
private final String finalBucket;
private final int otherBucket;

Result(int totalMoves, String finalBuckets, int otherBucket) {
this.totalMoves = totalMoves;
this.finalBucket = finalBuckets;
this.otherBucket = otherBucket;
}

public int getTotalMoves() {
return totalMoves;
}

public String getFinalBucket() {
return finalBucket;
}

public int getOtherBucket() {
return otherBucket;
}
}
14 changes: 4 additions & 10 deletions exercises/practice/two-bucket/src/main/java/TwoBucket.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
class TwoBucket {

TwoBucket(int bucketOneCap, int bucketTwoCap, int desiredLiters, String startBucket) {
throw new UnsupportedOperationException("Please implement the TwoBucket(int, int, int, String) constructor.");
}

int getTotalMoves() {
throw new UnsupportedOperationException("Please implement the TwoBucket.getTotalMoves() method.");
}

String getFinalBucket() {
throw new UnsupportedOperationException("Please implement the TwoBucket.getFinalBucket() method.");
}

int getOtherBucket() {
throw new UnsupportedOperationException("Please implement the TwoBucket.getOtherBucket() method.");
Result getResult() {
throw new UnsupportedOperationException("Please implement the TwoBucket(int, int, int, String) constructor.");
}

}
Loading

0 comments on commit 3f5c931

Please sign in to comment.