// TODO: don't count entering the first Five-Way
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()
        );
    }
.mapToInt(AtomicInteger::get)
.sum(),
// TODO: don't count entering the first Five-Way
(int) history.stream()
.map(strongholdPathEntry -> strongholdPath.getNextEntry(strongholdPathEntry))
});
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()
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()
);
}