From 3f5c93199397f685b203e68a66a2a8c61c408186 Mon Sep 17 00:00:00 2001 From: jagdish-15 Date: Fri, 17 Jan 2025 10:04:30 +0530 Subject: [PATCH] Sync two bucket (#2877) --- .../practice/two-bucket/.meta/config.json | 11 +- .../.meta/src/reference/java/Result.java | 24 ++ .../.meta/src/reference/java/TwoBucket.java | 223 ++++++++---------- .../java/UnreachableGoalException.java | 14 ++ .../practice/two-bucket/.meta/tests.toml | 22 +- .../two-bucket/src/main/java/Result.java | 24 ++ .../two-bucket/src/main/java/TwoBucket.java | 14 +- .../main/java/UnreachableGoalException.java | 14 ++ .../src/test/java/TwoBucketTest.java | 79 +++++-- 9 files changed, 262 insertions(+), 163 deletions(-) create mode 100644 exercises/practice/two-bucket/.meta/src/reference/java/Result.java create mode 100644 exercises/practice/two-bucket/.meta/src/reference/java/UnreachableGoalException.java create mode 100644 exercises/practice/two-bucket/src/main/java/Result.java create mode 100644 exercises/practice/two-bucket/src/main/java/UnreachableGoalException.java diff --git a/exercises/practice/two-bucket/.meta/config.json b/exercises/practice/two-bucket/.meta/config.json index 54da6bd62..4f45ff4a4 100644 --- a/exercises/practice/two-bucket/.meta/config.json +++ b/exercises/practice/two-bucket/.meta/config.json @@ -4,8 +4,11 @@ ], "contributors": [ "FridaTveit", + "jagdish-15", "jmrunkle", + "kahgoh", "lemoncurry", + "LoadingBG", "mirkoperillo", "msomji", "muzimuzhi", @@ -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" diff --git a/exercises/practice/two-bucket/.meta/src/reference/java/Result.java b/exercises/practice/two-bucket/.meta/src/reference/java/Result.java new file mode 100644 index 000000000..b7b23ce64 --- /dev/null +++ b/exercises/practice/two-bucket/.meta/src/reference/java/Result.java @@ -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; + } +} diff --git a/exercises/practice/two-bucket/.meta/src/reference/java/TwoBucket.java b/exercises/practice/two-bucket/.meta/src/reference/java/TwoBucket.java index 89771ab81..3cf41ccf7 100644 --- a/exercises/practice/two-bucket/.meta/src/reference/java/TwoBucket.java +++ b/exercises/practice/two-bucket/.meta/src/reference/java/TwoBucket.java @@ -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> 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 getAdjacentStates (State state) { - ArrayList adjacentStates = new ArrayList(); - - //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 paths = new ArrayList(); + 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 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); } } diff --git a/exercises/practice/two-bucket/.meta/src/reference/java/UnreachableGoalException.java b/exercises/practice/two-bucket/.meta/src/reference/java/UnreachableGoalException.java new file mode 100644 index 000000000..2b3ccbc49 --- /dev/null +++ b/exercises/practice/two-bucket/.meta/src/reference/java/UnreachableGoalException.java @@ -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); + } +} diff --git a/exercises/practice/two-bucket/.meta/tests.toml b/exercises/practice/two-bucket/.meta/tests.toml index 27adad905..d6ff02f53 100644 --- a/exercises/practice/two-bucket/.meta/tests.toml +++ b/exercises/practice/two-bucket/.meta/tests.toml @@ -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" @@ -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" diff --git a/exercises/practice/two-bucket/src/main/java/Result.java b/exercises/practice/two-bucket/src/main/java/Result.java new file mode 100644 index 000000000..2464dab5f --- /dev/null +++ b/exercises/practice/two-bucket/src/main/java/Result.java @@ -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; + } +} diff --git a/exercises/practice/two-bucket/src/main/java/TwoBucket.java b/exercises/practice/two-bucket/src/main/java/TwoBucket.java index ae7be705a..5cd0e4d87 100644 --- a/exercises/practice/two-bucket/src/main/java/TwoBucket.java +++ b/exercises/practice/two-bucket/src/main/java/TwoBucket.java @@ -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."); } + } diff --git a/exercises/practice/two-bucket/src/main/java/UnreachableGoalException.java b/exercises/practice/two-bucket/src/main/java/UnreachableGoalException.java new file mode 100644 index 000000000..2b3ccbc49 --- /dev/null +++ b/exercises/practice/two-bucket/src/main/java/UnreachableGoalException.java @@ -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); + } +} diff --git a/exercises/practice/two-bucket/src/test/java/TwoBucketTest.java b/exercises/practice/two-bucket/src/test/java/TwoBucketTest.java index cf05b67d1..3564951ab 100644 --- a/exercises/practice/two-bucket/src/test/java/TwoBucketTest.java +++ b/exercises/practice/two-bucket/src/test/java/TwoBucketTest.java @@ -2,17 +2,18 @@ import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; public class TwoBucketTest { @Test public void testBucketOneSizeThreeBucketTwoSizeFiveStartWithOne() { - TwoBucket twoBucket = new TwoBucket(3, 5, 1, "one"); + Result bucketResult = new TwoBucket(3, 5, 1, "one").getResult(); - assertThat(twoBucket.getTotalMoves()).isEqualTo(4); - assertThat(twoBucket.getFinalBucket()).isEqualTo("one"); - assertThat(twoBucket.getOtherBucket()).isEqualTo(5); + assertThat(bucketResult.getTotalMoves()).isEqualTo(4); + assertThat(bucketResult.getFinalBucket()).isEqualTo("one"); + assertThat(bucketResult.getOtherBucket()).isEqualTo(5); } @@ -20,11 +21,11 @@ public void testBucketOneSizeThreeBucketTwoSizeFiveStartWithOne() { @Test public void testBucketOneSizeThreeBucketTwoSizeFiveStartWithTwo() { - TwoBucket twoBucket = new TwoBucket(3, 5, 1, "two"); + Result bucketResult = new TwoBucket(3, 5, 1, "two").getResult(); - assertThat(twoBucket.getTotalMoves()).isEqualTo(8); - assertThat(twoBucket.getFinalBucket()).isEqualTo("two"); - assertThat(twoBucket.getOtherBucket()).isEqualTo(3); + assertThat(bucketResult.getTotalMoves()).isEqualTo(8); + assertThat(bucketResult.getFinalBucket()).isEqualTo("two"); + assertThat(bucketResult.getOtherBucket()).isEqualTo(3); } @@ -32,11 +33,11 @@ public void testBucketOneSizeThreeBucketTwoSizeFiveStartWithTwo() { @Test public void testBucketOneSizeSevenBucketTwoSizeElevenStartWithOne() { - TwoBucket twoBucket = new TwoBucket(7, 11, 2, "one"); + Result bucketResult = new TwoBucket(7, 11, 2, "one").getResult(); - assertThat(twoBucket.getTotalMoves()).isEqualTo(14); - assertThat(twoBucket.getFinalBucket()).isEqualTo("one"); - assertThat(twoBucket.getOtherBucket()).isEqualTo(11); + assertThat(bucketResult.getTotalMoves()).isEqualTo(14); + assertThat(bucketResult.getFinalBucket()).isEqualTo("one"); + assertThat(bucketResult.getOtherBucket()).isEqualTo(11); } @@ -44,11 +45,11 @@ public void testBucketOneSizeSevenBucketTwoSizeElevenStartWithOne() { @Test public void testBucketOneSizeSevenBucketTwoSizeElevenStartWithTwo() { - TwoBucket twoBucket = new TwoBucket(7, 11, 2, "two"); + Result bucketResult = new TwoBucket(7, 11, 2, "two").getResult(); - assertThat(twoBucket.getTotalMoves()).isEqualTo(18); - assertThat(twoBucket.getFinalBucket()).isEqualTo("two"); - assertThat(twoBucket.getOtherBucket()).isEqualTo(7); + assertThat(bucketResult.getTotalMoves()).isEqualTo(18); + assertThat(bucketResult.getFinalBucket()).isEqualTo("two"); + assertThat(bucketResult.getOtherBucket()).isEqualTo(7); } @@ -56,11 +57,11 @@ public void testBucketOneSizeSevenBucketTwoSizeElevenStartWithTwo() { @Test public void testBucketOneSizeOneBucketTwoSizeThreeStartWithTwo() { - TwoBucket twoBucket = new TwoBucket(1, 3, 3, "two"); + Result bucketResult = new TwoBucket(1, 3, 3, "two").getResult(); - assertThat(twoBucket.getTotalMoves()).isEqualTo(1); - assertThat(twoBucket.getFinalBucket()).isEqualTo("two"); - assertThat(twoBucket.getOtherBucket()).isEqualTo(0); + assertThat(bucketResult.getTotalMoves()).isEqualTo(1); + assertThat(bucketResult.getFinalBucket()).isEqualTo("two"); + assertThat(bucketResult.getOtherBucket()).isEqualTo(0); } @@ -68,11 +69,41 @@ public void testBucketOneSizeOneBucketTwoSizeThreeStartWithTwo() { @Test public void testBucketOneSizeTwoBucketTwoSizeThreeStartWithOne() { - TwoBucket twoBucket = new TwoBucket(2, 3, 3, "one"); + Result bucketResult = new TwoBucket(2, 3, 3, "one").getResult(); - assertThat(twoBucket.getTotalMoves()).isEqualTo(2); - assertThat(twoBucket.getFinalBucket()).isEqualTo("two"); - assertThat(twoBucket.getOtherBucket()).isEqualTo(2); + assertThat(bucketResult.getTotalMoves()).isEqualTo(2); + assertThat(bucketResult.getFinalBucket()).isEqualTo("two"); + assertThat(bucketResult.getOtherBucket()).isEqualTo(2); + + } + + @Disabled("Remove to run test") + @Test + public void testReachingGoalIsImpossible() { + + assertThatExceptionOfType(UnreachableGoalException.class) + .isThrownBy(() -> new TwoBucket(6, 15, 5, "one").getResult()); + + } + + @Disabled("Remove to run test") + @Test + public void testBucketOneSizeSixBucketTwoSizeFifteenStartWithOne() { + + Result bucketResult = new TwoBucket(6, 15, 9, "one").getResult(); + + assertThat(bucketResult.getTotalMoves()).isEqualTo(10); + assertThat(bucketResult.getFinalBucket()).isEqualTo("two"); + assertThat(bucketResult.getOtherBucket()).isEqualTo(0); + + } + + @Disabled("Remove to run test") + @Test + public void testGoalLargerThanBothBucketsIsImpossible() { + + assertThatExceptionOfType(UnreachableGoalException.class) + .isThrownBy(() -> new TwoBucket(5, 7, 8, "one").getResult()); } }