From d6398c6d504fc5f65c547abe27e7305fd4eddfcb Mon Sep 17 00:00:00 2001 From: Martin Bohman Date: Thu, 16 Apr 2015 22:38:08 +0800 Subject: [PATCH 1/6] play several games at the end --- Genetic.java | 4 ++++ PlayerSkeleton.java | 51 ++++++++++++++++++++++++--------------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/Genetic.java b/Genetic.java index a7e7d49..76a28a9 100644 --- a/Genetic.java +++ b/Genetic.java @@ -25,10 +25,14 @@ public static Individual procreate(Individual i1, Individual i2) { public void mutate() { double stdDev = 0.3; // std dev for random multiplication and scale factor double scale = 0.5*stdDev*r.nextGaussian()+1.0; + double flipChance = 0.10; // double scale = 1; for (int i = 0; i < chromosomes.length; i++) { int chr = chromosomes[i]; int mutated = (int) ((double) Math.round(chr * (stdDev*r.nextGaussian()+1.0) * scale) ); + // if(r.nextDouble() < flipChance) { + // mutated = -mutated; + // } chromosomes[i] = mutated; } } diff --git a/PlayerSkeleton.java b/PlayerSkeleton.java index 5d0b03c..8315d2f 100644 --- a/PlayerSkeleton.java +++ b/PlayerSkeleton.java @@ -62,12 +62,12 @@ public static Weights martinWeights() { } public static Weights someWeights() { - Weights w = new Weights(); // [239][-2][116][39][53] - w.numHoles = 239; - w.maxHeight = -2; - w.rowsCleared = 116; - w.colHeights = 39; - w.adjColHeightDiffs = 53; + Weights w = new Weights(); // [169][23][-153][10][48] + w.numHoles = 169; + w.maxHeight = 23; + w.rowsCleared = -153; + w.colHeights = 10; + w.adjColHeightDiffs = 48; return w; } @@ -315,31 +315,34 @@ public static int randomWithRange(int min, int max) { public static void main(String[] args) { State s = new State(); - TFrame tFrame = new TFrame(s); - Genetic gen = new Genetic(10, State.ROWS-10, State.COLS); Weights w = gen.train(25); // Number of generations // Weights w = Weights.jacobWeights(); // Weights w = Weights.martinWeights(); // Weights w = Weights.someWeights(); - PlayerSkeleton p = new PlayerSkeleton(w, State.ROWS, State.COLS); - - while(!s.hasLost()) { - int move = p.pickMove(s.legalMoves(), s.getNextPiece()); - p.gameSim.simMove(move, s.getNextPiece()); - s.makeMove(move); - // s.draw(); - tFrame.setScoreLabel(s.getRowsCleared()); - // s.drawNext(0,0); - - // try { - // Thread.sleep(00); - // } catch (InterruptedException e) { - // e.printStackTrace(); - // } - } + for(int i = 0; i<3; i++) { + s = new State(); + TFrame tFrame = new TFrame(s); + PlayerSkeleton p = new PlayerSkeleton(w, State.ROWS, State.COLS); + p.forwardLooking = true; + + while(!s.hasLost()) { + int move = p.pickMove(s.legalMoves(), s.getNextPiece()); + p.gameSim.simMove(move, s.getNextPiece()); + s.makeMove(move); + // s.draw(); + tFrame.setScoreLabel(s.getRowsCleared()); + // s.drawNext(0,0); + + // try { + // Thread.sleep(00); + // } catch (InterruptedException e) { + // e.printStackTrace(); + // } + } System.out.println("You have completed "+s.getRowsCleared()+" rows."); + } } } From 0dc76ee659d6abd429d2c1747317c08971932fc6 Mon Sep 17 00:00:00 2001 From: Martin Bohman Date: Fri, 17 Apr 2015 11:57:35 +0800 Subject: [PATCH 2/6] added new heuristics (wells, row transitions and column transitions) --- PlayerSkeleton.java | 115 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 104 insertions(+), 11 deletions(-) diff --git a/PlayerSkeleton.java b/PlayerSkeleton.java index 8315d2f..93a3252 100644 --- a/PlayerSkeleton.java +++ b/PlayerSkeleton.java @@ -14,11 +14,14 @@ class Weights { public int rowsCleared; public int colHeights; public int adjColHeightDiffs; + public int rowTrans; + public int colTrans; + public int wellSums; public Weights() {} public int[] toArray() { - int[] arr = new int[5]; + int[] arr = new int[8]; int wi = 0; arr[wi++] = numHoles; @@ -26,6 +29,9 @@ public int[] toArray() { arr[wi++] = rowsCleared; arr[wi++] = colHeights; arr[wi++] = adjColHeightDiffs; + arr[wi++] = rowTrans; + arr[wi++] = colTrans; + arr[wi++] = wellSums; return arr; } @@ -38,6 +44,10 @@ public static Weights fromArray(int[] arr) { w.rowsCleared = arr[wi++]; w.colHeights = arr[wi++]; w.adjColHeightDiffs = arr[wi++]; + w.rowTrans = arr[wi++]; + w.colTrans = arr[wi++]; + w.wellSums = arr[wi++]; + return w; } @@ -61,13 +71,26 @@ public static Weights martinWeights() { return w; } + // public static Weights someWeights() { + // Weights w = new Weights(); // [169][23][-153][10][48] + // w.numHoles = 169; + // w.maxHeight = 23; + // w.rowsCleared = -153; + // w.colHeights = 10; + // w.adjColHeightDiffs = 48; + // return w; + // } + public static Weights someWeights() { - Weights w = new Weights(); // [169][23][-153][10][48] - w.numHoles = 169; - w.maxHeight = 23; - w.rowsCleared = -153; - w.colHeights = 10; - w.adjColHeightDiffs = 48; + Weights w = new Weights(); // [708][-74][136][132][27][404][425][122] + w.numHoles = 708; + w.maxHeight = -74; + w.rowsCleared = 136; + w.colHeights = 132; + w.adjColHeightDiffs = 27; + w.rowTrans = 404; + w.colTrans = 425; + w.wellSums = 122; return w; } @@ -78,12 +101,15 @@ public static Weights randomWeights() { w.rowsCleared = getRandom(); w.colHeights = getRandom(); w.adjColHeightDiffs = getRandom(); + w.rowTrans = getRandom(); + w.colTrans = getRandom(); + w.wellSums = getRandom(); return w; } public static int getRandom() { java.util.Random r = new java.util.Random(); - return r.nextInt(501)-250; + return r.nextInt(5001)-2500; } } @@ -138,6 +164,74 @@ public int getHeuristic() { for(int i = 0; i < top.length - 1; i++) sum += Math.abs(top[i] - top[i+1]) * weights.adjColHeightDiffs; + + int n_coltrans = 0; + int n_rowtrans = 0; + int n_wells = 0; + int a, b, c, d; + + // coltrans + for(int col = 0; col < cols; col++) { + for(int row = 0; row < rows-2; row++) { + a=field[row][col]; + b=field[row+1][col]; + + if( a!=0 && b==0 ) { + n_coltrans++; + }else if(a==0 && b != 0) { + n_coltrans++; + } + } + } + + // rowtrans + for(int col = 0; col < cols-1; col++) { + for(int row = 0; row < rows-1; row++) { + a=field[row][col]; + b=field[row][col+1]; + + if( a!=0 && b==0 ) { + n_rowtrans++; + }else if(a==0 && b != 0) { + n_rowtrans++; + } + } + } + + // wells (inner) + for(int col = 1; col < cols-1; col++) { + for(int row = 0; row < rows-1; row++) { + a=field[row][col-1]; + b=field[row][col]; + c=field[row][col+1]; + + if( a!=0 && b==0 && c!=0 ) { + n_wells++; + } + } + } + + // wells (edges) + for(int row = 0; row < rows-1; row++) { + a=field[row][0]; + b=field[row][1]; + + c=field[row][cols-2]; + d=field[row][cols-1]; + + if( a==0 && b!=0 ) { + n_wells++; + } + + if( c!=0 && d==0 ) { + n_wells++; + } + } + + sum += n_coltrans * weights.colTrans; + sum += n_rowtrans * weights.rowTrans; + sum += n_wells * weights.wellSums; + return sum; } @@ -316,16 +410,15 @@ public static int randomWithRange(int min, int max) { public static void main(String[] args) { State s = new State(); Genetic gen = new Genetic(10, State.ROWS-10, State.COLS); - Weights w = gen.train(25); // Number of generations + Weights w = gen.train(20); // Number of generations // Weights w = Weights.jacobWeights(); // Weights w = Weights.martinWeights(); // Weights w = Weights.someWeights(); - for(int i = 0; i<3; i++) { + for(int i = 0; i<20; i++) { s = new State(); TFrame tFrame = new TFrame(s); PlayerSkeleton p = new PlayerSkeleton(w, State.ROWS, State.COLS); - p.forwardLooking = true; while(!s.hasLost()) { int move = p.pickMove(s.legalMoves(), s.getNextPiece()); From d1a52ed100c506b179e02128e1335afd7c2cf2f8 Mon Sep 17 00:00:00 2001 From: Martin Bohman Date: Fri, 17 Apr 2015 20:14:31 +0800 Subject: [PATCH 3/6] Switch loop order --- PlayerSkeleton.java | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/PlayerSkeleton.java b/PlayerSkeleton.java index 93a3252..cc5b499 100644 --- a/PlayerSkeleton.java +++ b/PlayerSkeleton.java @@ -94,6 +94,19 @@ public static Weights someWeights() { return w; } + // public static Weights someWeights() { + // Weights w = new Weights(); // [10978][4024][-432][2][1680][11][925][5396] + // w.numHoles = 10978; + // w.maxHeight = 4024; + // w.rowsCleared = -432; + // w.colHeights = 2; + // w.adjColHeightDiffs = 1680; + // w.rowTrans = 11; + // w.colTrans = 925; + // w.wellSums = 5396; + // return w; + // } + public static Weights randomWeights() { Weights w = new Weights(); w.numHoles = getRandom(); @@ -171,8 +184,8 @@ public int getHeuristic() { int a, b, c, d; // coltrans - for(int col = 0; col < cols; col++) { - for(int row = 0; row < rows-2; row++) { + for(int row = 0; row < rows-2; row++) { + for(int col = 0; col < cols; col++) { a=field[row][col]; b=field[row+1][col]; @@ -185,8 +198,8 @@ public int getHeuristic() { } // rowtrans - for(int col = 0; col < cols-1; col++) { - for(int row = 0; row < rows-1; row++) { + for(int row = 0; row < rows-1; row++) { + for(int col = 0; col < cols-1; col++) { a=field[row][col]; b=field[row][col+1]; @@ -199,8 +212,8 @@ public int getHeuristic() { } // wells (inner) - for(int col = 1; col < cols-1; col++) { - for(int row = 0; row < rows-1; row++) { + for(int row = 0; row < rows-1; row++) { + for(int col = 1; col < cols-1; col++) { a=field[row][col-1]; b=field[row][col]; c=field[row][col+1]; @@ -409,12 +422,12 @@ public static int randomWithRange(int min, int max) { public static void main(String[] args) { State s = new State(); - Genetic gen = new Genetic(10, State.ROWS-10, State.COLS); - Weights w = gen.train(20); // Number of generations + // Genetic gen = new Genetic(10, State.ROWS-10, State.COLS); + // Weights w = gen.train(20); // Number of generations // Weights w = Weights.jacobWeights(); // Weights w = Weights.martinWeights(); - // Weights w = Weights.someWeights(); + Weights w = Weights.someWeights(); for(int i = 0; i<20; i++) { s = new State(); TFrame tFrame = new TFrame(s); From aba29a71f5a74c668ee31cad309e46e515bef01a Mon Sep 17 00:00:00 2001 From: Martin Bohman Date: Fri, 17 Apr 2015 20:57:13 +0800 Subject: [PATCH 4/6] optimization --- PlayerSkeleton.java | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/PlayerSkeleton.java b/PlayerSkeleton.java index cc5b499..d6db09a 100644 --- a/PlayerSkeleton.java +++ b/PlayerSkeleton.java @@ -184,8 +184,8 @@ public int getHeuristic() { int a, b, c, d; // coltrans - for(int row = 0; row < rows-2; row++) { - for(int col = 0; col < cols; col++) { + for(int col = 0; col < cols; col++) { + for(int row = 0; row < top[col]; row++) { a=field[row][col]; b=field[row+1][col]; @@ -197,22 +197,8 @@ public int getHeuristic() { } } - // rowtrans - for(int row = 0; row < rows-1; row++) { - for(int col = 0; col < cols-1; col++) { - a=field[row][col]; - b=field[row][col+1]; - - if( a!=0 && b==0 ) { - n_rowtrans++; - }else if(a==0 && b != 0) { - n_rowtrans++; - } - } - } - - // wells (inner) - for(int row = 0; row < rows-1; row++) { + // rowtrans and wells (inner) + for(int row = 0; row < maxHeight; row++) { for(int col = 1; col < cols-1; col++) { a=field[row][col-1]; b=field[row][col]; @@ -221,11 +207,15 @@ public int getHeuristic() { if( a!=0 && b==0 && c!=0 ) { n_wells++; } + + if( b!=0 && c==0 ) { + n_rowtrans++; + }else if(b==0 && c != 0) { + n_rowtrans++; + } } - } - // wells (edges) - for(int row = 0; row < rows-1; row++) { + // edges a=field[row][0]; b=field[row][1]; From 1a5f54f175cb282a6136d66ef922391e0bd62162 Mon Sep 17 00:00:00 2001 From: Martin Bohman Date: Fri, 17 Apr 2015 21:55:01 +0800 Subject: [PATCH 5/6] divided 50k weights by 10 --- PlayerSkeleton.java | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/PlayerSkeleton.java b/PlayerSkeleton.java index d6db09a..8823e9a 100644 --- a/PlayerSkeleton.java +++ b/PlayerSkeleton.java @@ -94,18 +94,18 @@ public static Weights someWeights() { return w; } - // public static Weights someWeights() { - // Weights w = new Weights(); // [10978][4024][-432][2][1680][11][925][5396] - // w.numHoles = 10978; - // w.maxHeight = 4024; - // w.rowsCleared = -432; - // w.colHeights = 2; - // w.adjColHeightDiffs = 1680; - // w.rowTrans = 11; - // w.colTrans = 925; - // w.wellSums = 5396; - // return w; - // } + public static Weights fiftyKWeights() { + Weights w = new Weights(); // [10978][4024][-432][2][1680][11][925][5396] + w.numHoles = 10978/10; + w.maxHeight = 4024/10; + w.rowsCleared = -432/10; + w.colHeights = 2/10; + w.adjColHeightDiffs = 1680/10; + w.rowTrans = 11/10; + w.colTrans = 925/10; + w.wellSums = 5396/10; + return w; + } public static Weights randomWeights() { Weights w = new Weights(); @@ -417,7 +417,8 @@ public static void main(String[] args) { // Weights w = Weights.jacobWeights(); // Weights w = Weights.martinWeights(); - Weights w = Weights.someWeights(); + // Weights w = Weights.someWeights(); + Weights w = Weights.fiftyKWeights(); for(int i = 0; i<20; i++) { s = new State(); TFrame tFrame = new TFrame(s); From b60eb0dc8aaac50066307cea87bce7a1922aa628 Mon Sep 17 00:00:00 2001 From: Martin Bohman Date: Sat, 18 Apr 2015 18:33:22 +0800 Subject: [PATCH 6/6] change to doubles, WORKS WELL --- Genetic.java | 8 +++---- PlayerSkeleton.java | 54 ++++++++++++++++++++++----------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Genetic.java b/Genetic.java index 76a28a9..e14ec02 100644 --- a/Genetic.java +++ b/Genetic.java @@ -1,6 +1,6 @@ class Individual { public int fitness, cols; - public int[] chromosomes; + public double[] chromosomes; private static int MUCHANCE = 20; java.util.Random r; @@ -28,8 +28,8 @@ public void mutate() { double flipChance = 0.10; // double scale = 1; for (int i = 0; i < chromosomes.length; i++) { - int chr = chromosomes[i]; - int mutated = (int) ((double) Math.round(chr * (stdDev*r.nextGaussian()+1.0) * scale) ); + double chr = chromosomes[i]; + double mutated = chr * (stdDev*r.nextGaussian()+1.0) * scale; // if(r.nextDouble() < flipChance) { // mutated = -mutated; // } @@ -40,7 +40,7 @@ public void mutate() { public void print(int num) { System.out.format("%d Fitness: %d - Chromosomes: ", num, fitness); for (int i = 0; i < chromosomes.length; i++) - System.out.format("[%d]", chromosomes[i]); + System.out.format("[%f]", chromosomes[i]); System.out.format("\n"); } } diff --git a/PlayerSkeleton.java b/PlayerSkeleton.java index 8823e9a..295d989 100644 --- a/PlayerSkeleton.java +++ b/PlayerSkeleton.java @@ -9,19 +9,19 @@ public static int[][] getLegalMoves(int piece) { } class Weights { - public int numHoles; - public int maxHeight; - public int rowsCleared; - public int colHeights; - public int adjColHeightDiffs; - public int rowTrans; - public int colTrans; - public int wellSums; + public double numHoles; + public double maxHeight; + public double rowsCleared; + public double colHeights; + public double adjColHeightDiffs; + public double rowTrans; + public double colTrans; + public double wellSums; public Weights() {} - public int[] toArray() { - int[] arr = new int[8]; + public double[] toArray() { + double[] arr = new double[8]; int wi = 0; arr[wi++] = numHoles; @@ -35,7 +35,7 @@ public int[] toArray() { return arr; } - public static Weights fromArray(int[] arr) { + public static Weights fromArray(double[] arr) { Weights w = new Weights(); int wi = 0; @@ -96,14 +96,14 @@ public static Weights someWeights() { public static Weights fiftyKWeights() { Weights w = new Weights(); // [10978][4024][-432][2][1680][11][925][5396] - w.numHoles = 10978/10; - w.maxHeight = 4024/10; - w.rowsCleared = -432/10; - w.colHeights = 2/10; - w.adjColHeightDiffs = 1680/10; - w.rowTrans = 11/10; - w.colTrans = 925/10; - w.wellSums = 5396/10; + w.numHoles = 10.978; + w.maxHeight = 4.024; + w.rowsCleared = -0.432; + w.colHeights = 0.002; + w.adjColHeightDiffs = 1.680; + w.rowTrans = 0.011; + w.colTrans = 0.925; + w.wellSums = 5.396; return w; } @@ -120,7 +120,7 @@ public static Weights randomWeights() { return w; } - public static int getRandom() { + public static double getRandom() { java.util.Random r = new java.util.Random(); return r.nextInt(5001)-2500; } @@ -146,7 +146,7 @@ class Simulator // - Column Heights // - Holes // - Cleared - public int heuristic; + public double heuristic; public Simulator(Simulator sim) { this(sim.rows, sim.cols, sim.weights); @@ -171,8 +171,8 @@ public void revertTo(Simulator sim) { maxHeight = sim.maxHeight; } - public int getHeuristic() { - int sum = heuristic; + public double getHeuristic() { + double sum = heuristic; for(int i = 0; i < top.length - 1; i++) sum += Math.abs(top[i] - top[i+1]) * weights.adjColHeightDiffs; @@ -347,14 +347,14 @@ public int playAndReturnScore() { return gameSim.rowsCleared; } - private int forwardLookAvg(Simulator s, int maxdepth) { - int average = 0; + private double forwardLookAvg(Simulator s, int maxdepth) { + double average = 0; Simulator sim = new Simulator(s); // For all possible pieces for (int piece = 0; piece < State.N_PIECES; piece++) { int numMoves = Moves.getNumMoves(piece); - int pieceBestHeu = Integer.MAX_VALUE; + double pieceBestHeu = Double.MAX_VALUE; // Try all possible moves for piece for (int move = 0; move < numMoves; move++) { @@ -362,7 +362,7 @@ private int forwardLookAvg(Simulator s, int maxdepth) { if (!sim.simMove(move, piece)) continue; - int heu; + double heu; if (maxdepth != 1) heu = forwardLookAvg(sim, maxdepth - 1); else