From 1790d48393da1a55df7578e2081f1c9629262faa Mon Sep 17 00:00:00 2001 From: Woody Folsom Date: Sat, 17 Mar 2012 20:07:58 -0400 Subject: [PATCH] Non-bogus ProfileMatcher. --- src/dk/itu/mario/level/PlayerProfile.java | 2 +- .../mario/level/matcher/ProfileMatcher.java | 162 +++++++++++++++++- 2 files changed, 161 insertions(+), 3 deletions(-) diff --git a/src/dk/itu/mario/level/PlayerProfile.java b/src/dk/itu/mario/level/PlayerProfile.java index cefa4d5..0d18b47 100644 --- a/src/dk/itu/mario/level/PlayerProfile.java +++ b/src/dk/itu/mario/level/PlayerProfile.java @@ -5,7 +5,7 @@ import java.util.Set; public class PlayerProfile { //From Bartle/Yee models of player psychology: achiever, killer, explorer, manipulator - public enum TYPE { RUNNER, SHOOTER, JUMPER, BUMPER} + public enum TYPE { BUMPER, COLLECTOR, RUNNER, SHOOTER, JUMPER} //Dreyfus model of skill acquisition: public enum SKILL_LEVEL { NOVICE, BEGINNER, COMPETENT, PROFICIENT, EXPERT} diff --git a/src/dk/itu/mario/level/matcher/ProfileMatcher.java b/src/dk/itu/mario/level/matcher/ProfileMatcher.java index 6f7a5e2..09b09c8 100644 --- a/src/dk/itu/mario/level/matcher/ProfileMatcher.java +++ b/src/dk/itu/mario/level/matcher/ProfileMatcher.java @@ -1,14 +1,172 @@ 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; -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>(); + + 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."); - return new PlayerProfile(SKILL_LEVEL.BEGINNER, TYPE.JUMPER); + + 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; + } } }