public PlayerPathData populateStats() {
        this.playerEntity = strongholdPath.getPlayerEntity();
        StrongholdGenerator.Start start = this.strongholdPath.getStart();
        StrongholdTreeAccessor treeAccessor = (StrongholdTreeAccessor) start;
        List<StrongholdPathEntry> history = this.strongholdPath.getHistory();
        ArrayList<StructurePiece> solution = new ArrayList<>();
        StrongholdGenerator.Piece current = this.strongholdPath.getHistory().get(strongholdPath.getHistory().size() - 1).getCurrentPiece();
        while (current != null) {
            solution.add(current);
            current = (StrongholdGenerator.Piece) treeAccessor.getParents().get(current);
        }
        List<StrongholdPathEntry> validEntries = history.stream()
                .filter(entry -> validateEntryForLoss(strongholdPath, strongholdPath.getNextEntry(entry)))
                .filter(entry -> !solution.contains(strongholdPath.getNextEntry(entry).getCurrentPiece()) && solution.contains(entry.getCurrentPiece()))
                .collect(Collectors.toList());
        List<Pair<StrongholdPathEntry, Double>> losses = new ArrayList<>();
        validEntries.forEach(strongholdPathEntry -> losses.add(new Pair<>(strongholdPathEntry, loss(strongholdPath, strongholdPath.getNextEntry(strongholdPathEntry), solution))));
        this.inaccuracies = losses.stream().filter(pair -> pair.getRight() >= INACCURACY_THRESHOLD).map(Pair::getLeft).map(StrongholdPathEntry::getCurrentPiece).collect(Collectors.toList());
        this.mistakes = losses.stream().filter(pair -> pair.getRight() >= MISTAKE_THRESHOLD).map(Pair::getLeft).map(StrongholdPathEntry::getCurrentPiece).collect(Collectors.toList());
        this.blunders = losses.stream().filter(pair -> pair.getRight() >= BLUNDER_THRESHOLD).map(Pair::getLeft).map(StrongholdPathEntry::getCurrentPiece).collect(Collectors.toList());
        inaccuracies.removeAll(this.mistakes);
        mistakes.removeAll(this.blunders);
        ArrayList<Pair<StrongholdGenerator.Piece, Integer>> rooms = new ArrayList<>();
        history.forEach(pathEntry -> {
            Pair<StrongholdGenerator.Piece, Integer> pair = new Pair<>(pathEntry.getCurrentPiece(), pathEntry.getTicksSpentInPiece().get());
            rooms.add(pair);
        });
        return new PlayerPathData(
                rooms,
                strongholdPath.getTotalTime(),
                computeDifficulty(solution),
                history.stream()
                        .filter(pathEntry -> !solution.contains(pathEntry.getCurrentPiece()))
                        .map(StrongholdPathEntry::getTicksSpentInPiece)
                        .mapToInt(AtomicInteger::get)
                        .sum(),
                // TODO: don't count entering the first Five-Way
                (int) history.stream()
                        .map(strongholdPathEntry -> strongholdPath.getNextEntry(strongholdPathEntry))
                        .filter(Objects::nonNull)
                        .map(StrongholdPathEntry::getCurrentPiece)
                        .filter(solution::contains)
                        .count(),
                this.inaccuracies.size(),
                this.mistakes.size(),
                this.blunders.size(),
                (int) history.stream()
                        .filter(entry -> !(entry.getCurrentPiece() instanceof StrongholdGenerator.PortalRoom))
                        .filter(entry -> !areAdjacent(entry.getCurrentPiece(), strongholdPath.getNextEntry(entry).getCurrentPiece(), treeAccessor))
                        .count(),
                history.size() - 1,
                history.stream()
                        .filter(entry -> FEINBERG_AVG_ROOM_TIMES.containsKey(entry.getCurrentPiece().getClass()))
                        .mapToInt(value -> value.getTicksSpentInPiece().get() - FEINBERG_AVG_ROOM_TIMES.get(value.getCurrentPiece().getClass()))
                        .sum()
        );
    }
public PlayerPathData populateStats() {
        this.playerEntity = strongholdPath.getPlayerEntity();
        StrongholdGenerator.Start start = this.strongholdPath.getStart();
        StrongholdTreeAccessor treeAccessor = (StrongholdTreeAccessor) start;
        List<StrongholdPathEntry> history = this.strongholdPath.getHistory();
        ArrayList<StructurePiece> solution = new ArrayList<>();
        StrongholdGenerator.Piece current = this.strongholdPath.getHistory().get(strongholdPath.getHistory().size() - 1).getCurrentPiece();
        while (current != null) {
            solution.add(current);
            current = (StrongholdGenerator.Piece) treeAccessor.getParents().get(current);
        }
        List<StrongholdPathEntry> validEntries = history.stream()
                .filter(entry -> validateEntryForLoss(strongholdPath, strongholdPath.getNextEntry(entry)))
                .filter(entry -> !solution.contains(strongholdPath.getNextEntry(entry).getCurrentPiece()) && solution.contains(entry.getCurrentPiece()))
                .collect(Collectors.toList());
        List<Pair<StrongholdPathEntry, Double>> losses = new ArrayList<>();
        validEntries.forEach(strongholdPathEntry -> losses.add(new Pair<>(strongholdPathEntry, loss(strongholdPath, strongholdPath.getNextEntry(strongholdPathEntry), solution))));
        this.inaccuracies = losses.stream().filter(pair -> pair.getRight() >= INACCURACY_THRESHOLD).map(Pair::getLeft).map(StrongholdPathEntry::getCurrentPiece).collect(Collectors.toList());
        this.mistakes = losses.stream().filter(pair -> pair.getRight() >= MISTAKE_THRESHOLD).map(Pair::getLeft).map(StrongholdPathEntry::getCurrentPiece).collect(Collectors.toList());
        this.blunders = losses.stream().filter(pair -> pair.getRight() >= BLUNDER_THRESHOLD).map(Pair::getLeft).map(StrongholdPathEntry::getCurrentPiece).collect(Collectors.toList());
        inaccuracies.removeAll(this.mistakes);
        mistakes.removeAll(this.blunders);
        ArrayList<Pair<StrongholdGenerator.Piece, Integer>> rooms = new ArrayList<>();
        history.forEach(pathEntry -> {
            Pair<StrongholdGenerator.Piece, Integer> pair = new Pair<>(pathEntry.getCurrentPiece(), pathEntry.getTicksSpentInPiece().get());
            rooms.add(pair);
        });
        return new PlayerPathData(
                rooms,
                strongholdPath.getTotalTime(),
                computeDifficulty(solution),
                history.stream()
                        .filter(pathEntry -> !solution.contains(pathEntry.getCurrentPiece()))
                        .map(StrongholdPathEntry::getTicksSpentInPiece)
                        .mapToInt(AtomicInteger::get)
                        .sum(),
               
                (int) history.stream()
                        .map(strongholdPathEntry -> strongholdPath.getNextEntry(strongholdPathEntry))
                        .filter(Objects::nonNull)
                        .map(StrongholdPathEntry::getCurrentPiece)
                        .filter(solution::contains)
                        .count(),
                this.inaccuracies.size(),
                this.mistakes.size(),
                this.blunders.size(),
                (int) history.stream()
                        .filter(entry -> !(entry.getCurrentPiece() instanceof StrongholdGenerator.PortalRoom))
                        .filter(entry -> !areAdjacent(entry.getCurrentPiece(), strongholdPath.getNextEntry(entry).getCurrentPiece(), treeAccessor))
                        .count(),
                history.size() - 1,
                history.stream()
                        .filter(entry -> FEINBERG_AVG_ROOM_TIMES.containsKey(entry.getCurrentPiece().getClass()))
                        .mapToInt(value -> value.getTicksSpentInPiece().get() - FEINBERG_AVG_ROOM_TIMES.get(value.getCurrentPiece().getClass()))
                        .sum()
        );
    }
public playerpathdata populatestats() { this.playerentity = strongholdpath.getplayerentity(); strongholdgenerator.start start = this.strongholdpath.getstart(); strongholdtreeaccessor treeaccessor = (strongholdtreeaccessor) start; list<strongholdpathentry> history = this.strongholdpath.gethistory(); arraylist<structurepiece> solution = new arraylist<>(); strongholdgenerator.piece current = this.strongholdpath.gethistory().get(strongholdpath.gethistory().size() - 1).getcurrentpiece(); while (current != null) { solution.add(current); current = (strongholdgenerator.piece) treeaccessor.getparents().get(current); } list<strongholdpathentry> validentries = history.stream() .filter(entry -> validateentryforloss(strongholdpath, strongholdpath.getnextentry(entry))) .filter(entry -> !solution.contains(strongholdpath.getnextentry(entry).getcurrentpiece()) && solution.contains(entry.getcurrentpiece())) .collect(collectors.tolist()); list<pair<strongholdpathentry, double>> losses = new arraylist<>(); validentries.foreach(strongholdpathentry -> losses.add(new pair<>(strongholdpathentry, loss(strongholdpath, strongholdpath.getnextentry(strongholdpathentry), solution)))); this.inaccuracies = losses.stream().filter(pair -> pair.getright() >= inaccuracy_threshold).map(pair::getleft).map(strongholdpathentry::getcurrentpiece).collect(collectors.tolist()); this.mistakes = losses.stream().filter(pair -> pair.getright() >= mistake_threshold).map(pair::getleft).map(strongholdpathentry::getcurrentpiece).collect(collectors.tolist()); this.blunders = losses.stream().filter(pair -> pair.getright() >= blunder_threshold).map(pair::getleft).map(strongholdpathentry::getcurrentpiece).collect(collectors.tolist()); inaccuracies.removeall(this.mistakes); mistakes.removeall(this.blunders); arraylist<pair<strongholdgenerator.piece, integer>> rooms = new arraylist<>(); history.foreach(pathentry -> { pair<strongholdgenerator.piece, integer> pair = new pair<>(pathentry.getcurrentpiece(), pathentry.getticksspentinpiece().get()); rooms.add(pair); }); return new playerpathdata( rooms, strongholdpath.gettotaltime(), computedifficulty(solution), history.stream() .filter(pathentry -> !solution.contains(pathentry.getcurrentpiece())) .map(strongholdpathentry::getticksspentinpiece) .maptoint(atomicinteger::get) .sum(), (int) history.stream() .map(strongholdpathentry -> strongholdpath.getnextentry(strongholdpathentry)) .filter(objects::nonnull) .map(strongholdpathentry::getcurrentpiece) .filter(solution::contains) .count(), this.inaccuracies.size(), this.mistakes.size(), this.blunders.size(), (int) history.stream() .filter(entry -> !(entry.getcurrentpiece() instanceof strongholdgenerator.portalroom)) .filter(entry -> !areadjacent(entry.getcurrentpiece(), strongholdpath.getnextentry(entry).getcurrentpiece(), treeaccessor)) .count(), history.size() - 1, history.stream() .filter(entry -> feinberg_avg_room_times.containskey(entry.getcurrentpiece().getclass())) .maptoint(value -> value.getticksspentinpiece().get() - feinberg_avg_room_times.get(value.getcurrentpiece().getclass())) .sum() ); }