Compare commits

...

2 Commits

Author SHA1 Message Date
maddiebaka a8796ba886 Edit javadoc for clarity, method signature simplification
Make revisions to javadoc for clarity, remove unnecessary phrases, and
simplify calculateNextPermutation() method arguments.
2024-03-28 22:56:17 -04:00
maddiebaka f360c538eb Remove un-used import statements 2024-03-28 22:44:50 -04:00
8 changed files with 20 additions and 28 deletions

View File

@ -1,15 +1,13 @@
package com.cleverthis.interview; package com.cleverthis.interview;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
* Brute-forces padlock using lexicographically ordered permutation generation * Brute-forces padlock using lexicographically ordered permutation generation.
* *
* Algorithm documented at: https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order * Permutation-generation algorithm documented at: https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
*/ */
public class DumbBruteSolver implements SolverInterface { public class DumbBruteSolver implements SolverInterface {
@ -31,7 +29,7 @@ public class DumbBruteSolver implements SolverInterface {
boolean isCorrect = checkPermutation(currentPermutation, padlockAdapter); boolean isCorrect = checkPermutation(currentPermutation, padlockAdapter);
if (!isCorrect) { if (!isCorrect) {
boolean nextPermutationExists = calculateNextPermutation(currentPermutation, numpadSize); boolean nextPermutationExists = calculateNextPermutation(currentPermutation);
if(!nextPermutationExists) { if(!nextPermutationExists) {
return; return;
} }
@ -60,10 +58,11 @@ public class DumbBruteSolver implements SolverInterface {
/** /**
* Calculates the next permutation in lexicographic order, based on the algorithm linked on wikipedia * Calculates the next permutation in lexicographic order, based on the algorithm linked on wikipedia
* @param currentPermutation The current permutation to run the algorithm on * @param currentPermutation The current permutation to run the algorithm on
* @param numpadSize The number of items in the set to be permuted
* @return true if next permutation successfully generated, false if permutations have been exhausted * @return true if next permutation successfully generated, false if permutations have been exhausted
*/ */
protected boolean calculateNextPermutation(Integer[] currentPermutation, int numpadSize) { protected boolean calculateNextPermutation(Integer[] currentPermutation) {
int numpadSize = currentPermutation.length;
if(numpadSize < 2) { return false; } if(numpadSize < 2) { return false; }
//Integer k, l; //Integer k, l;

View File

@ -3,7 +3,7 @@ package com.cleverthis.interview;
import org.apache.commons.text.similarity.LevenshteinDistance; import org.apache.commons.text.similarity.LevenshteinDistance;
/** /**
* A wrapper class that holds possible padlock passcode permutations in an integer array. This class * Holds a single possible padlock passcode permutation in an integer array. This class
* overloads the toString() method and is comparable, using its string value to calculate the levenshtein distance and * overloads the toString() method and is comparable, using its string value to calculate the levenshtein distance and
* use those distance values for sorting into a data structure. * use those distance values for sorting into a data structure.
*/ */
@ -50,7 +50,7 @@ public class IntegerLevenshtein implements Comparable<IntegerLevenshtein> {
} }
/** /**
* Overriden compareTo method that compares the calculated levenshtein distance between two IntegerLevenshtein objects * Overridden compareTo method that compares the calculated levenshtein distance between two IntegerLevenshtein objects
* @param otherInteger the object to be compared. * @param otherInteger the object to be compared.
* @return The levenshtein distance between the two objects. * @return The levenshtein distance between the two objects.
*/ */

View File

@ -1,7 +1,7 @@
package com.cleverthis.interview; package com.cleverthis.interview;
/** /**
* This defines the interface that padlocks must conform to. * This defines the contract that padlocks must conform to.
* Concrete implementations will be adapted to this interface contract through concrete adapter classes. * Concrete implementations will be adapted to this interface contract through concrete adapter classes.
*/ */
public interface PadlockAdapter { public interface PadlockAdapter {

View File

@ -1,7 +1,7 @@
package com.cleverthis.interview; package com.cleverthis.interview;
/** /**
* Interface that defines the class signature for solver implementations * Defines the contract for padlock-cracking solver implementations
*/ */
public interface SolverInterface { public interface SolverInterface {

View File

@ -1,11 +1,9 @@
package com.cleverthis.interview; package com.cleverthis.interview;
import java.util.Iterator;
import java.util.TreeSet; import java.util.TreeSet;
import org.apache.commons.text.similarity.LevenshteinDistance;
/** /**
* This is a write-aware brute solver implementation that uses the levenshtein distance to sort passcode permutations * A write-aware brute solver implementation that uses the levenshtein distance to sort passcode permutations
* into a tree. Walking the tree in-order (Likely a depth-first traversal internally) results in a naive nearest-neighbor * into a tree. Walking the tree in-order (Likely a depth-first traversal internally) results in a naive nearest-neighbor
* optimization that generally performs well, but may perform poorly in some cases. Heuristic solutions exist that have * optimization that generally performs well, but may perform poorly in some cases. Heuristic solutions exist that have
* acceptable performance, and this is a more naive heuristic implementation. * acceptable performance, and this is a more naive heuristic implementation.
@ -17,7 +15,7 @@ import org.apache.commons.text.similarity.LevenshteinDistance;
* A more advanced solution (based on Christofides, or another TSP heuristic) may result in more performance gains, but * A more advanced solution (based on Christofides, or another TSP heuristic) may result in more performance gains, but
* the performance of this nearest-neighbor solution is adequate for the keypad sizes under test. A keypad size of 9 * the performance of this nearest-neighbor solution is adequate for the keypad sizes under test. A keypad size of 9
* results in a graph of vertex-count 9!. It's unlikely performance gains from a more intelligent TSP solver would * results in a graph of vertex-count 9!. It's unlikely performance gains from a more intelligent TSP solver would
* offset the performance cost of building a graph and optimizing traversal. * offset the performance cost of building a graph and solving for an optimal tour.
*/ */
public class WriteAwareBruteSolver extends DumbBruteSolver { public class WriteAwareBruteSolver extends DumbBruteSolver {
@ -68,10 +66,8 @@ public class WriteAwareBruteSolver extends DumbBruteSolver {
* @param size The number of keys on the numpad * @param size The number of keys on the numpad
*/ */
protected void createOrderedTree(int size) { protected void createOrderedTree(int size) {
if(this.numpadSize != size) { this.numpadSize = size;
this.numpadSize = size; orderedTree.clear();
orderedTree.clear();
}
Integer[] currentPermutation = new Integer[numpadSize]; Integer[] currentPermutation = new Integer[numpadSize];
for(int i = 0; i < numpadSize; i++) { for(int i = 0; i < numpadSize; i++) {
@ -84,7 +80,7 @@ public class WriteAwareBruteSolver extends DumbBruteSolver {
IntegerLevenshtein levenshteinPermutation = new IntegerLevenshtein(numpadSize); IntegerLevenshtein levenshteinPermutation = new IntegerLevenshtein(numpadSize);
levenshteinPermutation.setIntegerData(currentPermutation); levenshteinPermutation.setIntegerData(currentPermutation);
orderedTree.add(levenshteinPermutation); orderedTree.add(levenshteinPermutation);
morePermutationsExist = this.calculateNextPermutation(currentPermutation, numpadSize); morePermutationsExist = this.calculateNextPermutation(currentPermutation);
} while(morePermutationsExist); } while(morePermutationsExist);
} }
} }

View File

@ -43,7 +43,7 @@ public class DumbBruteSolverTest extends SolutionTestBase {
Integer[] permutation = new Integer[] {1, 2, 3, 4}; Integer[] permutation = new Integer[] {1, 2, 3, 4};
Integer[] correctPermutation = new Integer[] {1, 2, 4, 3}; Integer[] correctPermutation = new Integer[] {1, 2, 4, 3};
dumbSolver.calculateNextPermutation(permutation, 4); dumbSolver.calculateNextPermutation(permutation);
assertArrayEquals(permutation, correctPermutation); assertArrayEquals(permutation, correctPermutation);
} }
@ -59,7 +59,7 @@ public class DumbBruteSolverTest extends SolutionTestBase {
Integer[] correctPermutation = new Integer[] {1, 3, 2, 4}; Integer[] correctPermutation = new Integer[] {1, 3, 2, 4};
for(int i = 0; i < 2; i++) { for(int i = 0; i < 2; i++) {
dumbSolver.calculateNextPermutation(permutation, 4); dumbSolver.calculateNextPermutation(permutation);
} }
assertArrayEquals(permutation, correctPermutation); assertArrayEquals(permutation, correctPermutation);
@ -76,7 +76,7 @@ public class DumbBruteSolverTest extends SolutionTestBase {
Integer[] correctPermutation = new Integer[] {4, 3, 2, 1}; Integer[] correctPermutation = new Integer[] {4, 3, 2, 1};
for(int i = 0; i < 23; i++) { for(int i = 0; i < 23; i++) {
dumbSolver.calculateNextPermutation(permutation, 4); dumbSolver.calculateNextPermutation(permutation);
} }
assertArrayEquals(permutation, correctPermutation); assertArrayEquals(permutation, correctPermutation);
@ -93,10 +93,10 @@ public class DumbBruteSolverTest extends SolutionTestBase {
Integer[] permutation = new Integer[] {1, 2, 3, 4}; Integer[] permutation = new Integer[] {1, 2, 3, 4};
for(int i = 0; i < 23; i++) { for(int i = 0; i < 23; i++) {
assertTrue(dumbSolver.calculateNextPermutation(permutation, 4)); assertTrue(dumbSolver.calculateNextPermutation(permutation));
} }
assertFalse(dumbSolver.calculateNextPermutation(permutation, 4)); assertFalse(dumbSolver.calculateNextPermutation(permutation));
} }
} }

View File

@ -1,7 +1,5 @@
package com.cleverthis.interview; package com.cleverthis.interview;
import com.cleverthis.interview.padlock.PadlockImpl;
/** /**
* Performance test but not mean to run in unit test. * Performance test but not mean to run in unit test.
*/ */

View File

@ -1,6 +1,5 @@
package com.cleverthis.interview; package com.cleverthis.interview;
import com.cleverthis.interview.padlock.PadlockImpl;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;