Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: wichtounet/tetris-ai
base: 41ce4edbaf
...
head fork: wichtounet/tetris-ai
compare: 32c3a91c06
Checking mergeability… Don't worry, you can still create the pull request.
  • 3 commits
  • 3 files changed
  • 0 commit comments
  • 1 contributor
View
14 src/code/AbstractAI.java
@@ -46,6 +46,20 @@ public void send_ready(int lastscore) {
}
protected abstract BlockPosition computeBestFit(TetrisEngine engine);
+
+ public byte[][] mockGrid(TetrisEngine ge) {
+ byte[][] mockgrid = new byte[ge.width][ge.height];
+ for (int i = 0; i < ge.width; i++) {
+ for (int j = 0; j < ge.height; j++) {
+ byte s = (byte) ge.blocks[i][j].getState();
+ if (s == 2) {
+ s = 0;
+ }
+ mockgrid[i][j] = s;
+ }
+ }
+ return mockgrid;
+ }
class AIThread extends Thread {
@Override
View
207 src/code/ReinforcementAI.java
@@ -1,6 +1,5 @@
package code;
-import static code.ProjectConstants.sleep_;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
@@ -14,26 +13,35 @@
public class ReinforcementAI extends AbstractAI {
//General informations
private static int iteration = -1;
- private static int totalScores = 0;
+ private static long totalScores = 0;
private static int maxScore = -1;
//Percentage of time where the agent explores another way
- private static final int epsilon = 7;
+ private static final float epsilon = 0.05f;
//Learning rate
- private static final float alpha = 0.8f;
+ private static final float alpha = 0.2f;
//Discount factor
private static final float lambda = 0.8f;
private static final int LEVELS = 3;//WARNING Memory usage is exponential to LEVELS
- private static final float REWARD_LESS_LEVEL = 2.5f;
- private static final float REWARD_SAME_LEVEL = 1.0f;
- private static final float REWARD_MORE_LEVEL = -4.0f;
+ private static final float BASE_VALUE = 100;
+
+ private static final float REWARD_LESS_LEVEL = 0.16f * BASE_VALUE;
+ private static final float REWARD_SAME_LEVEL = 0.0f * BASE_VALUE;
+ private static final float REWARD_MORE_LEVEL = -0.4f * BASE_VALUE;
+
+ private static final float REWARD_TOUCHING_EDGES = 0.4f * BASE_VALUE;
+ private static final float REWARD_TOUCHING_WALLS = 0.65f * BASE_VALUE;
+ private static final float REWARD_TOUCHING_FLOOR = 0.0065f * BASE_VALUE;
+
+ private static final float REWARD_HOLES = 0.0f * BASE_VALUE;
+ private static final float REWARD_BLOCKADES = 0.0f * BASE_VALUE;
//By default, the value of unknown state is the max reward
- private static final float DEFAULT_VALUE = 4 * REWARD_LESS_LEVEL;
+ private static final float DEFAULT_VALUE = 4 * BASE_VALUE;
//Random number generator
private static final Random random = new Random();
@@ -45,29 +53,100 @@ public ReinforcementAI(TetrisPanel panel) {
setThread(new AIThread());
}
+
+ private void applyAction(BlockPosition action, byte[][] mockGrid) {
+ byte[][] definition = TetrisEngine.blockdef[engine.activeblock.type][action.rot];
+
+ int h;
+ for (h = engine.height - 1;; h--) {
+ // indicator. 1: fits. 0: doesn't fit. -1: game over.
+ int fit_state = 1;
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ if (definition[j][i] >= 1) {
+ if (h + j >= engine.height) {
+ fit_state = 0;
+ } else if (h + j < 0) {
+ fit_state = -1;
+ } else {
+ if (mockGrid[i + action.bx][h + j] >= 1) {
+ fit_state = 0;
+ }
+
+ if (fit_state == 1) {
+ for (int h1 = h + j - 1; h1 >= 0; h1--) {
+ if (mockGrid[i + action.bx][h1] >= 1) {
+ fit_state = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //We don't want game over so here:
+ if (fit_state == -1) {
+ return;
+ }
+
+ //1 = found!
+ if (fit_state == 1) {
+ break;
+ }
+ }
+
+ // copy over block position
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ if (definition[j][i] == 1) {
+ mockGrid[action.bx + i][h + j] = 2;
+ }
+ }
+ }
+
+ // check for clears
+ boolean foundline;
+ do {
+ foundline = false;
+ for (int line = 0; line < mockGrid[0].length; ++line) {
+ foundline = true;
+ for (int row = 0; row < mockGrid.length; row++) {
+ if (mockGrid[row][line] == 0) {
+ foundline = false;
+ break;
+ }
+ }
+
+ if(foundline){
+ if(line == 0){
+ for (int y = 0; y < mockGrid.length; y++) {
+ mockGrid[y][line] = 0;
+ }
+ } else {
+ // line line is full, clear it and copy
+ for (int a = line; a < mockGrid[0].length; ++a) {
+ for (int y = 0; y < mockGrid.length; y++) {
+ mockGrid[y][a] = mockGrid[y][a - 1];
+ }
+ }
+ }
+ }
+ }
+ } while (foundline);
+ }
class AIThread extends Thread {
@Override
public void run() {
while (flag) {
- try {
- //If it's merely paused, do nothing; if it's actually game over
- //then break loop entirely.
- if (engine.state == ProjectConstants.GameState.PLAYING) {
- if (engine.activeblock != null) {
- //System.out.println("doAction()");
- doAction(engine);
- //engine.step();
- }
- }
-
- //safety
- sleep_(waittime);
- } catch (Exception e) {
+ //try {
+ doAction(engine);
+ /*} catch (Exception e) {
//e.printStackTrace();
- //System.out.print("Aborting and retrying...\n");
- //return;
- }
+ }*/
}
}
}
@@ -98,7 +177,13 @@ protected BlockPosition computeBestFit(TetrisEngine ge) {
return null;
}
- private void doAction(TetrisEngine ge) {
+ private void doAction(TetrisEngine ge) {
+ /*try {
+ Thread.sleep(50);
+ } catch (InterruptedException ex) {
+ Logger.getLogger(ReinforcementAI.class.getName()).log(Level.SEVERE, null, ex);
+ }*/
+
//Compute the current state
State state = computeState(ge.blocks);
@@ -108,11 +193,70 @@ private void doAction(TetrisEngine ge) {
//Warning: Top and Max level are not the same
int maxLevel = getMaxLevel(ge.blocks);
- //Do the action
- movehere(action.bx, action.rot);
+ //Apply the action on a copy of the world
+ byte[][] mockGrid = mockGrid(ge);
+ applyAction(action, mockGrid);
float reward = 0;
+ //horizontal pairs
+ for (int i = 0; i < ge.height; i++) {
+ if (mockGrid[0][i] == 2) {
+ reward += REWARD_TOUCHING_WALLS;
+ }
+
+ if (mockGrid[ge.width - 1][i] == 2) {
+ reward += REWARD_TOUCHING_WALLS;
+ }
+
+ for (int j = 0; j < ge.width - 1; j++) {
+ if (mockGrid[j][i] + mockGrid[j + 1][i] >= 3) {
+ reward += REWARD_TOUCHING_EDGES;
+ }
+ }
+ }
+
+ //vertical pairs
+ for (int i = 0; i < ge.width; i++) {
+ if (mockGrid[i][ge.height - 1] == 2) {
+ reward += REWARD_TOUCHING_FLOOR;
+ }
+
+ for (int j = 0; j < ge.height - 1; j++) {
+ if (mockGrid[i][j] + mockGrid[i][j + 1] >= 3) {
+ reward += REWARD_TOUCHING_EDGES;
+ }
+ }
+ }
+
+ //Penalize holes. Also penalize blocks above holes.
+ for (int i = 0; i < ge.width; i++) {
+ // Part 1: Count how many holes (space beneath blocks)
+ boolean f = false;
+ for (int j = 0; j < ge.height; j++) {
+ if (mockGrid[i][j] > 0) {
+ f = true;
+ }
+ if (f && mockGrid[i][j] == 0) {
+ reward += REWARD_HOLES;
+ }
+ }
+
+ // Part 2: Count how many blockades (block above space)
+ f = false;
+ for (int j = ge.height - 1; j >= 0; j--) {
+ if (mockGrid[i][j] == 0) {
+ f = true;
+ }
+ if (f && mockGrid[i][j] > 0) {
+ reward += REWARD_BLOCKADES;
+ }
+ }
+ }
+
+ //Do the action
+ movehere(action.bx, action.rot);
+
//Reward difference in level
int diffLevel = getMaxLevel(ge.blocks) - maxLevel;
if(diffLevel < 0){
@@ -122,10 +266,7 @@ private void doAction(TetrisEngine ge) {
} else {
reward += diffLevel * REWARD_MORE_LEVEL;
}
-
- //TODO HOLES
- //TODO EDGES
-
+
//Compute the new state
State nextState = computeState(ge.blocks);
BlockPosition nextAction = getAction(ge, nextState);
@@ -193,7 +334,7 @@ private BlockPosition getAction(TetrisEngine ge, State state) {
BlockPosition action = null;
- if(random.nextInt(100) < epsilon){
+ if(random.nextDouble() <= epsilon){
//Explore a random action
action = posfits.get(random.nextInt(posfits.size()));
} else {
View
11 src/code/TetrisAI.java
@@ -60,16 +60,7 @@ protected BlockPosition computeBestFit(TetrisEngine ge) {
// after each iteration is too much of a hassle.
// This copies the grid.
- byte[][] mockgrid = new byte[ge.width][ge.height];
- for (int i = 0; i < ge.width; i++) {
- for (int j = 0; j < ge.height; j++) {
- byte s = (byte) ge.blocks[i][j].getState();
- if (s == 2) {
- s = 0;
- }
- mockgrid[i][j] = s;
- }
- }
+ byte[][] mockgrid = mockGrid(ge);
int cleared = 0;
for (int block = 1; block <= 2; block++) {

No commit comments for this range

Something went wrong with that request. Please try again.