Fixed NPE when the default player.txt does not exist. Fixed bug when requesting PowerUp component of invalid length. Change default lives to 1.
This commit is contained in:
12
README.TXT
Normal file
12
README.TXT
Normal file
@@ -0,0 +1,12 @@
|
||||
Adaptive Mario Instructions
|
||||
---------------------------
|
||||
|
||||
Unzip the attached archive 'CS8803_P3.zip' and change to the new directory.
|
||||
|
||||
To build Adaptive Mario: run 'ant clean' then 'ant' in this directory.
|
||||
|
||||
To run Adaptive Mario: change to the 'dist' directory, then run java -jar CS8803_P3.jar
|
||||
|
||||
For full instructions, see writeup/CS8803_P3.PDF.
|
||||
|
||||
For assistance, please contact Woody Folsom <woody.folsom@gatech.edu> or Marshall Gillson <mgillson1@gmail.com>.
|
||||
@@ -9,6 +9,7 @@ import java.io.Serializable;
|
||||
public class GamePlay implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
public static final GamePlay DEFAULT_PROFILE = new GamePlay();
|
||||
|
||||
public int completionTime; // counts only the current run on the level,
|
||||
// excluding death games
|
||||
@@ -96,6 +97,7 @@ public class GamePlay implements Serializable {
|
||||
// TODO Auto-generated catch block
|
||||
//e.printStackTrace();
|
||||
System.out.println("Unable to read from GamePlay file: " + fileName + ", initializing a new GamePlay instance.");
|
||||
gp = GamePlay.DEFAULT_PROFILE;
|
||||
}
|
||||
return gp;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ public class MarioComponent extends JComponent implements Runnable,
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
//while (true) {
|
||||
graphicsConfiguration = getGraphicsConfiguration();
|
||||
|
||||
Art.init(graphicsConfiguration, sound);
|
||||
@@ -191,7 +191,7 @@ public class MarioComponent extends JComponent implements Runnable,
|
||||
Mario.fire = false;
|
||||
Mario.large = false;
|
||||
Mario.coins = 0;
|
||||
Mario.lives = 3;
|
||||
Mario.lives = 1;
|
||||
|
||||
randomLevel.init();
|
||||
randomLevel.setSound(sound);
|
||||
@@ -262,6 +262,7 @@ public class MarioComponent extends JComponent implements Runnable,
|
||||
}
|
||||
|
||||
Art.stopMusic();
|
||||
//}
|
||||
}
|
||||
|
||||
private void drawString(Graphics g, String text, int x, int y, int c) {
|
||||
|
||||
@@ -1137,46 +1137,52 @@ public class PCGLevel extends Level {
|
||||
LevelComponent.TYPE lctype = lcomp.getType();
|
||||
System.out.println("Building for: " + lcomp);
|
||||
while (length < Math.min(width - 64, lcomp.getEnd())) {
|
||||
int lcLength;
|
||||
switch (lctype) {
|
||||
case FLAT_LO:
|
||||
case FLAT_HI:
|
||||
length += buildStraight(length, lcomp.getEnd(), true);
|
||||
lcLength = buildStraight(length, lcomp.getEnd(), true);
|
||||
break;
|
||||
case PIPE_JUMP:
|
||||
length += buildPipeJump(length, width - 64 - length);
|
||||
lcLength = buildPipeJump(length, width - 64 - length);
|
||||
break;
|
||||
case PLATFORM_JUMP:
|
||||
length += buildPlatformJump(length, width - 64 - length);
|
||||
lcLength = buildPlatformJump(length, width - 64 - length);
|
||||
break;
|
||||
case MAZE:
|
||||
length += buildMaze(length, width - 64 - length);
|
||||
lcLength = buildMaze(length, width - 64 - length);
|
||||
break;
|
||||
case BLOCKS:
|
||||
length += buildMaze(length, width - 64 - length);
|
||||
lcLength = buildMaze(length, width - 64 - length);
|
||||
break;
|
||||
case BOWLING_ALLEY :
|
||||
length += buildBowlingAlley(length, width - 64 - length);
|
||||
lcLength = buildBowlingAlley(length, width - 64 - length);
|
||||
break;
|
||||
case CANNON_LINE :
|
||||
length += buildCannonLine(length, width - 64 - length);
|
||||
lcLength = buildCannonLine(length, width - 64 - length);
|
||||
break;
|
||||
case COIN_DIVE :
|
||||
length += buildCoinDive(length, width - 64 - length);
|
||||
lcLength = buildCoinDive(length, width - 64 - length);
|
||||
break;
|
||||
case LEMMING_TRAP :
|
||||
length += buildLemmingTrap(length, width - 64 - length);
|
||||
lcLength = buildLemmingTrap(length, width - 64 - length);
|
||||
break;
|
||||
case POWER_UP :
|
||||
length += buildFreebie(length, width - 64 - length);
|
||||
lcLength = buildFreebie(length, width - 64 - length);
|
||||
break;
|
||||
case SINGLE_PIT :
|
||||
length += buildSinglePit(length, width - 64 - length);
|
||||
lcLength = buildSinglePit(length, width - 64 - length);
|
||||
break;
|
||||
default:
|
||||
lcLength = 0;
|
||||
System.out
|
||||
.println("Cannot build level segment for unrecognized LevelComponent type: "
|
||||
+ type);
|
||||
}
|
||||
if (lcLength == 0) {
|
||||
lcLength = buildStraight(length, lcomp.getEnd(), true);
|
||||
}
|
||||
length += lcLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1247,8 +1253,7 @@ public class PCGLevel extends Level {
|
||||
playerMetrics, dataRecorder);
|
||||
System.out.println("PlayerProfile: " + profile);
|
||||
|
||||
LevelArchetype archetype = ArchetypeMatcher.getMatchingArchetype(
|
||||
playerMetrics, dataRecorder);
|
||||
LevelArchetype archetype = ArchetypeMatcher.getMatchingArchetype(profile);
|
||||
System.out.println("LevelArchetype: " + archetype);
|
||||
|
||||
System.out.println("Creating level grammar");
|
||||
|
||||
@@ -7,7 +7,11 @@ import dk.itu.mario.MarioInterface.LevelGenerator;
|
||||
import dk.itu.mario.MarioInterface.LevelInterface;
|
||||
import dk.itu.mario.engine.DataRecorder;
|
||||
import dk.itu.mario.level.Level;
|
||||
import dk.itu.mario.level.LevelArchetype;
|
||||
import dk.itu.mario.level.PCGLevel;
|
||||
import dk.itu.mario.level.PlayerProfile;
|
||||
import dk.itu.mario.level.matcher.ArchetypeMatcher;
|
||||
import dk.itu.mario.level.matcher.ProfileMatcher;
|
||||
|
||||
public class PCGLevelGenerator implements
|
||||
LevelGenerator {
|
||||
@@ -20,7 +24,21 @@ public class PCGLevelGenerator implements
|
||||
@Override
|
||||
public int generateLevelType(GamePlay playerMetrics, DataRecorder dataRecorder) {
|
||||
System.out.println("Generating level type based on playerMetrics, dataRecorder: TYPE_OVERGROUND");
|
||||
return Level.TYPE_OVERGROUND;
|
||||
PlayerProfile profile = ProfileMatcher.getMatchingProfile(
|
||||
playerMetrics, dataRecorder);
|
||||
System.out.println("PlayerProfile: " + profile);
|
||||
|
||||
LevelArchetype archetype = ArchetypeMatcher.getMatchingArchetype(profile);
|
||||
switch (archetype.getType()) {
|
||||
case CASTLE :
|
||||
return LevelInterface.TYPE_CASTLE;
|
||||
case OVERGROUND :
|
||||
return LevelInterface.TYPE_OVERGROUND;
|
||||
case UNDERGROUND :
|
||||
return LevelInterface.TYPE_UNDERGROUND;
|
||||
default :
|
||||
return LevelInterface.TYPE_OVERGROUND;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,13 +1,48 @@
|
||||
package dk.itu.mario.level.matcher;
|
||||
|
||||
import dk.itu.mario.MarioInterface.GamePlay;
|
||||
import dk.itu.mario.engine.DataRecorder;
|
||||
import dk.itu.mario.level.LevelArchetype;
|
||||
import dk.itu.mario.level.LevelArchetype.TYPE;
|
||||
import dk.itu.mario.level.PlayerProfile;
|
||||
|
||||
public class ArchetypeMatcher {
|
||||
public static LevelArchetype getMatchingArchetype(GamePlay playerMetrics, DataRecorder detailedInfo) {
|
||||
System.out.println("Selecting PlayerProfile based on GamePlay metrics, DataRecorder logs.");
|
||||
return new LevelArchetype(TYPE.OVERGROUND,1);
|
||||
public static LevelArchetype getMatchingArchetype(
|
||||
PlayerProfile playerProfile) {
|
||||
System.out
|
||||
.println("Selecting PlayerProfile based on GamePlay metrics, DataRecorder logs.");
|
||||
|
||||
TYPE levelType;
|
||||
int primarySkill;
|
||||
|
||||
switch (playerProfile.getType()) {
|
||||
case BUMPER:
|
||||
levelType = TYPE.OVERGROUND;
|
||||
primarySkill = (int) Math
|
||||
.round(playerProfile.getBumpSkill() / 10.0);
|
||||
break;
|
||||
case COLLECTOR:
|
||||
levelType = TYPE.UNDERGROUND;
|
||||
primarySkill = (int) Math
|
||||
.round(playerProfile.getCollectSkill() / 10.0);
|
||||
break;
|
||||
case JUMPER:
|
||||
levelType = TYPE.CASTLE;
|
||||
primarySkill = (int) Math
|
||||
.round(playerProfile.getJumpSkill() / 10.0);
|
||||
break;
|
||||
case RUNNER:
|
||||
levelType = TYPE.OVERGROUND;
|
||||
primarySkill = (int) Math.round(playerProfile.getRunSkill() / 10.0);
|
||||
break;
|
||||
case SHOOTER:
|
||||
levelType = TYPE.UNDERGROUND;
|
||||
primarySkill = (int) Math
|
||||
.round(playerProfile.getShootSkill() / 10.0);
|
||||
break;
|
||||
default:
|
||||
levelType = TYPE.CASTLE;
|
||||
primarySkill = 1;
|
||||
}
|
||||
|
||||
return new LevelArchetype(levelType, Math.max(primarySkill,1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ 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 }
|
||||
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>>();
|
||||
|
||||
@@ -60,8 +62,10 @@ public class ProfileMatcher {
|
||||
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.");
|
||||
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;
|
||||
@@ -70,6 +74,14 @@ public class ProfileMatcher {
|
||||
int shooterScore = 0;
|
||||
int stomperScore = 0;
|
||||
|
||||
if (playerMetrics == GamePlay.DEFAULT_PROFILE) {
|
||||
bumperScore = 50;
|
||||
collectorScore = 50;
|
||||
jumperScore = 50;
|
||||
runnerScore = 50;
|
||||
shooterScore = 50;
|
||||
stomperScore = 50;
|
||||
} else {
|
||||
bumperScore += playerMetrics.percentageBlocksDestroyed * 20;
|
||||
bumperScore += playerMetrics.percentageCoinBlocksDestroyed * 20;
|
||||
bumperScore += playerMetrics.percentageEmptyBlockesDestroyed * 20;
|
||||
@@ -80,12 +92,17 @@ public class ProfileMatcher {
|
||||
|
||||
jumperScore = Math.min(100, playerMetrics.jumpsNumber);
|
||||
|
||||
runnerScore = playerMetrics.timeRunningRight / playerMetrics.totalTime;
|
||||
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));
|
||||
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);
|
||||
@@ -111,10 +128,12 @@ public class ProfileMatcher {
|
||||
PlayerProfile.TYPE closestMatch = PlayerProfile.TYPE.RUNNER;
|
||||
|
||||
for (PlayerProfile.TYPE type : PlayerProfile.TYPE.values()) {
|
||||
Map<SKILL,Integer> canonicalVector = ProfileMatcher.referenceMetrics.get(type);
|
||||
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);
|
||||
distance += Math.pow(canonicalVector.get(skill)
|
||||
- playerProfileVector.get(skill), 2);
|
||||
}
|
||||
if (distance < minDist) {
|
||||
minDist = distance;
|
||||
@@ -138,12 +157,15 @@ public class ProfileMatcher {
|
||||
skillLevel = SKILL_LEVEL.EXPERT;
|
||||
}
|
||||
|
||||
System.out.println("Skill level for this " + closestMatch + " is " + skillLevel + " (based on a score of " + keyScore + " out of 100.)");
|
||||
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) {
|
||||
private static int getKeyScore(Map<SKILL, Integer> playerProfileVector,
|
||||
PlayerProfile.TYPE playerProfileType) {
|
||||
switch (playerProfileType) {
|
||||
case BUMPER:
|
||||
return playerProfileVector.get(SKILL.BUMP);
|
||||
|
||||
Reference in New Issue
Block a user