package dk.itu.mario.level.matcher; import java.util.HashMap; import java.util.Map; import dk.itu.mario.MarioInterface.GamePlay; import dk.itu.mario.engine.DataRecorder; import dk.itu.mario.level.PlayerProfile; import dk.itu.mario.level.PlayerProfile.SKILL_LEVEL; public class ProfileMatcher { public enum SKILL { BUMP, COLLECT, JUMP, RUN, SHOOT, STOMP } private static Map> referenceMetrics = new HashMap>(); static { Map canonicalVector = new HashMap(); canonicalVector.put(SKILL.BUMP, 100); canonicalVector.put(SKILL.COLLECT, 50); canonicalVector.put(SKILL.JUMP, 50); canonicalVector.put(SKILL.RUN, 0); canonicalVector.put(SKILL.SHOOT, 0); canonicalVector.put(SKILL.STOMP, 0); referenceMetrics.put(PlayerProfile.TYPE.BUMPER, canonicalVector); canonicalVector = new HashMap(); canonicalVector.put(SKILL.BUMP, 50); canonicalVector.put(SKILL.COLLECT, 100); canonicalVector.put(SKILL.JUMP, 50); canonicalVector.put(SKILL.RUN, 0); canonicalVector.put(SKILL.SHOOT, 0); canonicalVector.put(SKILL.STOMP, 0); referenceMetrics.put(PlayerProfile.TYPE.COLLECTOR, canonicalVector); canonicalVector = new HashMap(); canonicalVector.put(SKILL.BUMP, 50); canonicalVector.put(SKILL.COLLECT, 0); canonicalVector.put(SKILL.JUMP, 100); canonicalVector.put(SKILL.RUN, 25); canonicalVector.put(SKILL.SHOOT, 0); canonicalVector.put(SKILL.STOMP, 0); referenceMetrics.put(PlayerProfile.TYPE.JUMPER, canonicalVector); canonicalVector = new HashMap(); canonicalVector.put(SKILL.BUMP, 0); canonicalVector.put(SKILL.COLLECT, 0); canonicalVector.put(SKILL.JUMP, 25); canonicalVector.put(SKILL.RUN, 100); canonicalVector.put(SKILL.SHOOT, 25); canonicalVector.put(SKILL.STOMP, 0); referenceMetrics.put(PlayerProfile.TYPE.RUNNER, canonicalVector); canonicalVector = new HashMap(); canonicalVector.put(SKILL.BUMP, 0); canonicalVector.put(SKILL.COLLECT, 0); canonicalVector.put(SKILL.JUMP, 25); canonicalVector.put(SKILL.RUN, 50); canonicalVector.put(SKILL.SHOOT, 100); canonicalVector.put(SKILL.STOMP, 0); referenceMetrics.put(PlayerProfile.TYPE.SHOOTER, canonicalVector); } public static PlayerProfile getMatchingProfile(GamePlay playerMetrics, DataRecorder detailedInfo) { System.out.println("Selecting PlayerProfile based on GamePlay metrics, DataRecorder logs."); int bumperScore = 0; int collectorScore = 0; int jumperScore = 0; int runnerScore = 0; int shooterScore = 0; int stomperScore = 0; bumperScore += playerMetrics.percentageBlocksDestroyed * 20; bumperScore += playerMetrics.percentageCoinBlocksDestroyed * 20; bumperScore += playerMetrics.percentageEmptyBlockesDestroyed * 20; bumperScore += playerMetrics.percentagePowerBlockDestroyed * 20; bumperScore += 4 * Math.min(5, playerMetrics.kickedShells); collectorScore += playerMetrics.coinsCollected / 35.0; jumperScore = Math.min(100, playerMetrics.jumpsNumber); runnerScore = playerMetrics.timeRunningRight / playerMetrics.totalTime; shooterScore += 10 * Math.min(10, playerMetrics.enemyKillByFire / 10.0); stomperScore += Math.min(100, 2 * (playerMetrics.GoombasKilled + playerMetrics.GreenTurtlesKilled + playerMetrics.RedTurtlesKilled)); clampToPercentRange(bumperScore); clampToPercentRange(collectorScore); clampToPercentRange(jumperScore); clampToPercentRange(runnerScore); clampToPercentRange(shooterScore); clampToPercentRange(stomperScore); System.out.println("bumperScore: " + bumperScore); System.out.println("collectorScore: " + collectorScore); System.out.println("jumperScore: " + jumperScore); System.out.println("shooterScore: " + shooterScore); System.out.println("stomperScore: " + stomperScore); Map playerProfileVector = new HashMap(); playerProfileVector.put(SKILL.BUMP, bumperScore); playerProfileVector.put(SKILL.COLLECT, collectorScore); playerProfileVector.put(SKILL.JUMP, jumperScore); playerProfileVector.put(SKILL.RUN, runnerScore); playerProfileVector.put(SKILL.SHOOT, shooterScore); playerProfileVector.put(SKILL.STOMP, stomperScore); double minDist = Double.MAX_VALUE; PlayerProfile.TYPE closestMatch = PlayerProfile.TYPE.RUNNER; for (PlayerProfile.TYPE type : PlayerProfile.TYPE.values()) { Map canonicalVector = ProfileMatcher.referenceMetrics.get(type); double distance = 0.0; for (SKILL skill : SKILL.values()) { distance += Math.pow(canonicalVector.get(skill) - playerProfileVector.get(skill), 2); } if (distance < minDist) { minDist = distance; closestMatch = type; } } SKILL_LEVEL skillLevel; int keyScore = getKeyScore(playerProfileVector, closestMatch); if (keyScore <= 20) { skillLevel = SKILL_LEVEL.NOVICE; } else if (keyScore <= 40) { skillLevel = SKILL_LEVEL.BEGINNER; } else if (keyScore <= 60) { skillLevel = SKILL_LEVEL.COMPETENT; } else if (keyScore <= 80) { skillLevel = SKILL_LEVEL.PROFICIENT; } else { skillLevel = SKILL_LEVEL.EXPERT; } System.out.println("Skill level for this " + closestMatch + " is " + skillLevel + " (based on a score of " + keyScore + " out of 100.)"); return new PlayerProfile(skillLevel, closestMatch); } private static int getKeyScore(Map playerProfileVector, PlayerProfile.TYPE playerProfileType) { switch (playerProfileType) { case BUMPER : return playerProfileVector.get(SKILL.BUMP); case COLLECTOR : return playerProfileVector.get(SKILL.COLLECT); case JUMPER : return playerProfileVector.get(SKILL.JUMP); case RUNNER : return playerProfileVector.get(SKILL.RUN); case SHOOTER : return playerProfileVector.get(SKILL.SHOOT); default : return 0; } } private static int clampToPercentRange(int value) { if (value < 0) { return 0; } else if (value > 100) { return 100; } else { return value; } } }