- Update the ProfileMatcher mapping.

This commit is contained in:
Marshall
2012-03-18 19:01:08 -04:00
parent a6f467d724
commit 952ccdc23b

View File

@@ -1,20 +1,25 @@
package dk.itu.mario.level.matcher; package dk.itu.mario.level.matcher;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import dk.itu.mario.MarioInterface.GamePlay; import dk.itu.mario.MarioInterface.GamePlay;
import dk.itu.mario.engine.DataRecorder; import dk.itu.mario.engine.DataRecorder;
import dk.itu.mario.level.PlayerProfile; import dk.itu.mario.level.PlayerProfile;
import dk.itu.mario.level.PlayerProfile.SKILL_LEVEL; import dk.itu.mario.level.PlayerProfile.SKILL_LEVEL;
import dk.itu.mario.level.PlayerProfile.TYPE;
public class ProfileMatcher { public class ProfileMatcher {
public enum SKILL { BUMP, COLLECT, JUMP, RUN, SHOOT, STOMP } public enum SKILL {
BUMP, COLLECT, JUMP, RUN, SHOOT, STOMP
}
private static Map<PlayerProfile.TYPE, Map<SKILL,Integer>> referenceMetrics = new HashMap<PlayerProfile.TYPE, Map<SKILL,Integer>>(); private static Map<PlayerProfile.TYPE, Map<SKILL, Integer>> referenceMetrics = new HashMap<PlayerProfile.TYPE, Map<SKILL, Integer>>();
static { static {
Map<SKILL,Integer> canonicalVector = new HashMap<SKILL,Integer>(); Map<SKILL, Integer> canonicalVector = new HashMap<SKILL, Integer>();
canonicalVector.put(SKILL.BUMP, 100); canonicalVector.put(SKILL.BUMP, 100);
canonicalVector.put(SKILL.COLLECT, 50); canonicalVector.put(SKILL.COLLECT, 50);
canonicalVector.put(SKILL.JUMP, 50); canonicalVector.put(SKILL.JUMP, 50);
@@ -23,7 +28,7 @@ public class ProfileMatcher {
canonicalVector.put(SKILL.STOMP, 0); canonicalVector.put(SKILL.STOMP, 0);
referenceMetrics.put(PlayerProfile.TYPE.BUMPER, canonicalVector); referenceMetrics.put(PlayerProfile.TYPE.BUMPER, canonicalVector);
canonicalVector = new HashMap<SKILL,Integer>(); canonicalVector = new HashMap<SKILL, Integer>();
canonicalVector.put(SKILL.BUMP, 50); canonicalVector.put(SKILL.BUMP, 50);
canonicalVector.put(SKILL.COLLECT, 100); canonicalVector.put(SKILL.COLLECT, 100);
canonicalVector.put(SKILL.JUMP, 50); canonicalVector.put(SKILL.JUMP, 50);
@@ -32,7 +37,7 @@ public class ProfileMatcher {
canonicalVector.put(SKILL.STOMP, 0); canonicalVector.put(SKILL.STOMP, 0);
referenceMetrics.put(PlayerProfile.TYPE.COLLECTOR, canonicalVector); referenceMetrics.put(PlayerProfile.TYPE.COLLECTOR, canonicalVector);
canonicalVector = new HashMap<SKILL,Integer>(); canonicalVector = new HashMap<SKILL, Integer>();
canonicalVector.put(SKILL.BUMP, 50); canonicalVector.put(SKILL.BUMP, 50);
canonicalVector.put(SKILL.COLLECT, 0); canonicalVector.put(SKILL.COLLECT, 0);
canonicalVector.put(SKILL.JUMP, 100); canonicalVector.put(SKILL.JUMP, 100);
@@ -41,7 +46,7 @@ public class ProfileMatcher {
canonicalVector.put(SKILL.STOMP, 0); canonicalVector.put(SKILL.STOMP, 0);
referenceMetrics.put(PlayerProfile.TYPE.JUMPER, canonicalVector); referenceMetrics.put(PlayerProfile.TYPE.JUMPER, canonicalVector);
canonicalVector = new HashMap<SKILL,Integer>(); canonicalVector = new HashMap<SKILL, Integer>();
canonicalVector.put(SKILL.BUMP, 0); canonicalVector.put(SKILL.BUMP, 0);
canonicalVector.put(SKILL.COLLECT, 0); canonicalVector.put(SKILL.COLLECT, 0);
canonicalVector.put(SKILL.JUMP, 25); canonicalVector.put(SKILL.JUMP, 25);
@@ -50,7 +55,7 @@ public class ProfileMatcher {
canonicalVector.put(SKILL.STOMP, 0); canonicalVector.put(SKILL.STOMP, 0);
referenceMetrics.put(PlayerProfile.TYPE.RUNNER, canonicalVector); referenceMetrics.put(PlayerProfile.TYPE.RUNNER, canonicalVector);
canonicalVector = new HashMap<SKILL,Integer>(); canonicalVector = new HashMap<SKILL, Integer>();
canonicalVector.put(SKILL.BUMP, 0); canonicalVector.put(SKILL.BUMP, 0);
canonicalVector.put(SKILL.COLLECT, 0); canonicalVector.put(SKILL.COLLECT, 0);
canonicalVector.put(SKILL.JUMP, 25); canonicalVector.put(SKILL.JUMP, 25);
@@ -60,102 +65,245 @@ public class ProfileMatcher {
referenceMetrics.put(PlayerProfile.TYPE.SHOOTER, canonicalVector); referenceMetrics.put(PlayerProfile.TYPE.SHOOTER, canonicalVector);
} }
public static PlayerProfile getMatchingProfile(GamePlay playerMetrics, DataRecorder detailedInfo) { public static PlayerProfile getMatchingProfile(GamePlay playerMetrics,
System.out.println("Selecting PlayerProfile based on GamePlay metrics, DataRecorder logs."); DataRecorder detailedInfo) {
System.out
.println("Selecting PlayerProfile based on GamePlay metrics, DataRecorder logs.");
int bumperScore = 0; // GAP comes from jump skill and jumper type.
int collectorScore = 0; // ENEMY comes from run skill and runner type and stomp skill.
int jumperScore = 0; // HARDER_ENEMY comes from shooting skill and shooting type.
int runnerScore = 0; // JUMP comes from jump skill and jumper type.
int shooterScore = 0; // BLOCK comes from bump skill and bumper type.
int stomperScore = 0; // COIN comes from collect skill and collector type.
// POWERUP comes from rote skill level.
bumperScore += playerMetrics.percentageBlocksDestroyed * 20; SKILL_LEVEL skillLevel = null;
bumperScore += playerMetrics.percentageCoinBlocksDestroyed * 20; TYPE type = null;
bumperScore += playerMetrics.percentageEmptyBlockesDestroyed * 20; HashMap<SKILL, Integer> skillVector = new HashMap<SKILL, Integer>();
bumperScore += playerMetrics.percentagePowerBlockDestroyed * 20;
bumperScore += 4 * Math.min(5, playerMetrics.kickedShells);
collectorScore += playerMetrics.coinsCollected / 35.0; int skillHolder;
jumperScore = Math.min(100, playerMetrics.jumpsNumber); // Get bump skills.
// Relevant to: BLOCK.
skillHolder = (int) (100 * playerMetrics.percentageBlocksDestroyed);
skillVector.put(SKILL.BUMP, new Integer(skillHolder));
runnerScore = playerMetrics.timeRunningRight / playerMetrics.totalTime; // Get collect skills.
// Relevant to: COIN.
skillHolder = (int) (100 * (((((double) playerMetrics.coinsCollected) / playerMetrics.totalCoins) + playerMetrics.percentageCoinBlocksDestroyed) / 2));
skillVector.put(SKILL.COLLECT, new Integer(skillHolder));
shooterScore += 10 * Math.min(10, playerMetrics.enemyKillByFire / 10.0); // 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...
stomperScore += Math.min(100, 2 * (playerMetrics.GoombasKilled + playerMetrics.GreenTurtlesKilled + playerMetrics.RedTurtlesKilled)); 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));
clampToPercentRange(bumperScore); // Get run skills.
clampToPercentRange(collectorScore); // Relevant to: ENEMY.
clampToPercentRange(jumperScore); skillHolder = (int) (100 * ((((double) playerMetrics.timeSpentRunning)
clampToPercentRange(runnerScore); / playerMetrics.totalTime + (playerMetrics.timesPressedRun / 75 > 1 ? 0
clampToPercentRange(shooterScore); : 1 - (playerMetrics.timesPressedRun / 75.0))) / 2));
clampToPercentRange(stomperScore); skillVector.put(SKILL.RUN, new Integer(skillHolder));
System.out.println("bumperScore: " + bumperScore); // Get shoot skills.
System.out.println("collectorScore: " + collectorScore); skillHolder = (int) (100 * (((((double) playerMetrics.totalTimeFireMode) / playerMetrics.totalTime) + (((double) playerMetrics.enemyKillByFire) / kills)) / 2));
System.out.println("jumperScore: " + jumperScore); skillVector.put(SKILL.SHOOT, new Integer(skillHolder));
System.out.println("shooterScore: " + shooterScore);
System.out.println("stomperScore: " + stomperScore);
Map<SKILL,Integer> playerProfileVector = new HashMap<SKILL,Integer>(); // Get stomp skills.
playerProfileVector.put(SKILL.BUMP, bumperScore); // ((kills - playerMetrics.enemyKillByFire -
playerProfileVector.put(SKILL.COLLECT, collectorScore); // playerMetrics.enemyKillByKickingShell) / (double) kills)
playerProfileVector.put(SKILL.JUMP, jumperScore); // playerMetrics.aimlessJumps.
playerProfileVector.put(SKILL.RUN, runnerScore); skillHolder = (int) (100 * ((kills - playerMetrics.enemyKillByFire - playerMetrics.enemyKillByKickingShell) / (double) kills));
playerProfileVector.put(SKILL.SHOOT, shooterScore); skillVector.put(SKILL.STOMP, new Integer(skillHolder));
playerProfileVector.put(SKILL.STOMP, stomperScore);
double minDist = Double.MAX_VALUE; // Determine type.
PlayerProfile.TYPE closestMatch = PlayerProfile.TYPE.RUNNER; skillHolder = skillVector.get(SKILL.BUMP).intValue();
type = TYPE.BUMPER;
for (PlayerProfile.TYPE type : PlayerProfile.TYPE.values()) { if (skillHolder < skillVector.get(SKILL.COLLECT).intValue()) {
Map<SKILL,Integer> canonicalVector = ProfileMatcher.referenceMetrics.get(type); skillHolder = skillVector.get(SKILL.COLLECT).intValue();
double distance = 0.0; type = TYPE.COLLECTOR;
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; if (skillHolder < skillVector.get(SKILL.JUMP).intValue()) {
skillHolder = skillVector.get(SKILL.JUMP).intValue();
type = TYPE.JUMPER;
}
int keyScore = getKeyScore(playerProfileVector, closestMatch); if (skillHolder < skillVector.get(SKILL.RUN).intValue()) {
skillHolder = skillVector.get(SKILL.RUN).intValue();
type = TYPE.RUNNER;
}
if (keyScore <= 20) { if (skillHolder < skillVector.get(SKILL.SHOOT).intValue()) {
skillLevel = SKILL_LEVEL.NOVICE; skillHolder = skillVector.get(SKILL.SHOOT).intValue();
} else if (keyScore <= 40) { type = TYPE.SHOOTER;
skillLevel = SKILL_LEVEL.BEGINNER; }
} else if (keyScore <= 60) {
skillLevel = SKILL_LEVEL.COMPETENT; if (skillHolder < skillVector.get(SKILL.STOMP).intValue()) {
} else if (keyScore <= 80) { type = TYPE.JUMPER;
skillLevel = SKILL_LEVEL.PROFICIENT; }
} else {
// Determine rote level.
skillHolder = 0;
for (Iterator<Entry<SKILL, Integer>> i = skillVector.entrySet()
.iterator(); i.hasNext();) {
skillHolder += i.next().getValue().intValue();
}
skillHolder /= skillVector.size();
if (skillHolder >= 80) {
skillLevel = SKILL_LEVEL.EXPERT; skillLevel = SKILL_LEVEL.EXPERT;
} }
System.out.println("Skill level for this " + closestMatch + " is " + skillLevel + " (based on a score of " + keyScore + " out of 100.)"); else if (skillHolder >= 60) {
skillLevel = SKILL_LEVEL.PROFICIENT;
return new PlayerProfile(skillLevel, closestMatch, playerProfileVector);
} }
private static int getKeyScore(Map<SKILL, Integer> playerProfileVector, PlayerProfile.TYPE playerProfileType) { 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<SKILL, Integer> playerProfileVector = new HashMap<SKILL,
// Integer>();
// 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<SKILL, Integer> 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<SKILL, Integer> playerProfileVector,
PlayerProfile.TYPE playerProfileType) {
switch (playerProfileType) { switch (playerProfileType) {
case BUMPER : case BUMPER:
return playerProfileVector.get(SKILL.BUMP); return playerProfileVector.get(SKILL.BUMP);
case COLLECTOR : case COLLECTOR:
return playerProfileVector.get(SKILL.COLLECT); return playerProfileVector.get(SKILL.COLLECT);
case JUMPER : case JUMPER:
return playerProfileVector.get(SKILL.JUMP); return playerProfileVector.get(SKILL.JUMP);
case RUNNER : case RUNNER:
return playerProfileVector.get(SKILL.RUN); return playerProfileVector.get(SKILL.RUN);
case SHOOTER : case SHOOTER:
return playerProfileVector.get(SKILL.SHOOT); return playerProfileVector.get(SKILL.SHOOT);
default : default:
return 0; return 0;
} }
} }