Commit 4fdae855 authored by mamunozgil's avatar mamunozgil
Browse files

Added debug logs

1 merge request!3Fix: dev recommendations
Pipeline #10595 passed with stage
in 18 seconds
This commit is part of merge request !3. Comments created here will be created in the context of that merge request.
Showing with 241 additions and 170 deletions
+241 -170
...@@ -27,110 +27,127 @@ import java.io.FileNotFoundException; ...@@ -27,110 +27,127 @@ import java.io.FileNotFoundException;
public class CompetencyAssessmentUtil { public class CompetencyAssessmentUtil {
private static final Logger LOG = LogManager.getLogger(CompetencyAssessmentUtil.class); private static final Logger LOG = LogManager.getLogger(CompetencyAssessmentUtil.class);
public static String TEST_COMPETENCY_MANIFEST_FILE_NAME="competency-tests.mft"; public static String TEST_COMPETENCY_MANIFEST_FILE_NAME = "competency-tests.mft";
public static String EXERCISE_COMPETENCY_MANIFEST_FILE_NAME="exercise-tests.mft"; public static String EXERCISE_COMPETENCY_MANIFEST_FILE_NAME = "exercise-tests.mft";
/*public static void main(String[] args) throws StreamReadException, DatabindException, MalformedURLException, IOException {
ResultSummary summary=ExecuteTestUtil.generateResult("1", Path.of(args[0]), Path.of(args[1]));
System.out.println(summary.successfulTestCompetencyProfile);
}
*/
public static float[] sumTestCompetencyProfiles(List<TestCompetencyProfile> testCompetencyProfiles) { public static float[] sumTestCompetencyProfiles(List<TestCompetencyProfile> testCompetencyProfiles) {
float[] tcpTotalProfile=new float[ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS]; LOG.debug("Starting sumTestCompetencyProfiles with {} test profiles.", testCompetencyProfiles.size());
for(TestCompetencyProfile currentProfile: testCompetencyProfiles) {
tcpTotalProfile=ICompetencyProfile.competencySum(tcpTotalProfile, currentProfile.competencyAssessments); float[] tcpTotalProfile = new float[ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS];
for (TestCompetencyProfile currentProfile : testCompetencyProfiles) {
LOG.debug("Adding competency assessments from profile: {}", currentProfile.testName);
tcpTotalProfile = ICompetencyProfile.competencySum(tcpTotalProfile, currentProfile.competencyAssessments);
} }
LOG.debug("Completed summing test competency profiles. Total profile: {}", packFloats(tcpTotalProfile));
return tcpTotalProfile; return tcpTotalProfile;
} }
public static float[] sumSuccessfulCompetencyProfiles(List<TestCompetencyProfile> testCompetencyProfiles, ResultSummary resultSummary, boolean success) { public static float[] sumSuccessfulCompetencyProfiles(List<TestCompetencyProfile> testCompetencyProfiles, ResultSummary resultSummary, boolean success) {
float[] sumSuccessful=new float[ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS]; LOG.debug("Starting sumSuccessfulCompetencyProfiles. Success flag: {}", success);
for(Result currentResult: resultSummary.results) {
float[] sumSuccessful = new float[ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS];
for (Result currentResult : resultSummary.results) {
boolean isSuccess = Integer.valueOf(currentResult.state).equals(Result.State.SUCCESS.ordinal()); boolean isSuccess = Integer.valueOf(currentResult.state).equals(Result.State.SUCCESS.ordinal());
if (isSuccess == success) { LOG.debug("Processing result: {} with success state: {}", currentResult.name, isSuccess);
TestCompetencyProfile currentProfile=new TestCompetencyProfile();
currentProfile.testPackageName=(currentResult.packageName!=null)?currentResult.packageName:""; if (isSuccess == success) {
currentProfile.testClassName=(currentResult.className!=null)?currentResult.className:""; TestCompetencyProfile currentProfile = new TestCompetencyProfile();
currentProfile.testName=(currentResult.name!=null)?currentResult.name:""; currentProfile.testPackageName = (currentResult.packageName != null) ? currentResult.packageName : "";
int testIndex=testCompetencyProfiles.indexOf(currentProfile); currentProfile.testClassName = (currentResult.className != null) ? currentResult.className : "";
if(testIndex!=-1) { currentProfile.testName = (currentResult.name != null) ? currentResult.name : "";
sumSuccessful=ICompetencyProfile.competencySum(sumSuccessful, testCompetencyProfiles.get(testIndex).competencyAssessments);
int testIndex = testCompetencyProfiles.indexOf(currentProfile);
if (testIndex != -1) {
LOG.debug("Found matching profile for result: {}. Adding competencies.", currentResult.name);
sumSuccessful = ICompetencyProfile.competencySum(sumSuccessful, testCompetencyProfiles.get(testIndex).competencyAssessments);
} else {
LOG.debug("No matching profile found for result: {}", currentResult.name);
} }
} }
} }
LOG.debug("Completed summing successful competency profiles. Sum: {}", packFloats(sumSuccessful));
return sumSuccessful; return sumSuccessful;
} }
public static List<TestCompetencyProfile> readTestCompetencyProfiles(Path testPath, String fileName) { public static List<TestCompetencyProfile> readTestCompetencyProfiles(Path testPath, String fileName) {
List<TestCompetencyProfile> testCompetencyProfiles=new ArrayList<TestCompetencyProfile>(); LOG.debug("Reading test competency profiles from path: {}, file: {}", testPath, fileName);
try {
BufferedReader testCompetencyManifest=new BufferedReader(new FileReader(new File(testPath.toFile(), fileName))); List<TestCompetencyProfile> testCompetencyProfiles = new ArrayList<>();
String testEntry=testCompetencyManifest.readLine(); try (BufferedReader testCompetencyManifest = new BufferedReader(new FileReader(new File(testPath.toFile(), fileName)))) {
while(testEntry!=null) String testEntry = testCompetencyManifest.readLine();
{
String[] testEntyComponents=testEntry.split(ICompetencyProfile.COMPETENCY_SEPARATOR); while (testEntry != null) {
TestCompetencyProfile currentProfile=new TestCompetencyProfile(); String[] testEntyComponents = testEntry.split(ICompetencyProfile.COMPETENCY_SEPARATOR);
currentProfile.testPackageName=testEntyComponents[0]; TestCompetencyProfile currentProfile = new TestCompetencyProfile();
currentProfile.testClassName=testEntyComponents[1];
currentProfile.testName=testEntyComponents[2]; currentProfile.testPackageName = testEntyComponents[0];
for(int competencyIndex=0; competencyIndex<ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS; competencyIndex++) { currentProfile.testClassName = testEntyComponents[1];
currentProfile.competencyAssessments[competencyIndex]=Float.valueOf(testEntyComponents[competencyIndex+3]); currentProfile.testName = testEntyComponents[2];
for (int competencyIndex = 0; competencyIndex < ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS; competencyIndex++) {
currentProfile.competencyAssessments[competencyIndex] = Float.valueOf(testEntyComponents[competencyIndex + 3]);
} }
testCompetencyProfiles.add(currentProfile); testCompetencyProfiles.add(currentProfile);
testEntry=testCompetencyManifest.readLine(); LOG.debug("Added test competency profile: {}", currentProfile.testName);
testEntry = testCompetencyManifest.readLine();
} }
testCompetencyManifest.close();
LOG.info("Added "+testCompetencyProfiles.size()+" test competency profiles from test competency manifest. Optional agent functionality enabled."); LOG.info("Added {} test competency profiles from manifest.", testCompetencyProfiles.size());
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
LOG.info("Test competency manifest file for agent feedback not found. Skipping optional functionality."); LOG.info("Test competency manifest file not found. Skipping functionality.");
testCompetencyProfiles=null;
} catch (IOException e) { } catch (IOException e) {
LOG.info("Test competency manifest file for agent feedback unreadable. Skipping optional functionality."); LOG.info("Test competency manifest file unreadable. Skipping functionality.");
testCompetencyProfiles=null; }
}
return testCompetencyProfiles; return testCompetencyProfiles;
} }
public static List<ExerciseCompetencyProfile> readExerciseCompetencyProfiles(Path exercisePath, String fileName) { public static List<ExerciseCompetencyProfile> readExerciseCompetencyProfiles(Path exercisePath, String fileName) {
List<ExerciseCompetencyProfile> exerciseCompetencyProfiles = new ArrayList<>(); LOG.debug("Reading exercise competency profiles from path: {}, file: {}", exercisePath, fileName);
try (BufferedReader exerciseCompetencyManifest = new BufferedReader(new FileReader(new File(exercisePath.toFile(), fileName)))) { List<ExerciseCompetencyProfile> exerciseCompetencyProfiles = new ArrayList<>();
String exerciseEntry = exerciseCompetencyManifest.readLine();
try (BufferedReader exerciseCompetencyManifest = new BufferedReader(new FileReader(new File(exercisePath.toFile(), fileName)))) {
while (exerciseEntry != null) { String exerciseEntry = exerciseCompetencyManifest.readLine();
String[] exerciseEntyComponents = exerciseEntry.split(ExerciseCompetencyProfile.COMPETENCY_SEPARATOR);
ExerciseCompetencyProfile currentProfile = new ExerciseCompetencyProfile(); while (exerciseEntry != null) {
String[] exerciseEntyComponents = exerciseEntry.split(ExerciseCompetencyProfile.COMPETENCY_SEPARATOR);
currentProfile.exerciseTopicName = exerciseEntyComponents[0]; ExerciseCompetencyProfile currentProfile = new ExerciseCompetencyProfile();
currentProfile.exerciseName = exerciseEntyComponents[1];
currentProfile.exerciseURL = exerciseEntyComponents[2]; currentProfile.exerciseTopicName = exerciseEntyComponents[0];
currentProfile.exerciseName = exerciseEntyComponents[1];
for (int competencyIndex = 0; competencyIndex < ExerciseCompetencyProfile.MAX_COMPETENCY_DIMENSIONS; competencyIndex++) { currentProfile.exerciseURL = exerciseEntyComponents[2];
currentProfile.competencyAssessments[competencyIndex] = Float.valueOf(exerciseEntyComponents[competencyIndex+3]);
} for (int competencyIndex = 0; competencyIndex < ExerciseCompetencyProfile.MAX_COMPETENCY_DIMENSIONS; competencyIndex++) {
currentProfile.competencyAssessments[competencyIndex] = Float.valueOf(exerciseEntyComponents[competencyIndex + 3]);
currentProfile.difficulty = Float.parseFloat(exerciseEntyComponents[19]); }
exerciseCompetencyProfiles.add(currentProfile); currentProfile.difficulty = Float.parseFloat(exerciseEntyComponents[19]);
exerciseEntry = exerciseCompetencyManifest.readLine(); exerciseCompetencyProfiles.add(currentProfile);
} LOG.debug("Added exercise competency profile: {}", currentProfile.exerciseName);
exerciseCompetencyManifest.close();
LOG.info("Added " + exerciseCompetencyProfiles.size() + " test competency profiles from exercise competency manifest."); exerciseEntry = exerciseCompetencyManifest.readLine();
} catch (FileNotFoundException e) { }
LOG.info("Exercise competency manifest file not found.");
} catch (IOException e) { LOG.info("Added {} exercise competency profiles from manifest.", exerciseCompetencyProfiles.size());
LOG.info("Exercise competency manifest file unreadable."); } catch (FileNotFoundException e) {
} LOG.info("Exercise competency manifest file not found.");
} catch (IOException e) {
return exerciseCompetencyProfiles; LOG.info("Exercise competency manifest file unreadable.");
}
return exerciseCompetencyProfiles;
} }
public static String packFloats(float[] array) { public static String packFloats(float[] array) {
LOG.debug("Packing float array into string: {}", array);
return IntStream.range(0, array.length) return IntStream.range(0, array.length)
.mapToObj(i -> String.valueOf(array[i])) .mapToObj(i -> String.valueOf(array[i]))
.collect(Collectors.joining(";")); .collect(Collectors.joining(";"));
} }
} }
...@@ -71,7 +71,7 @@ public class ExecuteTestUtil { ...@@ -71,7 +71,7 @@ public class ExecuteTestUtil {
assignmentBasePath + assignmentId + "_checkout", assignmentBasePath + assignmentId + "_checkout",
testPath.toString() ); testPath.toString() );
Files.copy(Paths.get( Files.copy(Paths.get(
assignmentBasePath, assignmentId + "_checkout", assignmentBasePath, assignmentId + "_checkout",
CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME), CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME),
Paths.get( Paths.get(
testPath.toString(), testPath.toString(),
...@@ -177,99 +177,153 @@ public class ExecuteTestUtil { ...@@ -177,99 +177,153 @@ public class ExecuteTestUtil {
return resultSummary; return resultSummary;
} }
/* /*
* exercise recommendation part * exercise recommendation part
*/ */
public List<Recommendation> recommendNextExercises(String assignmentId, Path testPathHost, List<TestCompetencyProfile> testCompetencyProfiles, ResultSummary resultSummary) public List<Recommendation> recommendNextExercises(String assignmentId, Path testPathHost, List<TestCompetencyProfile> testCompetencyProfiles, ResultSummary resultSummary)
throws FileNotFoundException { throws FileNotFoundException {
// fetch repo url from original test upload LOG.debug("Starting recommendNextExercises with assignmentId: {}", assignmentId);
Pattern pattern = Pattern.compile(RegexUtil.DTA_TESTCONFIGREGEX);
File file = Paths.get(assignmentBasePath, assignmentId + ".txt").toFile(); // fetch repo url from original test upload
FileInputStream configFileStream = new FileInputStream(file); Pattern pattern = Pattern.compile(RegexUtil.DTA_TESTCONFIGREGEX);
Matcher config = RegexUtil.extractConfig(configFileStream, pattern); LOG.debug("Compiled regex pattern for DTA_TESTCONFIGREGEX.");
String testRepoURL = config.group(1)+config.group(4);
File file = Paths.get(assignmentBasePath, assignmentId + ".txt").toFile();
List<ExerciseCompetencyProfile> exerciseCompetencyProfiles = CompetencyAssessmentUtil.readExerciseCompetencyProfiles(testPathHost, CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME); LOG.debug("Resolved file path for assignmentId {}: {}", assignmentId, file.getAbsolutePath());
int currentTopicIndex=0; FileInputStream configFileStream = new FileInputStream(file);
float currentDifficulty=0.0f; LOG.debug("Opened FileInputStream for file: {}", file.getAbsolutePath());
//build course topic order Matcher config = RegexUtil.extractConfig(configFileStream, pattern);
Map<String, Integer> topicOrder = new HashMap<>(); LOG.debug("Extracted configuration using regex pattern.");
int order = 1;
for (ExerciseCompetencyProfile e : exerciseCompetencyProfiles) { String testRepoURL = config.group(1) + config.group(4);
if (!topicOrder.containsKey(e.exerciseTopicName)) { LOG.debug("Constructed testRepoURL: {}", testRepoURL);
topicOrder.put(e.exerciseTopicName, order++);
} List<ExerciseCompetencyProfile> exerciseCompetencyProfiles = CompetencyAssessmentUtil.readExerciseCompetencyProfiles(
if (e.exerciseURL.equals(testRepoURL)) { testPathHost, CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME);
currentTopicIndex = order; LOG.debug("Read exercise competency profiles from path: {}", testPathHost.resolve(CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME));
currentDifficulty = e.difficulty;
} int currentTopicIndex = 0;
float currentDifficulty = 0.0f;
// build course topic order
LOG.debug("Building course topic order.");
Map<String, Integer> topicOrder = new HashMap<>();
int order = 1;
for (ExerciseCompetencyProfile e : exerciseCompetencyProfiles) {
if (!topicOrder.containsKey(e.exerciseTopicName)) {
topicOrder.put(e.exerciseTopicName, order++);
LOG.debug("Added topic {} to topicOrder with order {}", e.exerciseTopicName, order - 1);
} }
if (e.exerciseURL.equals(testRepoURL)) {
//filter exercises according to success currentTopicIndex = order;
float[] unsuccessful = CompetencyAssessmentUtil.sumSuccessfulCompetencyProfiles(testCompetencyProfiles, resultSummary, false); currentDifficulty = e.difficulty;
List<ExerciseCompetencyProfile> filteredExercises = filterExercisesByTopicsAndDifficulty( LOG.debug("Matched current testRepoURL to topic: {}, index: {}, difficulty: {}", e.exerciseTopicName, currentTopicIndex, currentDifficulty);
exerciseCompetencyProfiles, topicOrder, currentTopicIndex, testRepoURL,
currentDifficulty, unsuccessful, resultSummary);
//compute recommendations
List<Recommendation> recommendedExercises = new ArrayList<>();
for (ExerciseCompetencyProfile exerciseProfile : filteredExercises) {
Recommendation recommendation = new Recommendation(exerciseProfile.exerciseTopicName, exerciseProfile.exerciseURL, exerciseProfile.exerciseName,
exerciseProfile.difficulty, calculateScore(exerciseProfile, unsuccessful, topicOrder, currentDifficulty));
recommendedExercises.add(recommendation);
LOG.info("Recommending exercise "+recommendation.topic+"/"+recommendation.exerciseName+" with score "+recommendation.score);
} }
//sort the recommendations for successful or resilient learners, otherwise reverse in display
recommendedExercises.stream().sorted(Recommendation.COMPARE_BY_SCORE).collect(Collectors.toList());
return recommendedExercises;
} }
public static List<ExerciseCompetencyProfile> filterExercisesByTopicsAndDifficulty(List<ExerciseCompetencyProfile> exerciseCompetencyProfiles, // filter exercises according to success
Map<String, Integer> topicOrder, int currentTopicIndex, String testRepoURL, float currentDifficulty, float[] unsuccessful, LOG.debug("Filtering exercises according to success.");
ResultSummary resultSummary) { float[] unsuccessful = CompetencyAssessmentUtil.sumSuccessfulCompetencyProfiles(testCompetencyProfiles, resultSummary, false);
//filter out all advanced topics in any case LOG.debug("Computed unsuccessful competency profile: {}", unsuccessful);
//option for later: include next topic if fullsuccess and current difficulty == max difficulty
List<ExerciseCompetencyProfile> filteredExercises = exerciseCompetencyProfiles.stream()
.filter(testProfile -> topicOrder.get(testProfile.exerciseTopicName) <= currentTopicIndex)
.collect(Collectors.toList());
//filter by difficulty according to success
if (isFullSuccess(unsuccessful)) {
filteredExercises = filteredExercises.stream().filter(profile -> profile.difficulty >= currentDifficulty && !testRepoURL.equals(profile.exerciseURL)).collect(Collectors.toList());
} else {
filteredExercises = filteredExercises.stream().filter(profile -> profile.difficulty <= currentDifficulty).collect(Collectors.toList());
}
return filteredExercises; List<ExerciseCompetencyProfile> filteredExercises = filterExercisesByTopicsAndDifficulty(
} exerciseCompetencyProfiles, topicOrder, currentTopicIndex, testRepoURL,
currentDifficulty, unsuccessful, resultSummary);
public static boolean isFullSuccess(float[] unsuccessful) { LOG.debug("Filtered exercises count: {}", filteredExercises.size());
for (float value : unsuccessful) {
if (value != 0.0f) {
return false;
}
}
return true;
}
public static float calculateScore(ExerciseCompetencyProfile exerciseProfile, float[] unsuccessful, Map<String, Integer> topicOrder, float currentDifficulty) { // compute recommendations
//ensure factor 1 for full success not to blank out score, thus offset the base LOG.debug("Computing recommendations from filtered exercises.");
float score = 1.0f; List<Recommendation> recommendedExercises = new ArrayList<>();
//competency profile difference to not fully achieved competencies component for (ExerciseCompetencyProfile exerciseProfile : filteredExercises) {
for (int i = 0; i < exerciseProfile.competencyAssessments.length-1; i++) { Recommendation recommendation = new Recommendation(
score += exerciseProfile.competencyAssessments[i] * unsuccessful[i]; exerciseProfile.exerciseTopicName, exerciseProfile.exerciseURL, exerciseProfile.exerciseName,
} exerciseProfile.difficulty, calculateScore(exerciseProfile, unsuccessful, topicOrder, currentDifficulty));
recommendedExercises.add(recommendation);
//difficulty component LOG.info("Recommending exercise {}/{} with score {}", recommendation.topic, recommendation.exerciseName, recommendation.score);
score = score * (exerciseProfile.difficulty*(0.5f+Math.abs(currentDifficulty-exerciseProfile.difficulty)));
//topic component
score *= topicOrder.get(exerciseProfile.exerciseTopicName);
score = Math.round(score * 10.0f) / 10.0f;
return score;
} }
// sort the recommendations for successful or resilient learners, otherwise reverse in display
LOG.debug("Sorting recommendations.");
recommendedExercises.stream().sorted(Recommendation.COMPARE_BY_SCORE).collect(Collectors.toList());
LOG.debug("Completed recommendNextExercises with {} recommendations.", recommendedExercises.size());
return recommendedExercises;
}
public static List<ExerciseCompetencyProfile> filterExercisesByTopicsAndDifficulty(
List<ExerciseCompetencyProfile> exerciseCompetencyProfiles,
Map<String, Integer> topicOrder, int currentTopicIndex, String testRepoURL,
float currentDifficulty, float[] unsuccessful, ResultSummary resultSummary) {
LOG.debug("Starting filterExercisesByTopicsAndDifficulty with currentTopicIndex: {}, currentDifficulty: {}, testRepoURL: {}",
currentTopicIndex, currentDifficulty, testRepoURL);
// Filter out all advanced topics in any case
List<ExerciseCompetencyProfile> filteredExercises = exerciseCompetencyProfiles.stream()
.filter(testProfile -> topicOrder.get(testProfile.exerciseTopicName) <= currentTopicIndex)
.collect(Collectors.toList());
LOG.debug("Filtered exercises by topic index. Remaining exercises count: {}", filteredExercises.size());
// Filter by difficulty according to success
if (isFullSuccess(unsuccessful)) {
LOG.debug("Detected full success, filtering exercises with difficulty >= {} and excluding current testRepoURL.", currentDifficulty);
filteredExercises = filteredExercises.stream()
.filter(profile -> profile.difficulty >= currentDifficulty && !testRepoURL.equals(profile.exerciseURL))
.collect(Collectors.toList());
} else {
LOG.debug("Detected partial success, filtering exercises with difficulty <= {}.", currentDifficulty);
filteredExercises = filteredExercises.stream()
.filter(profile -> profile.difficulty <= currentDifficulty)
.collect(Collectors.toList());
}
LOG.debug("Filtered exercises count after difficulty filter: {}", filteredExercises.size());
return filteredExercises;
}
public static boolean isFullSuccess(float[] unsuccessful) {
LOG.debug("Checking for full success. Unsuccessful array: {}", unsuccessful);
for (float value : unsuccessful) {
if (value != 0.0f) {
LOG.debug("Found non-zero value in unsuccessful array: {}. Returning false for full success.", value);
return false;
}
}
LOG.debug("All values in unsuccessful array are zero. Returning true for full success.");
return true;
}
public static float calculateScore(ExerciseCompetencyProfile exerciseProfile, float[] unsuccessful,
Map<String, Integer> topicOrder, float currentDifficulty) {
LOG.debug("Starting calculateScore for exercise: {}, difficulty: {}, currentDifficulty: {}",
exerciseProfile.exerciseName, exerciseProfile.difficulty, currentDifficulty);
float score = 1.0f;
LOG.debug("Initial score set to 1.0");
// Competency profile difference to not fully achieved competencies component
for (int i = 0; i < exerciseProfile.competencyAssessments.length - 1; i++) {
float adjustment = exerciseProfile.competencyAssessments[i] * unsuccessful[i];
score += adjustment;
LOG.debug("Adjusted score by competency index {}: {}, new score: {}", i, adjustment, score);
}
// Difficulty component
float difficultyComponent = exerciseProfile.difficulty * (0.5f + Math.abs(currentDifficulty - exerciseProfile.difficulty));
score = score * difficultyComponent;
LOG.debug("Applied difficulty component: {}, updated score: {}", difficultyComponent, score);
// Topic component
float topicMultiplier = topicOrder.get(exerciseProfile.exerciseTopicName);
score *= topicMultiplier;
LOG.debug("Applied topic multiplier: {}, updated score: {}", topicMultiplier, score);
// Round score
score = Math.round(score * 10.0f) / 10.0f;
LOG.debug("Final rounded score: {}", score);
return score;
}
} }
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment