public String generatePath() {
        // Our input for solving
        StartFinish startFinish = new StartFinish();
        KeyTable<Vertex, String> table = new KeyTable<Vertex, String>();

        prepareForSolving(table, startFinish);

        Vertex start = startFinish.getStart();
        Vertex finish = startFinish.getFinish();

//        for (int r = 0; r < table.size(); r++) {
//            System.out.println("TEST: table: " + table.getValueForKey(table.getKey(r).getA(), table.getKey(r).getB()));
//        }

        // Working space for solving
        List<Vertex> layer;
        List<Vertex> nextLayer = new ArrayList<Vertex>();

        // Starting preparations
        table.addKey(finish, finish, "");
        table.addKey(start, start, "");
        nextLayer.add(finish);

        while (nextLayer.size() > 0) {
            layer = nextLayer;
            nextLayer = new ArrayList<Vertex>();

            for (int i = 0; i < layer.size(); i++) {
                // take its children, process them
                for (int j = 0; j < layer.get(i).getChildrenAmount(); j++) {
                    Vertex thisVertex = layer.get(i).getChild(j);
                    Vertex parentVertex = layer.get(i);

                    // check table for that key
//                    String calculatedPath = table.getValueForKey(thisVertex, parentVertex)
//                            + table.getValueForKey(parentVertex, finish);
                    String calculatedPath = getValueForThisOrOppositeKey(table, thisVertex, parentVertex) +
                            getValueForThisOrOppositeKey(table, parentVertex, finish);

                    // I check also for parent==finish because otherwise everything(given only one child for
                    // finish) would terminate
                    if (table.keyExists(thisVertex, finish) || table.keyExists(finish, thisVertex)) {
                        if (getValueForThisOrOppositeKey(table, thisVertex, finish).length() > calculatedPath.length()) {
                            setNewValueForKeyOrOpposite(table, thisVertex, finish, calculatedPath);
                        }

                        if (parentVertex.equals(finish)) {
                            // CONTINUE
                            nextLayer.add(thisVertex);
                        }

                        // TERMINATE

                    } else {
                        table.addKey(thisVertex, finish, calculatedPath);
//                        table.addKey(finish, thisVertex, invert(calculatedPath));

                        if (!thisVertex.equals(start)) {
                            // CONTINUE
                            nextLayer.add(thisVertex);
                        }

                        // If this is Start then TERMINATE
                    }
                }
            }
        }

//        System.out.println("Table size:" + table.size());

//        String p = table.getValueForKey(start, finish);
        String p = getValueForThisOrOppositeKey(table, start, finish);
        if (p == null) {
            System.out.println("Start -> Finish == null");
        }

        return p;
    }