/*
* Copyright (C) 2022 NotEnoughUpdates contributors
*
* This file is part of NotEnoughUpdates.
*
* NotEnoughUpdates is free software: you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* NotEnoughUpdates is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with NotEnoughUpdates. If not, see .
*/
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.core.util.Vec3Comparable;
import io.github.moulberry.notenoughupdates.miscfeatures.CrystalMetalDetectorSolver.SolutionState;
import io.github.moulberry.notenoughupdates.util.NEUDebugLogger;
import net.minecraft.util.BlockPos;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
class CrystalMetalDetectorSolverTest {
class Location {
double distance;
Vec3Comparable playerPosition;
SolutionState expectedState;
boolean centerKnown;
public Location(
double distance,
Vec3Comparable playerPosition,
SolutionState expectedState,
boolean centerKnown
) {
this.distance = distance;
this.playerPosition = playerPosition;
this.expectedState = expectedState;
this.centerKnown = centerKnown;
}
}
class Solution {
ArrayList locations = new ArrayList<>();
BlockPos center = BlockPos.ORIGIN;
BlockPos expectedSolution = BlockPos.ORIGIN;
}
@BeforeEach
void setUp() {
CrystalMetalDetectorSolver.initWorld();
CrystalMetalDetectorSolver.treasureAllowedPredicate = blockPos -> true;
NEUDebugLogger.logMethod = CrystalMetalDetectorSolverTest::neuDebugLog;
NEUDebugLogger.allFlagsEnabled = true;
}
private void findPossibleSolutionsTwice(Location loc, boolean centerNewlyDiscovered) {
// Each location has to be received twice to be valid
CrystalMetalDetectorSolver.findPossibleSolutions(loc.distance, loc.playerPosition, centerNewlyDiscovered);
CrystalMetalDetectorSolver.findPossibleSolutions(loc.distance, loc.playerPosition, false);
}
private void checkSolution(Solution solution) {
boolean centerSet = false;
int index = 0;
for (Location loc : solution.locations) {
if (loc.centerKnown && !centerSet && !solution.center.equals(BlockPos.ORIGIN)) {
CrystalMetalDetectorSolver.setMinesCenter(solution.center);
centerSet = true;
findPossibleSolutionsTwice(loc, true);
} else {
findPossibleSolutionsTwice(loc, false);
}
Assertions.assertEquals(
loc.expectedState,
CrystalMetalDetectorSolver.currentState,
"Location index " + index
);
index++;
}
Assertions.assertEquals(solution.expectedSolution, CrystalMetalDetectorSolver.getSolution());
}
@Test
void findPossibleSolutions_single_location_sample_is_ignored() {
Location location = new Location(
37.3,
new Vec3Comparable(779.1057116115207, 70.5, 502.2997937667801),
SolutionState.MULTIPLE,
false
);
CrystalMetalDetectorSolver.findPossibleSolutions(location.distance, location.playerPosition, false);
Assertions.assertEquals(SolutionState.NOT_STARTED, CrystalMetalDetectorSolver.previousState,
"Previous state"
);
Assertions.assertEquals(SolutionState.NOT_STARTED, CrystalMetalDetectorSolver.currentState,
"Current state"
);
}
@Test
void findPossibleSolutions_currentState_becomes_previousState() {
Location location = new Location(
37.3,
new Vec3Comparable(779.1057116115207, 70.5, 502.2997937667801),
SolutionState.MULTIPLE,
false
);
findPossibleSolutionsTwice(location, false);
Assertions.assertEquals(SolutionState.NOT_STARTED, CrystalMetalDetectorSolver.previousState,
"Previous state"
);
Assertions.assertEquals(location.expectedState, CrystalMetalDetectorSolver.currentState,
"Current state"
);
}
@Test
void findPossibleSolutions_state_is_invalid_when_solution_and_distance_mismatch() {
Solution solution = new Solution();
solution.center = new BlockPos(736, 88, 547);
solution.expectedSolution = new BlockPos(722, 67, 590);
solution.locations.add(new Location(
67.5,
new Vec3Comparable(757.8235166144441, 68.0, 532.8037800566217),
SolutionState.FOUND_KNOWN,
true
));
// slightly different player position with invalid distance
solution.locations.add(new Location(
4.0,
new Vec3Comparable(757.8235166144441, 69.0, 532.8037800566217),
SolutionState.INVALID,
true
));
checkSolution(solution);
}
@Test
void findPossibleSolutions_state_is_failed_when_second_location_eliminates_all_blocks() {
Solution solution = new Solution();
solution.center = new BlockPos(736, 88, 547);
solution.locations.add(new Location(
29.4,
new Vec3Comparable(721.5979761606153, 68.0, 590.9056839507032),
SolutionState.MULTIPLE_KNOWN,
true
));
solution.locations.add(new Location(
4.0, // actual distance should be 38.2
new Vec3Comparable(711.858759313838, 67.0, 590.3583935310772),
SolutionState.FAILED,
true
));
checkSolution(solution);
}
@Test
void findPossibleSolutions_state_is_found_known_when_center_found_after_location() {
Solution solution = new Solution();
solution.center = new BlockPos(736, 88, 547);
solution.locations.add(new Location(
67.5,
new Vec3Comparable(757.8235166144441, 68.0, 532.8037800566217),
SolutionState.MULTIPLE,
false
));
checkSolution(solution);
solution.locations.get(0).centerKnown = true;
solution.locations.get(0).expectedState = SolutionState.FOUND_KNOWN;
solution.expectedSolution = new BlockPos(722, 67, 590);
checkSolution(solution);
}
@Test
void findPossibleSolutions_state_is_found_when_single_known_location() {
Solution solution = new Solution();
solution.center = new BlockPos(736, 88, 547);
solution.expectedSolution = new BlockPos(722, 67, 590);
solution.locations.add(new Location(
67.5,
new Vec3Comparable(757.8235166144441, 68.0, 532.8037800566217),
SolutionState.FOUND_KNOWN,
true
));
checkSolution(solution);
}
@Test
void findPossibleSolutions_states_are_correct_using_multiple_locations_with_unknown_center() {
Solution solution = new Solution();
solution.locations.add(new Location(
37.3,
new Vec3Comparable(779.1057116115207, 70.5, 502.2997937667801),
SolutionState.MULTIPLE,
false
));
solution.locations.add(new Location(
34.8,
new Vec3Comparable(782.6999999880791, 71.0, 508.69999998807907),
SolutionState.FOUND,
false
));
solution.expectedSolution = new BlockPos(758, 67, 533);
checkSolution(solution);
}
@Test
void findPossibleSolutions_states_are_correct_when_multiple_known_locations_found() {
Solution solution = new Solution();
// First, validate that the solution doesn't work without the center
solution.locations.add(new Location(
29.4,
new Vec3Comparable(721.5979761606153, 68.0, 590.9056839507032),
SolutionState.MULTIPLE,
false
));
solution.locations.add(new Location(
38.2,
new Vec3Comparable(711.858759313838, 67.0, 590.3583935310772),
SolutionState.MULTIPLE,
false
));
checkSolution(solution);
// Now validate that the solution works with the center
CrystalMetalDetectorSolver.resetSolution(false);
solution.locations.get(0).expectedState = SolutionState.MULTIPLE_KNOWN;
solution.locations.get(0).centerKnown = true;
solution.locations.get(1).expectedState = SolutionState.FOUND_KNOWN;
solution.locations.get(1).centerKnown = true;
solution.expectedSolution = new BlockPos(748, 66, 578);
solution.center = new BlockPos(736, 88, 547);
checkSolution(solution);
}
private static void neuDebugLog(String message) {
System.out.println(message);
}
}