import java.util.*;

/*
 * We need to get all of the keys. We only need to open doors if they prevent
 * us from getting to a key.
 * 
 * - Order the keys and their locations first in the tunnels?
 * - The order of keys is always a to z? Not necessarily.
 * - If we get to a door and we don't have the key to get through it then backtrack
 *   and find the key? Or don't even go there in the first place?
 * - If another key is closer to our current location than going through the
 *   next door then collect the key for shortest path.
 * - Go for all keys in sae direction until we hit a door that
 *   we can't pass then change direction.
 *
 * BFS from current location to next key.
 */

public class Explorer
{
    public Explorer (Map theMap, boolean debug)
    {
        _theMap = theMap;
        _start = _theMap.getEntrance();
        _totalNumnberOfKeys = _theMap.numberOfKeys();
        _states = new ArrayDeque<State>();
        _visited = new Vector<State>();
        _debug = debug;
    }

   /*
    * Algorithm:
    *
    * - initial starting point @
    * - move to find next key
    * - if we hit a door ...
    *      if we have the key, keep going
    *      if we do not have the key, we can't get through the door so we
    *      need to stop going in that direction and find the key.
    * - each time we find a key, reset the starting point and remember
    *   to reset the visited bit in each Node.
    * - keep going until we hit a door or find all keys
    */

    public int findAllKeys ()
    {
        _states.offer(new State(_start, Collections.emptySet(), 0));

        while (_states.size() > 0)
        {
            State state = _states.pop();
            
            if (_state.numberOfKeys() == _totalNumnberOfKeys)
                return state.numberOfSteps();

            for (Coordinate nextPosition : state.getPosition().directions())
            {
                if (!isValidPosition(nextPosition, map))
                    continue;
                var mapValue = nextPosition.getValueFrom(map);
                if (isUpperCase(mapValue) && !state.keys.contains(toLowerCase(mapValue)))
                    continue;
                var keys = state.keys;
                if (isLowerCase(mapValue)) {
                    keys = new HashSet<>(keys);
                    keys.add(mapValue);
                }
                var nextState = new State(nextPosition, keys, state.steps+1);
                if (!visitedState.add(nextState.identifier))
                    continue;
                states.add(nextState);
            }
        }
        throw new RuntimeException("Cannot find route");
    }

    private Map _theMap;
    private Coordinate _start;
    private int _totalNumnberOfKeys;
    private ArrayDeque<State> _states;
    private Vector<State> _visited;
    private boolean _debug;
}
@@ -1911,12 +1911,17 @@
 if (
-!isV
+_theMap.v
 alid
@@ -1945,13 +1945,8 @@
 tion
-, map
 ))%0A 
@@ -1966,32 +1966,33 @@
       continue;%0A
+%0A
                 
@@ -1995,55 +1995,58 @@
     
-var mapValue = nextPosition.getValueFrom(map
+char content = _theMap.getContent(nextPosition
 );%0A
+%0A
     
@@ -2065,75 +2065,55 @@
 if (
-isUpperCase(mapValue
+Util.isDoor(content)
 ) && !
+_
 state.
-keys.contains(toLowerCase(mapValue)
+hasKey(content
 ))%0A 
@@ -2133,32 +2133,33 @@
       continue;%0A
+%0A
                 
@@ -2162,19 +2162,30 @@
     
-var
+Set%3CCharacter%3E
  keys = 
 stat
@@ -2184,19 +2184,26 @@
 s = 
+_
 state.
-keys;
+getKeys();%0A
 %0A   
@@ -2223,30 +2223,44 @@
 if (
-isLowerCase(mapValue))
+Util.isKey(content))%0A               
  %7B%0A 
@@ -2339,16 +2339,15 @@
 add(
-mapValue
+content
 );%0A 
@@ -2355,32 +2355,33 @@
               %7D%0A
+%0A
                 
@@ -2384,11 +2384,13 @@
     
-var
+State
  nex
@@ -2432,24 +2432,36 @@
 ys, 
+_
 state.
-s
+numberOfS
 teps
+()
 +1);%0A
+%0A
     
@@ -2481,20 +2481,16 @@
 f (!
+_
 visited
-State
 .add
@@ -2500,17 +2500,20 @@
 xtState.
-i
+getI
 dentifie
@@ -2513,16 +2513,17 @@
 entifier
+(
 ))%0A     
@@ -2547,16 +2547,17 @@
 ntinue;%0A
+%0A
         
@@ -2564,16 +2564,17 @@
         
+_
 states.a
@@ -2624,55 +2624,26 @@
     
-throw new RuntimeException(%22Cannot find route%22)
+%0A        return -1
 ;%0A  
@@ -2800,19 +2800,20 @@
 ector%3CSt
-ate
+ring
 %3E _visit

Update Explorer.java