package com.cleverthis.interview.padlock; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import static com.cleverthis.interview.padlock.Utils.ensureSleep; /** * This is a logical representation of a physical padlock with a numpad. *
* The padlock has the following features: * *
* After create, the input buffer is empty, you have to initialize. */ public class PadlockImpl { private final boolean fast = Boolean.parseBoolean(System.getProperty("fast")); private final int numpadSize; private final Integer[] inputBuffer; private final Integer[] correctPasscode; /** * Create a padlock instance. * * @param numpadSize The number of buttons on the numpad of this lock. */ public PadlockImpl(int numpadSize) { if (numpadSize < 1) throw new IllegalArgumentException("numpadSize must be a positive number"); this.numpadSize = numpadSize; this.inputBuffer = new Integer[numpadSize]; List answer = new ArrayList<>(numpadSize); for (int i = 0; i < numpadSize; i++) answer.add(i); for (int i = 0; i < numpadSize / 2; i++) { Collections.shuffle(answer); } this.correctPasscode = answer.toArray(new Integer[0]); } public int getNumpadSize() { return numpadSize; } /** * Write a digit into padlock's input buffer. This is a very expensive operation. * * @param address The digits you want to write. Range: [0, numpadSize) * @param keyIndex The key/button index you want to put here. Range: [0, numpadSize) * @return The old value, null if not initialized. */ public synchronized Integer writeInputBuffer(int address, int keyIndex) { if (!fast) ensureSleep(1000); if (keyIndex < 0 || keyIndex >= numpadSize) throw new IllegalArgumentException( "keyIndex out of range. Keypad size: " + numpadSize + ", keyIndex: " + keyIndex); Integer oldValue = inputBuffer[address]; inputBuffer[address] = keyIndex; return oldValue; } /** * Check if the input buffer contains a correct passcode. * * @return true if the passcode is correct; false if passcode is wrong. * @throws IllegalStateException if the input buffer is not a valid passcode */ public synchronized boolean isPasscodeCorrect() { // first check if the input is legal boolean[] uniqueTestArr = new boolean[numpadSize]; for (Integer i : inputBuffer) { if (i == null) throw new IllegalStateException( "Passcode invalid: contain uninitialized value. " + Arrays.toString(inputBuffer)); if (uniqueTestArr[i]) throw new IllegalStateException( "Passcode invalid: contain duplicated value. " + Arrays.toString(inputBuffer)); uniqueTestArr[i] = true; } // if no exception, means: // every digit is unique, and every digit is initialized // aka this is a valid code // now compare with our answer return Arrays.equals(correctPasscode, inputBuffer); } }