Merge branch 'master' of woodyfolsom.net:/opt/git/cs8803p3
Conflicts: src/dk/itu/mario/level/matcher/ProfileMatcher.java
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>.
|
||||||
@@ -15,3 +15,19 @@ rule "BeginnerJumper"
|
|||||||
System.out.println("PlayerProfile indicates Beginner (or better) Jumper. Pipe challenge enabled!"); // consequence
|
System.out.println("PlayerProfile indicates Beginner (or better) Jumper. Pipe challenge enabled!"); // consequence
|
||||||
playerProfile.setEnabled(LevelComponent.TYPE.PIPE_JUMP);
|
playerProfile.setEnabled(LevelComponent.TYPE.PIPE_JUMP);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
rule "NoviceRunner"
|
||||||
|
when
|
||||||
|
playerProfile : PlayerProfile( runSkill <= 20 ) // condition
|
||||||
|
then
|
||||||
|
System.out.println("PlayerProfile indicates NoviceRunner. Disabling Maze challenge."); // consequence
|
||||||
|
playerProfile.setDisabled(LevelComponent.TYPE.MAZE);
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "BeginnerRunner"
|
||||||
|
when
|
||||||
|
playerProfile : PlayerProfile( runSkill > 20 ) // condition
|
||||||
|
then
|
||||||
|
System.out.println("PlayerProfile indicates Beginner (or better) Runner. Maze challenge enabled!"); // consequence
|
||||||
|
playerProfile.setEnabled(LevelComponent.TYPE.MAZE);
|
||||||
|
end
|
||||||
@@ -9,6 +9,7 @@ import java.io.Serializable;
|
|||||||
public class GamePlay implements Serializable {
|
public class GamePlay implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
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,
|
public int completionTime; // counts only the current run on the level,
|
||||||
// excluding death games
|
// excluding death games
|
||||||
@@ -96,6 +97,7 @@ public class GamePlay implements Serializable {
|
|||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
//e.printStackTrace();
|
//e.printStackTrace();
|
||||||
System.out.println("Unable to read from GamePlay file: " + fileName + ", initializing a new GamePlay instance.");
|
System.out.println("Unable to read from GamePlay file: " + fileName + ", initializing a new GamePlay instance.");
|
||||||
|
gp = GamePlay.DEFAULT_PROFILE;
|
||||||
}
|
}
|
||||||
return gp;
|
return gp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ public class MarioComponent extends JComponent implements Runnable,
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
//while (true) {
|
||||||
graphicsConfiguration = getGraphicsConfiguration();
|
graphicsConfiguration = getGraphicsConfiguration();
|
||||||
|
|
||||||
Art.init(graphicsConfiguration, sound);
|
Art.init(graphicsConfiguration, sound);
|
||||||
@@ -191,7 +191,7 @@ public class MarioComponent extends JComponent implements Runnable,
|
|||||||
Mario.fire = false;
|
Mario.fire = false;
|
||||||
Mario.large = false;
|
Mario.large = false;
|
||||||
Mario.coins = 0;
|
Mario.coins = 0;
|
||||||
Mario.lives = 3;
|
Mario.lives = 1;
|
||||||
|
|
||||||
randomLevel.init();
|
randomLevel.init();
|
||||||
randomLevel.setSound(sound);
|
randomLevel.setSound(sound);
|
||||||
@@ -262,6 +262,7 @@ public class MarioComponent extends JComponent implements Runnable,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Art.stopMusic();
|
Art.stopMusic();
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawString(Graphics g, String text, int x, int y, int c) {
|
private void drawString(Graphics g, String text, int x, int y, int c) {
|
||||||
|
|||||||
@@ -8,7 +8,23 @@ public class FitnessEvaluator {
|
|||||||
public static boolean isFit(LevelParseTree parseTree, PlayerProfile playerProfile, LevelArchetype levelArchetype) {
|
public static boolean isFit(LevelParseTree parseTree, PlayerProfile playerProfile, LevelArchetype levelArchetype) {
|
||||||
System.out.println("Evaluating LevelParseTree for fitness");
|
System.out.println("Evaluating LevelParseTree for fitness");
|
||||||
List<LevelComponent> levelTemplate = parseTree.getLevelTemplate();
|
List<LevelComponent> levelTemplate = parseTree.getLevelTemplate();
|
||||||
//a good level has 8-16 components, plus some additional complexity depending on the player's skill level
|
//a good level has 8-24 components, plus some additional complexity depending on the player's skill level
|
||||||
return levelTemplate.size() > 9 && levelTemplate.size() < 25;
|
|
||||||
|
if (levelTemplate.size() < 8) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (levelTemplate.size() > 24) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (LevelComponent lc : levelTemplate) {
|
||||||
|
if (!playerProfile.isEnabled(lc.getType())) {
|
||||||
|
System.out.println("Level is not fit: " + lc.getType() + " is not enabled.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ public class PCGLevel extends Level {
|
|||||||
|
|
||||||
setSpriteTemplate(xo + 2, floor - 1, new SpriteTemplate(
|
setSpriteTemplate(xo + 2, floor - 1, new SpriteTemplate(
|
||||||
SpriteTemplate.RED_TURTLE, false));
|
SpriteTemplate.RED_TURTLE, false));
|
||||||
|
ENEMIES++;
|
||||||
|
|
||||||
for (int x = 5; x < 26; x++) {
|
for (int x = 5; x < 26; x++) {
|
||||||
for (int y = floor - 3; y < height; y++) {
|
for (int y = floor - 3; y < height; y++) {
|
||||||
@@ -216,30 +217,37 @@ public class PCGLevel extends Level {
|
|||||||
&& x >= 11 && x <= 23) {
|
&& x >= 11 && x <= 23) {
|
||||||
if (x == 15) {
|
if (x == 15) {
|
||||||
setBlock(xo + x, floor - 6, Level.COIN);
|
setBlock(xo + x, floor - 6, Level.COIN);
|
||||||
|
COINS++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (x == 16) {
|
else if (x == 16) {
|
||||||
setBlock(xo + x, floor - 7, Level.COIN);
|
setBlock(xo + x, floor - 7, Level.COIN);
|
||||||
|
COINS++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (x == 18) {
|
else if (x == 18) {
|
||||||
setBlock(xo + x, floor - 8, Level.COIN);
|
setBlock(xo + x, floor - 8, Level.COIN);
|
||||||
|
COINS++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (x == 19) {
|
else if (x == 19) {
|
||||||
setBlock(xo + x, floor - 8, Level.COIN);
|
setBlock(xo + x, floor - 8, Level.COIN);
|
||||||
|
COINS++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (x == 20) {
|
else if (x == 20) {
|
||||||
setBlock(xo + x, floor - 8, Level.COIN);
|
setBlock(xo + x, floor - 8, Level.COIN);
|
||||||
|
COINS++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (x == 22) {
|
else if (x == 22) {
|
||||||
setBlock(xo + x, floor - 7, Level.COIN);
|
setBlock(xo + x, floor - 7, Level.COIN);
|
||||||
|
COINS++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (x == 23) {
|
else if (x == 23) {
|
||||||
setBlock(xo + x, floor - 6, Level.COIN);
|
setBlock(xo + x, floor - 6, Level.COIN);
|
||||||
|
COINS++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,21 +255,30 @@ public class PCGLevel extends Level {
|
|||||||
&& reward == PlayerProfile.ChallengeRewardType.COIN
|
&& reward == PlayerProfile.ChallengeRewardType.COIN
|
||||||
&& x >= 10 && x <= 20) {
|
&& x >= 10 && x <= 20) {
|
||||||
setBlock(xo + x, floor - 6, Level.COIN);
|
setBlock(xo + x, floor - 6, Level.COIN);
|
||||||
|
COINS++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (reward == PlayerProfile.ChallengeRewardType.BLOCK
|
else if (reward == PlayerProfile.ChallengeRewardType.BLOCK
|
||||||
&& x >= 13 && x <= 17) {
|
&& x >= 13 && x <= 17) {
|
||||||
setBlock(
|
byte tile = (random.nextDouble() <= probability
|
||||||
xo + x,
|
|
||||||
floor - 6,
|
|
||||||
(random.nextDouble() <= probability
|
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP)) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP)) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
|
|
||||||
|
setBlock(xo + x, floor - 6, tile);
|
||||||
|
|
||||||
|
if (tile == Level.BLOCK_COIN) {
|
||||||
|
BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_POWERUP) {
|
||||||
|
BLOCKS_POWER++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x >= 26 - numEnemies) {
|
if (x >= 26 - numEnemies) {
|
||||||
setSpriteTemplate(xo + x, floor - 4, new SpriteTemplate(
|
setSpriteTemplate(xo + x, floor - 4, new SpriteTemplate(
|
||||||
enemyType, false));
|
enemyType, false));
|
||||||
|
ENEMIES++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,16 +329,22 @@ public class PCGLevel extends Level {
|
|||||||
|
|
||||||
if (x > 2 && x < 6) {
|
if (x > 2 && x < 6) {
|
||||||
setBlock(xo + x, floor - 3, Level.BLOCK_EMPTY);
|
setBlock(xo + x, floor - 3, Level.BLOCK_EMPTY);
|
||||||
|
this.BLOCKS_EMPTY++;
|
||||||
} else if (x > 2 && x < 11) {
|
} else if (x > 2 && x < 11) {
|
||||||
setBlock(xo + x, floor - 5, Level.BLOCK_EMPTY);
|
setBlock(xo + x, floor - 5, Level.BLOCK_EMPTY);
|
||||||
|
this.BLOCKS_EMPTY++;
|
||||||
} else if (x == 11 || x == 12) {
|
} else if (x == 11 || x == 12) {
|
||||||
setBlock(xo + x, floor - 6, Level.COIN);
|
setBlock(xo + x, floor - 6, Level.COIN);
|
||||||
|
COINS++;
|
||||||
} else if (x == 13) {
|
} else if (x == 13) {
|
||||||
setBlock(xo + x, floor - 5, Level.COIN);
|
setBlock(xo + x, floor - 5, Level.COIN);
|
||||||
|
COINS++;
|
||||||
} else if (x == 14) {
|
} else if (x == 14) {
|
||||||
setBlock(xo + x, floor - 4, Level.COIN);
|
setBlock(xo + x, floor - 4, Level.COIN);
|
||||||
|
COINS++;
|
||||||
} else if (x == 15) {
|
} else if (x == 15) {
|
||||||
setBlock(xo + x, floor - 3, Level.COIN);
|
setBlock(xo + x, floor - 3, Level.COIN);
|
||||||
|
COINS++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,11 +372,14 @@ public class PCGLevel extends Level {
|
|||||||
|
|
||||||
setSpriteTemplate(xo + 6, floor - 1, new SpriteTemplate(
|
setSpriteTemplate(xo + 6, floor - 1, new SpriteTemplate(
|
||||||
SpriteTemplate.GREEN_TURTLE, false));
|
SpriteTemplate.GREEN_TURTLE, false));
|
||||||
|
|
||||||
|
this.BLOCKS_EMPTY++;
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
this.ENEMIES++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
int powerupLoc = random.nextInt(5);
|
int powerupLoc = random.nextInt(5);
|
||||||
|
|
||||||
setBlock(xo + 2, floor - 3,
|
setBlock(xo + 2, floor - 3,
|
||||||
powerupLoc == 0 ? Level.BLOCK_POWERUP
|
powerupLoc == 0 ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN);
|
||||||
@@ -369,6 +395,9 @@ public class PCGLevel extends Level {
|
|||||||
setBlock(xo + 6, floor - 3,
|
setBlock(xo + 6, floor - 3,
|
||||||
powerupLoc == 4 ? Level.BLOCK_POWERUP
|
powerupLoc == 4 ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN);
|
||||||
|
|
||||||
|
this.BLOCKS_COINS += 4;
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 9;
|
return 9;
|
||||||
@@ -387,12 +416,18 @@ public class PCGLevel extends Level {
|
|||||||
setBlock(xo, floor - 1, Level.BLOCK_EMPTY);
|
setBlock(xo, floor - 1, Level.BLOCK_EMPTY);
|
||||||
setBlock(xo + 4, floor - 1, Level.BLOCK_POWERUP);
|
setBlock(xo + 4, floor - 1, Level.BLOCK_POWERUP);
|
||||||
|
|
||||||
|
this.BLOCKS_EMPTY++;
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
|
||||||
setSpriteTemplate(xo + 3, floor - 1, new SpriteTemplate(
|
setSpriteTemplate(xo + 3, floor - 1, new SpriteTemplate(
|
||||||
SpriteTemplate.GREEN_TURTLE, false));
|
SpriteTemplate.GREEN_TURTLE, false));
|
||||||
|
|
||||||
|
this.ENEMIES++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
setBlock(xo + 2, floor - 3, Level.BLOCK_POWERUP);
|
setBlock(xo + 2, floor - 3, Level.BLOCK_POWERUP);
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 5;
|
return 5;
|
||||||
@@ -427,21 +462,30 @@ public class PCGLevel extends Level {
|
|||||||
if (x > 6 && x % 2 == 0) {
|
if (x > 6 && x % 2 == 0) {
|
||||||
setSpriteTemplate(xo + x, floor - 5, new SpriteTemplate(
|
setSpriteTemplate(xo + x, floor - 5, new SpriteTemplate(
|
||||||
enemyType, flying));
|
enemyType, flying));
|
||||||
|
ENEMIES++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reward == PlayerProfile.ChallengeRewardType.COIN && x >= 7
|
if (reward == PlayerProfile.ChallengeRewardType.COIN && x >= 7
|
||||||
&& x <= 16) {
|
&& x <= 16) {
|
||||||
setBlock(xo + x, floor - 7, Level.COIN);
|
setBlock(xo + x, floor - 7, Level.COIN);
|
||||||
|
COINS++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (reward == PlayerProfile.ChallengeRewardType.BLOCK
|
else if (reward == PlayerProfile.ChallengeRewardType.BLOCK
|
||||||
&& x >= 10 && x <= 13) {
|
&& x >= 10 && x <= 13) {
|
||||||
setBlock(
|
byte tile = random.nextDouble() < probability
|
||||||
xo + x,
|
|
||||||
floor - 7,
|
|
||||||
random.nextDouble() < probability
|
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
|
|
||||||
|
setBlock(xo + x, floor - 7, tile);
|
||||||
|
|
||||||
|
if (tile == Level.BLOCK_COIN) {
|
||||||
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 18;
|
return 18;
|
||||||
@@ -589,6 +633,7 @@ public class PCGLevel extends Level {
|
|||||||
setSpriteTemplate(xo + soFar + x, this.height
|
setSpriteTemplate(xo + soFar + x, this.height
|
||||||
- heightMod, new SpriteTemplate(enemyType,
|
- heightMod, new SpriteTemplate(enemyType,
|
||||||
false));
|
false));
|
||||||
|
ENEMIES++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,6 +697,7 @@ public class PCGLevel extends Level {
|
|||||||
setSpriteTemplate(xo + length, height - localHeight,
|
setSpriteTemplate(xo + length, height - localHeight,
|
||||||
new SpriteTemplate(SpriteTemplate.JUMP_FLOWER,
|
new SpriteTemplate(SpriteTemplate.JUMP_FLOWER,
|
||||||
false));
|
false));
|
||||||
|
ENEMIES++;
|
||||||
}
|
}
|
||||||
|
|
||||||
length += 2;
|
length += 2;
|
||||||
@@ -821,11 +867,13 @@ public class PCGLevel extends Level {
|
|||||||
enemyType,
|
enemyType,
|
||||||
(enemyType == SpriteTemplate.RED_TURTLE && shouldAddChallenge(PlayerProfile.ChallengeRewardType.HARDER_ENEMY))
|
(enemyType == SpriteTemplate.RED_TURTLE && shouldAddChallenge(PlayerProfile.ChallengeRewardType.HARDER_ENEMY))
|
||||||
|| enemyType != SpriteTemplate.RED_TURTLE));
|
|| enemyType != SpriteTemplate.RED_TURTLE));
|
||||||
|
ENEMIES++;
|
||||||
}
|
}
|
||||||
|
|
||||||
reward = shouldAddReward();
|
reward = shouldAddReward();
|
||||||
if (reward == PlayerProfile.ChallengeRewardType.COIN
|
if (reward == PlayerProfile.ChallengeRewardType.COIN
|
||||||
&& hold != LevelComponent.PlatformLevel.TOP) {
|
&& hold != LevelComponent.PlatformLevel.TOP) {
|
||||||
|
|
||||||
setBlock(xo + length, this.height - heightMod - 3,
|
setBlock(xo + length, this.height - heightMod - 3,
|
||||||
Level.COIN);
|
Level.COIN);
|
||||||
setBlock(xo + length + 1, this.height - heightMod - 3,
|
setBlock(xo + length + 1, this.height - heightMod - 3,
|
||||||
@@ -834,22 +882,38 @@ public class PCGLevel extends Level {
|
|||||||
Level.COIN);
|
Level.COIN);
|
||||||
setBlock(xo + length + 3, this.height - heightMod - 3,
|
setBlock(xo + length + 3, this.height - heightMod - 3,
|
||||||
Level.COIN);
|
Level.COIN);
|
||||||
|
|
||||||
|
COINS += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (reward == PlayerProfile.ChallengeRewardType.BLOCK
|
else if (reward == PlayerProfile.ChallengeRewardType.BLOCK
|
||||||
&& hold != LevelComponent.PlatformLevel.TOP) {
|
&& hold != LevelComponent.PlatformLevel.TOP) {
|
||||||
setBlock(
|
|
||||||
xo + length + 1,
|
byte tile = random.nextDouble() < probability
|
||||||
this.height - heightMod - 3,
|
|
||||||
random.nextDouble() < probability
|
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
setBlock(
|
setBlock(xo + length + 1, this.height - heightMod - 3, tile);
|
||||||
xo + length + 2,
|
|
||||||
this.height - heightMod - 3,
|
if (tile == Level.BLOCK_COIN) {
|
||||||
random.nextDouble() < probability
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile = random.nextDouble() < probability
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
|
setBlock(xo + length + 2, this.height - heightMod - 3, tile);
|
||||||
|
|
||||||
|
if (tile == Level.BLOCK_COIN) {
|
||||||
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
length += 4 + gapLength;
|
length += 4 + gapLength;
|
||||||
@@ -953,10 +1017,12 @@ public class PCGLevel extends Level {
|
|||||||
new SpriteTemplate(
|
new SpriteTemplate(
|
||||||
enemyType,
|
enemyType,
|
||||||
shouldAddChallenge(PlayerProfile.ChallengeRewardType.HARDER_ENEMY)));
|
shouldAddChallenge(PlayerProfile.ChallengeRewardType.HARDER_ENEMY)));
|
||||||
|
ENEMIES++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reward != null) {
|
if (reward != null) {
|
||||||
|
byte tile;
|
||||||
if (length >= 13) {
|
if (length >= 13) {
|
||||||
setBlock(xo + (length - 11), floor - 3, Level.COIN);
|
setBlock(xo + (length - 11), floor - 3, Level.COIN);
|
||||||
setBlock(xo + (length - 10), floor - 4, Level.COIN);
|
setBlock(xo + (length - 10), floor - 4, Level.COIN);
|
||||||
@@ -965,48 +1031,104 @@ public class PCGLevel extends Level {
|
|||||||
setBlock(xo + (length - 6), floor - 5, Level.COIN);
|
setBlock(xo + (length - 6), floor - 5, Level.COIN);
|
||||||
setBlock(xo + (length - 4), floor - 4, Level.COIN);
|
setBlock(xo + (length - 4), floor - 4, Level.COIN);
|
||||||
setBlock(xo + (length - 3), floor - 3, Level.COIN);
|
setBlock(xo + (length - 3), floor - 3, Level.COIN);
|
||||||
|
|
||||||
|
COINS += 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (length >= 7) {
|
else if (length >= 7) {
|
||||||
int start = length / 2;
|
int start = length / 2;
|
||||||
boolean coins = (reward == PlayerProfile.ChallengeRewardType.COIN);
|
boolean coins = (reward == PlayerProfile.ChallengeRewardType.COIN);
|
||||||
|
|
||||||
setBlock(
|
tile = coins ? Level.COIN
|
||||||
xo + (start - 2),
|
|
||||||
floor - 3,
|
|
||||||
coins ? Level.COIN
|
|
||||||
: random.nextDouble() < probability
|
: random.nextDouble() < probability
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
setBlock(
|
setBlock(xo + (start - 2), floor - 3, tile);
|
||||||
xo + (start - 1),
|
|
||||||
floor - 3,
|
if (coins) {
|
||||||
coins ? Level.COIN
|
COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_COIN) {
|
||||||
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_POWERUP) {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile = coins ? Level.COIN
|
||||||
: random.nextDouble() < probability
|
: random.nextDouble() < probability
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
setBlock(
|
setBlock(xo + (start - 1), floor - 3, tile);
|
||||||
xo + start,
|
|
||||||
floor - 3,
|
if (coins) {
|
||||||
coins ? Level.COIN
|
COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_COIN) {
|
||||||
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_POWERUP) {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile = coins ? Level.COIN
|
||||||
: random.nextDouble() < probability
|
: random.nextDouble() < probability
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
setBlock(
|
setBlock(xo + start, floor - 3, tile);
|
||||||
xo + (start + 1),
|
|
||||||
floor - 3,
|
if (coins) {
|
||||||
coins ? Level.COIN
|
COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_COIN) {
|
||||||
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_POWERUP) {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile = coins ? Level.COIN
|
||||||
: random.nextDouble() < probability
|
: random.nextDouble() < probability
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
|
setBlock(xo + (start + 1), floor - 3, tile);
|
||||||
|
|
||||||
|
if (coins) {
|
||||||
|
COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_COIN) {
|
||||||
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_POWERUP) {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
|
|
||||||
if (length % 2 != 0) {
|
if (length % 2 != 0) {
|
||||||
setBlock(
|
tile = coins ? Level.COIN
|
||||||
xo + (start + 2),
|
|
||||||
floor - 3,
|
|
||||||
coins ? Level.COIN
|
|
||||||
: random.nextDouble() < probability
|
: random.nextDouble() < probability
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
|
setBlock(xo + (start + 2), floor - 3, tile);
|
||||||
|
|
||||||
|
if (coins) {
|
||||||
|
COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_COIN) {
|
||||||
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_POWERUP) {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,27 +1136,59 @@ public class PCGLevel extends Level {
|
|||||||
int start = length / 2;
|
int start = length / 2;
|
||||||
boolean coins = (reward == PlayerProfile.ChallengeRewardType.COIN);
|
boolean coins = (reward == PlayerProfile.ChallengeRewardType.COIN);
|
||||||
|
|
||||||
setBlock(
|
tile = coins ? Level.COIN
|
||||||
xo + (start - 1),
|
|
||||||
floor - 3,
|
|
||||||
coins ? Level.COIN
|
|
||||||
: random.nextDouble() < probability
|
: random.nextDouble() < probability
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
setBlock(
|
setBlock(xo + (start - 1), floor - 3, tile);
|
||||||
xo + start,
|
|
||||||
floor - 3,
|
if (coins) {
|
||||||
coins ? Level.COIN
|
COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_COIN) {
|
||||||
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_POWERUP) {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile = coins ? Level.COIN
|
||||||
: random.nextDouble() < probability
|
: random.nextDouble() < probability
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
setBlock(
|
setBlock(xo + start, floor - 3, tile);
|
||||||
xo + (start + 1),
|
|
||||||
floor - 3,
|
if (coins) {
|
||||||
coins ? Level.COIN
|
COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_COIN) {
|
||||||
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_POWERUP) {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile = coins ? Level.COIN
|
||||||
: random.nextDouble() < probability
|
: random.nextDouble() < probability
|
||||||
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
.get(PlayerProfile.ChallengeRewardType.POWERUP) ? Level.BLOCK_POWERUP
|
||||||
: Level.BLOCK_COIN);
|
: Level.BLOCK_COIN;
|
||||||
|
setBlock(xo + (start + 1), floor - 3, tile);
|
||||||
|
|
||||||
|
if (coins) {
|
||||||
|
COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_COIN) {
|
||||||
|
this.BLOCKS_COINS++;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tile == Level.BLOCK_POWERUP) {
|
||||||
|
this.BLOCKS_POWER++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1111,7 +1265,7 @@ public class PCGLevel extends Level {
|
|||||||
System.out.println("Generating level for component list: ");
|
System.out.println("Generating level for component list: ");
|
||||||
LevelParseTree parseTree = grammar.generateRandomTree(seed, width);
|
LevelParseTree parseTree = grammar.generateRandomTree(seed, width);
|
||||||
|
|
||||||
int MAX_REGENS = 10;
|
int MAX_REGENS = 30;
|
||||||
int nRegens = 0;
|
int nRegens = 0;
|
||||||
while (!FitnessEvaluator.isFit(parseTree, profile, archetype)
|
while (!FitnessEvaluator.isFit(parseTree, profile, archetype)
|
||||||
&& nRegens < MAX_REGENS) {
|
&& nRegens < MAX_REGENS) {
|
||||||
@@ -1121,58 +1275,70 @@ public class PCGLevel extends Level {
|
|||||||
nRegens++;
|
nRegens++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<LevelComponent> levelTemplate = parseTree.getLevelTemplate();
|
||||||
|
|
||||||
if (nRegens == MAX_REGENS) {
|
if (nRegens == MAX_REGENS) {
|
||||||
System.out.println("Failed to generate a fit level after "
|
System.out.println("Failed to generate a fit level after "
|
||||||
+ nRegens + " attempts. Proceeding with unfit level.");
|
+ nRegens + " attempts. Proceeding with unfit level.");
|
||||||
|
} else {
|
||||||
|
System.out.println("Found fit level:");
|
||||||
|
for (LevelComponent lc : levelTemplate) {
|
||||||
|
System.out.println(lc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<LevelComponent> levelTemplate = parseTree.getLevelTemplate();
|
|
||||||
|
|
||||||
for (LevelComponent lcomp : levelTemplate) {
|
for (LevelComponent lcomp : levelTemplate) {
|
||||||
LevelComponent.TYPE lctype = lcomp.getType();
|
LevelComponent.TYPE lctype = lcomp.getType();
|
||||||
System.out.println("Building for: " + lcomp);
|
System.out.println("Building for: " + lcomp);
|
||||||
while (length < Math.min(width - 64, lcomp.getEnd())) {
|
while (length < Math.min(width - 64, lcomp.getEnd())) {
|
||||||
|
int lcLength;
|
||||||
switch (lctype) {
|
switch (lctype) {
|
||||||
case FLAT_LO:
|
case FLAT_LO:
|
||||||
case FLAT_HI:
|
case FLAT_HI:
|
||||||
length += buildStraight(length, lcomp.getEnd(), true);
|
lcLength = buildStraight(length, lcomp.getEnd(), true);
|
||||||
break;
|
break;
|
||||||
case PIPE_JUMP:
|
case PIPE_JUMP:
|
||||||
length += buildPipeJump(length, width - 64 - length);
|
lcLength = buildPipeJump(length, width - 64 - length);
|
||||||
break;
|
break;
|
||||||
case PLATFORM_JUMP:
|
case PLATFORM_JUMP:
|
||||||
length += buildPlatformJump(length, width - 64 - length);
|
lcLength = buildPlatformJump(length, width - 64
|
||||||
|
- length);
|
||||||
break;
|
break;
|
||||||
case MAZE:
|
case MAZE:
|
||||||
length += buildMaze(length, width - 64 - length);
|
lcLength = buildMaze(length, width - 64 - length);
|
||||||
break;
|
break;
|
||||||
case BLOCKS:
|
case BLOCKS:
|
||||||
length += buildMaze(length, width - 64 - length);
|
lcLength = buildMaze(length, width - 64 - length);
|
||||||
break;
|
break;
|
||||||
case BOWLING_ALLEY:
|
case BOWLING_ALLEY:
|
||||||
length += buildBowlingAlley(length, width - 64 - length);
|
lcLength = buildBowlingAlley(length, width - 64
|
||||||
|
- length);
|
||||||
break;
|
break;
|
||||||
case CANNON_LINE:
|
case CANNON_LINE:
|
||||||
length += buildCannonLine(length, width - 64 - length);
|
lcLength = buildCannonLine(length, width - 64 - length);
|
||||||
break;
|
break;
|
||||||
case COIN_DIVE:
|
case COIN_DIVE:
|
||||||
length += buildCoinDive(length, width - 64 - length);
|
lcLength = buildCoinDive(length, width - 64 - length);
|
||||||
break;
|
break;
|
||||||
case LEMMING_TRAP:
|
case LEMMING_TRAP:
|
||||||
length += buildLemmingTrap(length, width - 64 - length);
|
lcLength = buildLemmingTrap(length, width - 64 - length);
|
||||||
break;
|
break;
|
||||||
case POWER_UP:
|
case POWER_UP:
|
||||||
length += buildFreebie(length, width - 64 - length);
|
lcLength = buildFreebie(length, width - 64 - length);
|
||||||
//length += buildStraight(length, lcomp.getEnd(), true);
|
|
||||||
break;
|
break;
|
||||||
case SINGLE_PIT:
|
case SINGLE_PIT:
|
||||||
length += buildSinglePit(length, width - 64 - length);
|
lcLength = buildSinglePit(length, width - 64 - length);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
lcLength = 0;
|
||||||
System.out
|
System.out
|
||||||
.println("Cannot build level segment for unrecognized LevelComponent type: "
|
.println("Cannot build level segment for unrecognized LevelComponent type: "
|
||||||
+ type);
|
+ type);
|
||||||
}
|
}
|
||||||
|
if (lcLength == 0) {
|
||||||
|
lcLength = buildStraight(length, lcomp.getEnd(), true);
|
||||||
|
}
|
||||||
|
length += lcLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1243,8 +1409,8 @@ public class PCGLevel extends Level {
|
|||||||
playerMetrics, dataRecorder);
|
playerMetrics, dataRecorder);
|
||||||
System.out.println("PlayerProfile: " + profile);
|
System.out.println("PlayerProfile: " + profile);
|
||||||
|
|
||||||
LevelArchetype archetype = ArchetypeMatcher.getMatchingArchetype(
|
LevelArchetype archetype = ArchetypeMatcher
|
||||||
playerMetrics, dataRecorder);
|
.getMatchingArchetype(profile);
|
||||||
System.out.println("LevelArchetype: " + archetype);
|
System.out.println("LevelArchetype: " + archetype);
|
||||||
|
|
||||||
System.out.println("Creating level grammar");
|
System.out.println("Creating level grammar");
|
||||||
|
|||||||
@@ -52,33 +52,26 @@ public class PlayerProfile {
|
|||||||
return skillLevel;
|
return skillLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getBumpSkill() {
|
||||||
|
return skillVector.get(SKILL.BUMP);
|
||||||
|
}
|
||||||
|
public int getCollectSkill() {
|
||||||
|
return skillVector.get(SKILL.COLLECT);
|
||||||
|
}
|
||||||
public int getJumpSkill() {
|
public int getJumpSkill() {
|
||||||
switch (type) {
|
return skillVector.get(SKILL.JUMP);
|
||||||
case JUMPER:
|
|
||||||
switch (skillLevel) {
|
|
||||||
case NOVICE:
|
|
||||||
return 20;
|
|
||||||
case BEGINNER:
|
|
||||||
return 40;
|
|
||||||
case COMPETENT:
|
|
||||||
return 60;
|
|
||||||
case PROFICIENT:
|
|
||||||
return 80;
|
|
||||||
case EXPERT:
|
|
||||||
return 100;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
default:
|
public int getRunSkill() {
|
||||||
return 0;
|
return skillVector.get(SKILL.RUN);
|
||||||
}
|
}
|
||||||
|
public int getShootSkill() {
|
||||||
|
return skillVector.get(SKILL.SHOOT);
|
||||||
|
}
|
||||||
|
public int getStompSkill() {
|
||||||
|
return skillVector.get(SKILL.STOMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getProbability(ChallengeRewardType crt) {
|
public double getProbability(ChallengeRewardType crt) {
|
||||||
// if (!isEnabled(type)) {
|
|
||||||
// return 0.0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
switch (crt) {
|
switch (crt) {
|
||||||
case GAP:
|
case GAP:
|
||||||
return Math.min(.5, (.5) * (skillVector.get(SKILL.JUMP) / 100.0)
|
return Math.min(.5, (.5) * (skillVector.get(SKILL.JUMP) / 100.0)
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ import dk.itu.mario.MarioInterface.LevelGenerator;
|
|||||||
import dk.itu.mario.MarioInterface.LevelInterface;
|
import dk.itu.mario.MarioInterface.LevelInterface;
|
||||||
import dk.itu.mario.engine.DataRecorder;
|
import dk.itu.mario.engine.DataRecorder;
|
||||||
import dk.itu.mario.level.Level;
|
import dk.itu.mario.level.Level;
|
||||||
|
import dk.itu.mario.level.LevelArchetype;
|
||||||
import dk.itu.mario.level.PCGLevel;
|
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
|
public class PCGLevelGenerator implements
|
||||||
LevelGenerator {
|
LevelGenerator {
|
||||||
@@ -20,7 +24,21 @@ public class PCGLevelGenerator implements
|
|||||||
@Override
|
@Override
|
||||||
public int generateLevelType(GamePlay playerMetrics, DataRecorder dataRecorder) {
|
public int generateLevelType(GamePlay playerMetrics, DataRecorder dataRecorder) {
|
||||||
System.out.println("Generating level type based on playerMetrics, dataRecorder: TYPE_OVERGROUND");
|
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
|
@Override
|
||||||
|
|||||||
@@ -1,13 +1,48 @@
|
|||||||
package dk.itu.mario.level.matcher;
|
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;
|
||||||
import dk.itu.mario.level.LevelArchetype.TYPE;
|
import dk.itu.mario.level.LevelArchetype.TYPE;
|
||||||
|
import dk.itu.mario.level.PlayerProfile;
|
||||||
|
|
||||||
public class ArchetypeMatcher {
|
public class ArchetypeMatcher {
|
||||||
public static LevelArchetype getMatchingArchetype(GamePlay playerMetrics, DataRecorder detailedInfo) {
|
public static LevelArchetype getMatchingArchetype(
|
||||||
System.out.println("Selecting PlayerProfile based on GamePlay metrics, DataRecorder logs.");
|
PlayerProfile playerProfile) {
|
||||||
return new LevelArchetype(TYPE.OVERGROUND,1);
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ public class ProfileMatcher {
|
|||||||
DataRecorder detailedInfo) {
|
DataRecorder detailedInfo) {
|
||||||
System.out
|
System.out
|
||||||
.println("Selecting PlayerProfile based on GamePlay metrics, DataRecorder logs.");
|
.println("Selecting PlayerProfile based on GamePlay metrics, DataRecorder logs.");
|
||||||
|
|
||||||
// GAP comes from jump skill and jumper type.
|
// GAP comes from jump skill and jumper type.
|
||||||
// ENEMY comes from run skill and runner type and stomp skill.
|
// ENEMY comes from run skill and runner type and stomp skill.
|
||||||
// HARDER_ENEMY comes from shooting skill and shooting type.
|
// HARDER_ENEMY comes from shooting skill and shooting type.
|
||||||
@@ -123,7 +122,7 @@ public class ProfileMatcher {
|
|||||||
// Relevant to: ENEMY.
|
// Relevant to: ENEMY.
|
||||||
skillHolder = (int) (100 * ((((double) playerMetrics.timeSpentRunning)
|
skillHolder = (int) (100 * ((((double) playerMetrics.timeSpentRunning)
|
||||||
/ playerMetrics.totalTime + (playerMetrics.timesPressedRun / 75 > 1 ? 0
|
/ playerMetrics.totalTime + (playerMetrics.timesPressedRun / 75 > 1 ? 0
|
||||||
: 1 - (playerMetrics.timesPressedRun / 75.0))) / 2));
|
: 1 - (playerMetrics.timesPressedRun / 200))) / 2));
|
||||||
skillVector.put(SKILL.RUN, new Integer(skillHolder));
|
skillVector.put(SKILL.RUN, new Integer(skillHolder));
|
||||||
|
|
||||||
// Get shoot skills.
|
// Get shoot skills.
|
||||||
@@ -174,6 +173,8 @@ public class ProfileMatcher {
|
|||||||
|
|
||||||
skillHolder /= skillVector.size();
|
skillHolder /= skillVector.size();
|
||||||
|
|
||||||
|
skillHolder = (skillHolder + ((int) (100 * ((double) playerMetrics.timesSwichingPower / (playerMetrics.totalpowerBlocks * 2))))) / 2;
|
||||||
|
|
||||||
if (skillHolder >= 80) {
|
if (skillHolder >= 80) {
|
||||||
skillLevel = SKILL_LEVEL.EXPERT;
|
skillLevel = SKILL_LEVEL.EXPERT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
\relax
|
\relax
|
||||||
|
\citation{zimmerman}
|
||||||
\citation{bartle}
|
\citation{bartle}
|
||||||
\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Adaptive Mario in action}}{1}}
|
\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Adaptive Mario in action}}{1}}
|
||||||
\newlabel{img:mario-ex}{{1}{1}}
|
\newlabel{img:mario-ex}{{1}{1}}
|
||||||
\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Flow State: Game Difficulty vs. Player Skill}}{2}}
|
\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Flow State: Game Difficulty vs. Player Skill}}{2}}
|
||||||
\newlabel{img:flow-state}{{2}{2}}
|
\newlabel{img:flow-state}{{2}{2}}
|
||||||
\bibstyle{unsrt}
|
|
||||||
\bibdata{p3refs}
|
|
||||||
\bibcite{bartle}{1}
|
|
||||||
\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces A Simple Overland Level Grammar}}{3}}
|
\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces A Simple Overland Level Grammar}}{3}}
|
||||||
\newlabel{img:stochastic-grammar}{{3}{3}}
|
\newlabel{img:stochastic-grammar}{{3}{3}}
|
||||||
|
\bibstyle{unsrt}
|
||||||
|
\bibdata{p3refs}
|
||||||
|
\bibcite{zimmerman}{1}
|
||||||
|
\bibcite{bartle}{2}
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
\begin{thebibliography}{1}
|
\begin{thebibliography}{1}
|
||||||
|
|
||||||
|
\bibitem{zimmerman}
|
||||||
|
K.~Salen and E.~Zimmerman.
|
||||||
|
\newblock {\em Rules of Play}.
|
||||||
|
\newblock The MIT Press, 2004.
|
||||||
|
|
||||||
\bibitem{bartle}
|
\bibitem{bartle}
|
||||||
Richard Bartle.
|
Richard Bartle.
|
||||||
\newblock Hearts, {Clubs}, {Diamonds}, {Spades}: {Players Who} suit {MUDs}.
|
\newblock Hearts, clubs, diamonds, spades: Players who suit {MUDs}.
|
||||||
\newblock http://aigamedev.com/open/interviews/mario-ai/, 1996.
|
\newblock http://aigamedev.com/open/interviews/mario-ai/, 1996.
|
||||||
\newblock [Online; accessed 18-March-2012].
|
\newblock [Online; accessed 18-March-2012].
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
This is pdfTeX, Version 3.1415926-2.3-1.40.12 (MiKTeX 2.9) (preloaded format=pdflatex 2012.1.11) 18 MAR 2012 15:01
|
This is pdfTeX, Version 3.1415926-2.3-1.40.12 (MiKTeX 2.9) (preloaded format=pdflatex 2012.1.11) 18 MAR 2012 18:45
|
||||||
entering extended mode
|
entering extended mode
|
||||||
**D:/workspace/cs8803p3/writeup/CS8803_P3.tex
|
**D:/workspace/cs8803p3/writeup/CS8803_P3.tex
|
||||||
(D:/workspace/cs8803p3/writeup/CS8803_P3.tex
|
(D:/workspace/cs8803p3/writeup/CS8803_P3.tex
|
||||||
@@ -175,10 +175,11 @@ File: mario_example.png Graphic file (type png)
|
|||||||
<use mario_example.png>
|
<use mario_example.png>
|
||||||
Package pdftex.def Info: mario_example.png used on input line 23.
|
Package pdftex.def Info: mario_example.png used on input line 23.
|
||||||
(pdftex.def) Requested size: 216.80669pt x 162.60416pt.
|
(pdftex.def) Requested size: 216.80669pt x 162.60416pt.
|
||||||
File: mario_example.png Graphic file (type png)
|
|
||||||
|
|
||||||
<use mario_example.png>
|
<mario_underground.png, id=2, 642.4pt x 481.8pt>
|
||||||
Package pdftex.def Info: mario_example.png used on input line 24.
|
File: mario_underground.png Graphic file (type png)
|
||||||
|
<use mario_underground.png>
|
||||||
|
Package pdftex.def Info: mario_underground.png used on input line 24.
|
||||||
(pdftex.def) Requested size: 216.80669pt x 162.60416pt.
|
(pdftex.def) Requested size: 216.80669pt x 162.60416pt.
|
||||||
Missing character: There is no à in font cmr10!
|
Missing character: There is no à in font cmr10!
|
||||||
Missing character: There is no ¡ in font cmr10!
|
Missing character: There is no ¡ in font cmr10!
|
||||||
@@ -186,12 +187,12 @@ Missing character: There is no
|
|||||||
Missing character: There is no in font cmr10!
|
Missing character: There is no in font cmr10!
|
||||||
Missing character: There is no à in font cmr10!
|
Missing character: There is no à in font cmr10!
|
||||||
Missing character: There is no ¡ in font cmr10!
|
Missing character: There is no ¡ in font cmr10!
|
||||||
<flow-state.png, id=2, 305.34074pt x 223.43475pt>
|
|
||||||
File: flow-state.png Graphic file (type png)
|
|
||||||
|
|
||||||
|
<flow-state.png, id=3, 305.34074pt x 223.43475pt>
|
||||||
|
File: flow-state.png Graphic file (type png)
|
||||||
<use flow-state.png>
|
<use flow-state.png>
|
||||||
Package pdftex.def Info: flow-state.png used on input line 36.
|
Package pdftex.def Info: flow-state.png used on input line 36.
|
||||||
(pdftex.def) Requested size: 216.80669pt x 158.65341pt.
|
(pdftex.def) Requested size: 271.0125pt x 198.33125pt.
|
||||||
|
|
||||||
|
|
||||||
LaTeX Warning: `!h' float specifier changed to `!ht'.
|
LaTeX Warning: `!h' float specifier changed to `!ht'.
|
||||||
@@ -199,32 +200,28 @@ LaTeX Warning: `!h' float specifier changed to `!ht'.
|
|||||||
[1
|
[1
|
||||||
|
|
||||||
{C:/ProgramData/MiKTeX/2.9/pdftex/config/pdftex.map} <D:/workspace/cs8803p3/wri
|
{C:/ProgramData/MiKTeX/2.9/pdftex/config/pdftex.map} <D:/workspace/cs8803p3/wri
|
||||||
teup/mario_example.png>]
|
teup/mario_example.png> <D:/workspace/cs8803p3/writeup/mario_underground.png (P
|
||||||
|
NG copy)>]
|
||||||
LaTeX Font Info: External font `cmex10' loaded for size
|
LaTeX Font Info: External font `cmex10' loaded for size
|
||||||
(Font) <7> on input line 61.
|
(Font) <7> on input line 61.
|
||||||
LaTeX Font Info: External font `cmex10' loaded for size
|
LaTeX Font Info: External font `cmex10' loaded for size
|
||||||
(Font) <5> on input line 61.
|
(Font) <5> on input line 61.
|
||||||
[2 <D:/workspace/cs8803p3/writeup/flow-state.png>]
|
[2 <D:/workspace/cs8803p3/writeup/flow-state.png>]
|
||||||
<StochasticGrammar.png, id=15, 438.438pt x 222.8325pt>
|
<StochasticGrammar.png, id=16, 438.438pt x 222.8325pt>
|
||||||
File: StochasticGrammar.png Graphic file (type png)
|
File: StochasticGrammar.png Graphic file (type png)
|
||||||
|
|
||||||
<use StochasticGrammar.png>
|
<use StochasticGrammar.png>
|
||||||
Package pdftex.def Info: StochasticGrammar.png used on input line 83.
|
Package pdftex.def Info: StochasticGrammar.png used on input line 84.
|
||||||
(pdftex.def) Requested size: 406.51875pt x 206.62346pt.
|
(pdftex.def) Requested size: 406.51875pt x 206.62346pt.
|
||||||
(D:\workspace\cs8803p3\writeup\CS8803_P3.bbl
|
[3 <D:/workspace/cs8803p3/writeup/StochasticGrammar.png>] (D:\workspace\cs8803
|
||||||
Underfull \hbox (badness 10000) in paragraph at lines 4--8
|
p3\writeup\CS8803_P3.bbl) [4]
|
||||||
[]\OT1/cmr/m/n/10 Richard Bar-tle. Hearts, Clubs, Di-a-monds, Spades: Play-ers
|
|
||||||
Who suit MUDs.
|
|
||||||
[]
|
|
||||||
|
|
||||||
[3 <D:/workspace/cs8803p3/writeup/StochasticGrammar.png>]) [4]
|
|
||||||
(D:\workspace\cs8803p3\writeup\CS8803_P3.aux) )
|
(D:\workspace\cs8803p3\writeup\CS8803_P3.aux) )
|
||||||
Here is how much of TeX's memory you used:
|
Here is how much of TeX's memory you used:
|
||||||
1905 strings out of 494045
|
1913 strings out of 494045
|
||||||
26059 string characters out of 3145969
|
26215 string characters out of 3145969
|
||||||
87712 words of memory out of 3000000
|
87715 words of memory out of 3000000
|
||||||
5212 multiletter control sequences out of 15000+200000
|
5218 multiletter control sequences out of 15000+200000
|
||||||
7458 words of font info for 27 fonts, out of 3000000 for 9000
|
7804 words of font info for 28 fonts, out of 3000000 for 9000
|
||||||
715 hyphenation exceptions out of 8191
|
715 hyphenation exceptions out of 8191
|
||||||
27i,7n,32p,875b,220s stack positions out of 5000i,500n,10000p,200000b,50000s
|
27i,7n,32p,875b,220s stack positions out of 5000i,500n,10000p,200000b,50000s
|
||||||
<C:/Program Files (x86)/MiKTeX 2
|
<C:/Program Files (x86)/MiKTeX 2
|
||||||
@@ -233,10 +230,11 @@ Here is how much of TeX's memory you used:
|
|||||||
onts/type1/public/amsfonts/cm/cmr10.pfb><C:/Program Files (x86)/MiKTeX 2.9/font
|
onts/type1/public/amsfonts/cm/cmr10.pfb><C:/Program Files (x86)/MiKTeX 2.9/font
|
||||||
s/type1/public/amsfonts/cm/cmr12.pfb><C:/Program Files (x86)/MiKTeX 2.9/fonts/t
|
s/type1/public/amsfonts/cm/cmr12.pfb><C:/Program Files (x86)/MiKTeX 2.9/fonts/t
|
||||||
ype1/public/amsfonts/cm/cmr17.pfb><C:/Program Files (x86)/MiKTeX 2.9/fonts/type
|
ype1/public/amsfonts/cm/cmr17.pfb><C:/Program Files (x86)/MiKTeX 2.9/fonts/type
|
||||||
1/public/amsfonts/cm/cmtt10.pfb>
|
1/public/amsfonts/cm/cmti10.pfb><C:/Program Files (x86)/MiKTeX 2.9/fonts/type1/
|
||||||
Output written on CS8803_P3.pdf (4 pages, 130421 bytes).
|
public/amsfonts/cm/cmtt10.pfb>
|
||||||
|
Output written on CS8803_P3.pdf (4 pages, 153381 bytes).
|
||||||
PDF statistics:
|
PDF statistics:
|
||||||
42 PDF objects out of 1000 (max. 8388607)
|
47 PDF objects out of 1000 (max. 8388607)
|
||||||
0 named destinations out of 1000 (max. 500000)
|
0 named destinations out of 1000 (max. 500000)
|
||||||
16 words of extra memory for PDF output out of 10000 (max. 10000000)
|
21 words of extra memory for PDF output out of 10000 (max. 10000000)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -21,7 +21,7 @@ The authors of Adaptive Mario use several PCG techniques to develop a simple pla
|
|||||||
\begin{figure}[h!]
|
\begin{figure}[h!]
|
||||||
\centering
|
\centering
|
||||||
\includegraphics[width=0.4 \textwidth]{mario_example.png}
|
\includegraphics[width=0.4 \textwidth]{mario_example.png}
|
||||||
\includegraphics[width=0.4 \textwidth]{mario_example.png}
|
\includegraphics[width=0.4 \textwidth]{mario_underground.png}
|
||||||
\caption{Adaptive Mario in action}
|
\caption{Adaptive Mario in action}
|
||||||
\label{img:mario-ex}
|
\label{img:mario-ex}
|
||||||
\end{figure}
|
\end{figure}
|
||||||
@@ -29,11 +29,11 @@ The authors of Adaptive Mario use several PCG techniques to develop a simple pla
|
|||||||
As shown in Figure \ref{img:mario-ex}, the conceptual goal is that players with different play styles and skill levels should have a very different gameplay experience from the moment the level begins. Of course, the very first time Adaptive Mario is run in a new environment, a specific level is presented based on an a priori model of an 'average' player.
|
As shown in Figure \ref{img:mario-ex}, the conceptual goal is that players with different play styles and skill levels should have a very different gameplay experience from the moment the level begins. Of course, the very first time Adaptive Mario is run in a new environment, a specific level is presented based on an a priori model of an 'average' player.
|
||||||
|
|
||||||
\section*{Related Works}
|
\section*{Related Works}
|
||||||
The essential goal of Adaptive Mario is to facilitate flow state by giving the player sufficient challenge and variety without rapidly becoming too difficult. As defined by Mihály Csíkszentmihályi, ``flow'' is the state of total immersion and cocentration in which the player believes he or she is overcoming obstacles by the narrowest of margins. As shown in Figure \ref{img:flow-state}, achieving this state involves a delicate balance between the difficulty of the game and the player's degree of skill. If the game is too hard, the player will become frustrated. On the other hand, most players will become bored if the game is too easy.
|
The essential goal of Adaptive Mario is to facilitate flow state by giving the player sufficient challenge and variety without rapidly becoming too difficult. As defined by Mihály Csíkszentmihályi, according to Salen and Zimmerman \cite{zimmerman}, ``flow'' is the state of total immersion and cocentration in which the player believes he or she is overcoming obstacles by the narrowest of margins. As shown in Figure \ref{img:flow-state}, achieving this state involves a delicate balance between the difficulty of the game and the player's degree of skill. If the game is too hard, the player will become frustrated. On the other hand, most players will become bored if the game is too easy.
|
||||||
|
|
||||||
\begin{figure}[h!]
|
\begin{figure}[h!]
|
||||||
\centering
|
\centering
|
||||||
\includegraphics[width=0.4 \textwidth]{flow-state.png}
|
\includegraphics[width=0.5 \textwidth]{flow-state.png}
|
||||||
\caption{Flow State: Game Difficulty vs. Player Skill}
|
\caption{Flow State: Game Difficulty vs. Player Skill}
|
||||||
\label{img:flow-state}
|
\label{img:flow-state}
|
||||||
\end{figure}
|
\end{figure}
|
||||||
@@ -61,13 +61,14 @@ In addition to assigning a player profile, the ProfileMatcher assesses the playe
|
|||||||
\begin{tabular}{ | l | l | l | }
|
\begin{tabular}{ | l | l | l | }
|
||||||
\hline
|
\hline
|
||||||
Score & Skill Level & Attributes\\ \hline
|
Score & Skill Level & Attributes\\ \hline
|
||||||
20\% & Novice & low situational awareness, reflexive responses\\ \hline
|
20\% & Novice & Low situational awareness, Reflexive responses\\ \hline
|
||||||
40\% & Beginner & uses judgement to react to challenges, limited awareness \\ \hline
|
40\% & Beginner & Uses judgement to react to challenges, Limited awareness \\ \hline
|
||||||
60\% & Competent & copies with multiple challenges, uses sound strategy \\ \hline
|
60\% & Competent & Copes with multiple challenges, Uses sound strategy \\ \hline
|
||||||
80\% & Proficient & makes rapid decisions, prioritzes goals \\ \hline
|
80\% & Proficient & Makes rapid decisions, Prioritzes goals \\ \hline
|
||||||
100\% & Expert & intuitively solves challenges, pushes boundaries \\ \hline
|
100\% & Expert & Intuitively solves challenges, Pushes limits \\ \hline
|
||||||
\end{tabular}
|
\end{tabular}
|
||||||
\end{table}
|
\end{table}
|
||||||
|
|
||||||
\subsection*{Level Archetype Selection}
|
\subsection*{Level Archetype Selection}
|
||||||
The Level Archetype selector picks an overall macro-form for the level based on the player's profile and skill level. As there are five categories and only three distinct environments in the Inifinite Mario engine (Overland, Underground and Castle), different profiles cause similar Level Archetypes to be generated. However, this does provide the opportunity to indicate to the player what types of challenges lie ahead and may serve to enhance immersion.
|
The Level Archetype selector picks an overall macro-form for the level based on the player's profile and skill level. As there are five categories and only three distinct environments in the Inifinite Mario engine (Overland, Underground and Castle), different profiles cause similar Level Archetypes to be generated. However, this does provide the opportunity to indicate to the player what types of challenges lie ahead and may serve to enhance immersion.
|
||||||
|
|
||||||
@@ -88,8 +89,38 @@ Given a suitable array of predefined LevelComponent types, each of which corresp
|
|||||||
One potential pitfall of using a CFG for this purpose is that the generated level may be over-specified (containing too many elements) and hence too crowded, or under-specified and nearly empty. To mitigate this problem, a fitness evaluation function iteratively invokes the LevelGrammar, rejecting proposed levels with too many or too few LevelComponents.
|
One potential pitfall of using a CFG for this purpose is that the generated level may be over-specified (containing too many elements) and hence too crowded, or under-specified and nearly empty. To mitigate this problem, a fitness evaluation function iteratively invokes the LevelGrammar, rejecting proposed levels with too many or too few LevelComponents.
|
||||||
|
|
||||||
\subsection*{Challenge Components: Micro-structure}
|
\subsection*{Challenge Components: Micro-structure}
|
||||||
|
Challenge components are small puzzles that lend variety to the randomized levels and serve a dual purpose in allowing Adaptive Mario to fit the player's preferred style.
|
||||||
|
|
||||||
|
First, by providing ever more difficulty scenarios, challenge is mainted. This trend also prevents a feedback loop wherein a player jumps frequently because a level contains many platforms, which causes the next level to contain many jumping puzzles and so on.
|
||||||
|
|
||||||
|
Second, specific can could be chosen to allow Adaptive Mario to discriminate between playstyles when a player's metrics are borderline between two typical profiles. Thus a player who is both a Runner and a Jumper could be given a very difficult jumping challenge to cause the metrics to trend one way or the other. However, this advanced adaptation was not implemented during this iteration of the project.
|
||||||
|
|
||||||
|
\begin{table}[ht]
|
||||||
|
\centering
|
||||||
|
\begin{tabular}{ | l | l | l | }
|
||||||
|
\hline
|
||||||
|
Difficulty & Challenge Component & Description \\ \hline
|
||||||
|
1 & Coin Dive & Some empty blocks, coins line the path to the ground.\\ \hline
|
||||||
|
2 & Free power-up & Sets the player up to get a power-up with little or no challenge.\\ \hline
|
||||||
|
3 & Straight & A straight stretch of land with maybe one enemy and maybe some coins or blocks\\ \hline
|
||||||
|
4 & Single Pit & A pit that the user must jump over; rocks on either side.\\ \hline
|
||||||
|
5 & Bowling Alley & A red koopa right before a long line of enemies. Kill them all!\\ \hline
|
||||||
|
6 & Cannon Line & A stack of 2 or 3 cannons.\\ \hline
|
||||||
|
7 & Maze & A maze of indestructible blocks, with enemies.\\ \hline
|
||||||
|
8 & Lemming Trap & A little pit with a few enemies that jump down into it.\\ \hline
|
||||||
|
9 & Platform Jump & A bunch of platforms to jump between.\\ \hline
|
||||||
|
10 & Pipe Jump & A bunch of thin pipes to jump between.\\ \hline
|
||||||
|
\end{tabular}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
\section*{Evaluation}
|
\section*{Evaluation}
|
||||||
|
Several challenges were overcome during the implementation of Adaptive Mario.
|
||||||
|
|
||||||
|
From a technical standpoint, finding a Java-compatible rule engine (Drools) was a time-consuming effort, mainly due to the large number of third-party JAR dependencies. Sufficient time was invested in this endeavor before integration was ultimately successful that the role of the rules engine was minimized during the design process. Consequently, only basic alterations are made to the random level structure based on the player profile.
|
||||||
|
|
||||||
|
Randomized level generation using a stochastic CFG was largely successful, however. Not only can this very simple grammar generate a variety of levels, implementation of a parser for the rule set allows a designer to make meaningful content changes without the need to recompile source code. Such grammars are limited of course - integration between the top-down macro generation code and bottom-up Challenge Component code was a challenge, as the LevelGrammar module lacks the capability to plan ahead and avoid akward juxtapositions of LevelComponents.
|
||||||
|
|
||||||
|
While the arbitrary scoring and single-iteration feedback loop of the PlayerProfile module functions as designed, the core PlayerProfile model reperesents the most likely area of improvement in the next version of Adaptive Mario. Because small changes to the scoring weights can make a great difference in determining which level-building rules are ultimately invoked, better tuning of these parameters is vital. Consequently, this package would benefit greatly from use of Artificial Neural Networks or Bayesian Inference to discover more accurate scoring values.
|
||||||
|
|
||||||
\section*{Conclusion}
|
\section*{Conclusion}
|
||||||
It seems clear from the results that the framework of Adaptive Mario has the potential to guide the player toward his or her own idealized version of a platform game, while still presenting a reasonable level of challenge. Not only does difficulty scale in proportion to the player's performance (preventing frustration), but care is taken in the design of the level grammar to avoid repeatedly giving the player 'more of the same' (leading to boredom). One potential issue exists, however - it is possible that some players simply are not fans of the platform jumper genre!
|
It seems clear from the results that the framework of Adaptive Mario has the potential to guide the player toward his or her own idealized version of a platform game, while still presenting a reasonable level of challenge. Not only does difficulty scale in proportion to the player's performance (preventing frustration), but care is taken in the design of the level grammar to avoid repeatedly giving the player 'more of the same' (leading to boredom). One potential issue exists, however - it is possible that some players simply are not fans of the platform jumper genre!
|
||||||
|
|||||||
@@ -30,8 +30,15 @@
|
|||||||
|
|
||||||
@MISC{bartle,
|
@MISC{bartle,
|
||||||
AUTHOR = "Richard Bartle",
|
AUTHOR = "Richard Bartle",
|
||||||
TITLE = "Hearts, {Clubs}, {Diamonds}, {Spades}: {Players Who} suit {MUDs}",
|
TITLE = "Hearts, Clubs, Diamonds, Spades: Players Who suit {MUDs}",
|
||||||
HOWPUBLISHED = "http://aigamedev.com/open/interviews/mario-ai/",
|
HOWPUBLISHED = "http://aigamedev.com/open/interviews/mario-ai/",
|
||||||
YEAR = 1996,
|
YEAR = 1996,
|
||||||
NOTE = "[Online; accessed 18-March-2012]"
|
NOTE = "[Online; accessed 18-March-2012]"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BOOK{zimmerman,
|
||||||
|
title = {Rules of Play},
|
||||||
|
author = {Salen, K. and Zimmerman, E.},
|
||||||
|
publisher = {The MIT Press},
|
||||||
|
year = 2004
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
This is pdfTeX, Version 3.1415926-2.3-1.40.12 (MiKTeX 2.9) (preloaded format=pdftex 2012.1.30) 18 MAR 2012 14:06
|
|
||||||
entering extended mode
|
|
||||||
**D:/workspace/cs8803p3/writeup/p3refs.bib
|
|
||||||
(D:/workspace/cs8803p3/writeup/p3refs.bib)
|
|
||||||
*
|
|
||||||
! Emergency stop.
|
|
||||||
<*> D:/workspace/cs8803p3/writeup/p3refs.bib
|
|
||||||
|
|
||||||
End of file on the terminal!
|
|
||||||
|
|
||||||
! ==> Fatal error occurred, no output PDF file produced!
|
|
||||||
Reference in New Issue
Block a user