From 952ccdc23bbad084531e3fb426b273cce7c90bdc Mon Sep 17 00:00:00 2001 From: Marshall Date: Sun, 18 Mar 2012 19:01:08 -0400 Subject: [PATCH] - Update the ProfileMatcher mapping. --- .../mario/level/matcher/ProfileMatcher.java | 354 +++++++++++++----- 1 file changed, 251 insertions(+), 103 deletions(-) diff --git a/src/dk/itu/mario/level/matcher/ProfileMatcher.java b/src/dk/itu/mario/level/matcher/ProfileMatcher.java index cd01b0e..648eac0 100644 --- a/src/dk/itu/mario/level/matcher/ProfileMatcher.java +++ b/src/dk/itu/mario/level/matcher/ProfileMatcher.java @@ -1,20 +1,25 @@ package dk.itu.mario.level.matcher; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; +import java.util.Map.Entry; 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; +import dk.itu.mario.level.PlayerProfile.TYPE; public class ProfileMatcher { - public enum SKILL { BUMP, COLLECT, JUMP, RUN, SHOOT, STOMP } - - private static Map> referenceMetrics = new HashMap>(); - + public enum SKILL { + BUMP, COLLECT, JUMP, RUN, SHOOT, STOMP + } + + private static Map> referenceMetrics = new HashMap>(); + static { - Map canonicalVector = new HashMap(); + Map canonicalVector = new HashMap(); canonicalVector.put(SKILL.BUMP, 100); canonicalVector.put(SKILL.COLLECT, 50); canonicalVector.put(SKILL.JUMP, 50); @@ -22,17 +27,17 @@ public class ProfileMatcher { canonicalVector.put(SKILL.SHOOT, 0); canonicalVector.put(SKILL.STOMP, 0); referenceMetrics.put(PlayerProfile.TYPE.BUMPER, canonicalVector); - - canonicalVector = new HashMap(); + + 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); + canonicalVector.put(SKILL.STOMP, 0); referenceMetrics.put(PlayerProfile.TYPE.COLLECTOR, canonicalVector); - - canonicalVector = new HashMap(); + + canonicalVector = new HashMap(); canonicalVector.put(SKILL.BUMP, 50); canonicalVector.put(SKILL.COLLECT, 0); canonicalVector.put(SKILL.JUMP, 100); @@ -40,17 +45,17 @@ public class ProfileMatcher { canonicalVector.put(SKILL.SHOOT, 0); canonicalVector.put(SKILL.STOMP, 0); referenceMetrics.put(PlayerProfile.TYPE.JUMPER, canonicalVector); - - canonicalVector = new HashMap(); + + 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); + canonicalVector.put(SKILL.STOMP, 0); referenceMetrics.put(PlayerProfile.TYPE.RUNNER, canonicalVector); - - canonicalVector = new HashMap(); + + canonicalVector = new HashMap(); canonicalVector.put(SKILL.BUMP, 0); canonicalVector.put(SKILL.COLLECT, 0); canonicalVector.put(SKILL.JUMP, 25); @@ -59,107 +64,250 @@ public class ProfileMatcher { 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; - } + + public static PlayerProfile getMatchingProfile(GamePlay playerMetrics, + DataRecorder detailedInfo) { + System.out + .println("Selecting PlayerProfile based on GamePlay metrics, DataRecorder logs."); + + // GAP comes from jump skill and jumper type. + // ENEMY comes from run skill and runner type and stomp skill. + // HARDER_ENEMY comes from shooting skill and shooting type. + // JUMP comes from jump skill and jumper type. + // BLOCK comes from bump skill and bumper type. + // COIN comes from collect skill and collector type. + // POWERUP comes from rote skill level. + + SKILL_LEVEL skillLevel = null; + TYPE type = null; + HashMap skillVector = new HashMap(); + + int skillHolder; + + // Get bump skills. + // Relevant to: BLOCK. + skillHolder = (int) (100 * playerMetrics.percentageBlocksDestroyed); + skillVector.put(SKILL.BUMP, new Integer(skillHolder)); + + // Get collect skills. + // Relevant to: COIN. + skillHolder = (int) (100 * (((((double) playerMetrics.coinsCollected) / playerMetrics.totalCoins) + playerMetrics.percentageCoinBlocksDestroyed) / 2)); + skillVector.put(SKILL.COLLECT, new Integer(skillHolder)); + + // Get jump skills. + // Relevant to: GAP, JUMP. + // A high percentage of your kills were by stomping and a low percentage + // of your deaths were by plummeting... + + int deaths = playerMetrics.timesOfDeathByArmoredTurtle + + playerMetrics.timesOfDeathByCannonBall + + playerMetrics.timesOfDeathByChompFlower + + (int) playerMetrics.timesOfDeathByFallingIntoGap + + playerMetrics.timesOfDeathByGoomba + + playerMetrics.timesOfDeathByGreenTurtle + + playerMetrics.timesOfDeathByJumpFlower + + playerMetrics.timesOfDeathByArmoredTurtle; + int kills = playerMetrics.ArmoredTurtlesKilled + + playerMetrics.CannonBallKilled + + playerMetrics.ChompFlowersKilled + + playerMetrics.GoombasKilled + + playerMetrics.GreenTurtlesKilled + + playerMetrics.JumpFlowersKilled + + playerMetrics.RedTurtlesKilled; + skillHolder = (int) (100 * (1 + - ((playerMetrics.aimlessJumps / playerMetrics.jumpsNumber)) + + ((kills - playerMetrics.enemyKillByFire - playerMetrics.enemyKillByKickingShell) / (double) kills) + (1 - (playerMetrics.timesOfDeathByFallingIntoGap / deaths))) / 3); + skillVector.put(SKILL.JUMP, new Integer(skillHolder)); + + // Get run skills. + // Relevant to: ENEMY. + skillHolder = (int) (100 * ((((double) playerMetrics.timeSpentRunning) + / playerMetrics.totalTime + (playerMetrics.timesPressedRun / 75 > 1 ? 0 + : 1 - (playerMetrics.timesPressedRun / 75.0))) / 2)); + skillVector.put(SKILL.RUN, new Integer(skillHolder)); + + // Get shoot skills. + skillHolder = (int) (100 * (((((double) playerMetrics.totalTimeFireMode) / playerMetrics.totalTime) + (((double) playerMetrics.enemyKillByFire) / kills)) / 2)); + skillVector.put(SKILL.SHOOT, new Integer(skillHolder)); + + // Get stomp skills. + // ((kills - playerMetrics.enemyKillByFire - + // playerMetrics.enemyKillByKickingShell) / (double) kills) + // playerMetrics.aimlessJumps. + skillHolder = (int) (100 * ((kills - playerMetrics.enemyKillByFire - playerMetrics.enemyKillByKickingShell) / (double) kills)); + skillVector.put(SKILL.STOMP, new Integer(skillHolder)); + + // Determine type. + skillHolder = skillVector.get(SKILL.BUMP).intValue(); + type = TYPE.BUMPER; + + if (skillHolder < skillVector.get(SKILL.COLLECT).intValue()) { + skillHolder = skillVector.get(SKILL.COLLECT).intValue(); + type = TYPE.COLLECTOR; } - - 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 { + + if (skillHolder < skillVector.get(SKILL.JUMP).intValue()) { + skillHolder = skillVector.get(SKILL.JUMP).intValue(); + type = TYPE.JUMPER; + } + + if (skillHolder < skillVector.get(SKILL.RUN).intValue()) { + skillHolder = skillVector.get(SKILL.RUN).intValue(); + type = TYPE.RUNNER; + } + + if (skillHolder < skillVector.get(SKILL.SHOOT).intValue()) { + skillHolder = skillVector.get(SKILL.SHOOT).intValue(); + type = TYPE.SHOOTER; + } + + if (skillHolder < skillVector.get(SKILL.STOMP).intValue()) { + type = TYPE.JUMPER; + } + + // Determine rote level. + skillHolder = 0; + for (Iterator> i = skillVector.entrySet() + .iterator(); i.hasNext();) { + skillHolder += i.next().getValue().intValue(); + } + + skillHolder /= skillVector.size(); + + if (skillHolder >= 80) { 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, playerProfileVector); + + else if (skillHolder >= 60) { + skillLevel = SKILL_LEVEL.PROFICIENT; + } + + else if (skillHolder >= 40) { + skillLevel = SKILL_LEVEL.COMPETENT; + } + + else if (skillHolder >= 20) { + skillLevel = SKILL_LEVEL.BEGINNER; + } + + else { + skillLevel = SKILL_LEVEL.NOVICE; + } + + return new PlayerProfile(skillLevel, type, skillVector); + + // None of this is wrong necessarily. I just want to try some other + // stuff. + // 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, + // playerProfileVector); } - - private static int getKeyScore(Map playerProfileVector, PlayerProfile.TYPE playerProfileType) { + + private static int getKeyScore(Map playerProfileVector, + PlayerProfile.TYPE playerProfileType) { switch (playerProfileType) { - case BUMPER : + case BUMPER: return playerProfileVector.get(SKILL.BUMP); - case COLLECTOR : + case COLLECTOR: return playerProfileVector.get(SKILL.COLLECT); - case JUMPER : + case JUMPER: return playerProfileVector.get(SKILL.JUMP); - case RUNNER : + case RUNNER: return playerProfileVector.get(SKILL.RUN); - case SHOOTER : + case SHOOTER: return playerProfileVector.get(SKILL.SHOOT); - default : + default: return 0; } } - + private static int clampToPercentRange(int value) { if (value < 0) { return 0;