Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
sas12028 committed Apr 30, 2017
2 parents 54fca15 + 606c0b0 commit a7779ca
Show file tree
Hide file tree
Showing 10 changed files with 2,652 additions and 60 deletions.
2,276 changes: 2,276 additions & 0 deletions gamesAgainstOtherAGroup.txt

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/CheckersGameState.java
Expand Up @@ -7,4 +7,6 @@ boolean isTerminal();
int winner();
void printState ();
public double[] getFeatures(int player);
public boolean isEndGame();
public double[] getEndGameFeatures(int player);
}
90 changes: 53 additions & 37 deletions src/CheckersGameState3.java
@@ -1,5 +1,6 @@
import java.util.List;
import java.util.LinkedList;
import java.util.ArrayList;

public class CheckersGameState3 implements CheckersGameState{

Expand Down Expand Up @@ -388,9 +389,9 @@ public class CheckersGameState3 implements CheckersGameState{

/* computes feature vector:
[0: piece-ratio,
1: loners,
2: safes,
3: 1*#pawns+ 2*#kings
1: loners, //toss?
2: safes, /toss?
3: 1*#pawns+ 2*#kings //toss?
4: # of moveable pawns + 2*#of moveable kings
5: aggregate distance of all pawns to promotion line
6: promotion line opening
Expand All @@ -399,6 +400,9 @@ public class CheckersGameState3 implements CheckersGameState{
9: central pieces
10: # pawns on diagonal + 2 * # kings on diagonal
11: ^ same but for the two smaller diagonals
12: bridge pattern TODO!!!
13: triangle pattern TODO
14: dog pattern TODO, also take out useless features
]
*/
private boolean king(int piece){
Expand Down Expand Up @@ -452,53 +456,53 @@ public class CheckersGameState3 implements CheckersGameState{

/* computes feature vector:
[0: piece-ratio,
1: # of moveable pawns + 2*#of moveable kings
2: num attacking pieces
3: central pieces
4: # pawns on diagonal + 2 * # kings on diagonal
5: bridge pattern
6: triangle pattern
7: dog pattern
8: opponents kings are on the side.
1: num attacking pieces
2: dist to oppon
]
*/
public double[] getEndGameFeatures(int player){
double[] features = new double[9];
double[] features = new double[3];
double total = 0.0;
double mypieces = 0.0;
ArrayList<Integer> mykingloc = new ArrayList<Integer>();
ArrayList<Integer> opponpieceloc = new ArrayList<Integer>();
for(int i = 0; i<this.board.length; i++){
if(i%9!=8){ //valid square
if(this.board[i] != 0 ) total+=1.0;
/****my pieces (pawns and kings)*****/
if(myPiece(this.board[i], player)){
mypieces+=1.0;
/*****pawns features****/
if(this.board[i] == player){
if(pawn_can_move(i)) features[1] += 1.0; //moveable pawns
if(i == 10 || i == 11 || i == 14 || i == 15 || i == 19 || i == 20 || i == 23 || i ==24){
features[3] +=1.0; //central pawns
}
}
/****kings features****/
else if(this.board[i] == player+2){
if(king_can_move(i)) features[1] += 2.0; //add to aggregate distance of the kings
if(i == 10 || i == 11 || i == 14 || i == 15 || i == 19 || i == 20 || i == 23 || i ==24){
features[3] +=2.0; //central kings
if(this.board[i] != 0 ) {
total+=1.0;
if(myPiece(this.board[i], player)){
mypieces+=1.0;
if(this.board[i] == player+2){ //king
mykingloc.add(i);
}
}
else{
opponpieceloc.add(i);
}
}
}
}
}
features[0] = mypieces/total; //piece ratio
features[2] = numAttacking(player);
features[4] = numOnDiag1(player) + numOnDiag2(player);
features[5] = bridge(player);
features[6] = triangle(player);
features[7] = dog(player);
features[8] = opponKingsOnSide(player);
features[1] = numAttacking(player);
features[2] = distToOppon(mykingloc, opponpieceloc);
return features;
}

/* takes in list of all my and all my opponent's pieces locations on the board
and returns an accumulative sum of the distances between our pieces*/
private double distToOppon(ArrayList<Integer> myloc, ArrayList<Integer> opploc){
int myrow, opprow;
int sum = 0;
for(int i = 0; i< myloc.size(); i++){
myrow = (myloc.get(i)-((myloc.get(i))/9))/4;
for(int j=0; j< opploc.size(); j++){
opprow = (opploc.get(j)-((opploc.get(j))/9))/4;
sum += Math.abs(myrow - opprow);
}
}
return sum * 1.0;
}

/* number of pawns and kings on the long diagonal*/
public int numOnMainDiag(int player){
int count = 0;
Expand Down Expand Up @@ -626,7 +630,7 @@ public class CheckersGameState3 implements CheckersGameState{
}
return 0.0;
}
/* feature: triangle patter*/
/* feature: triangle pattern*/
public double triangle(int player){
if(player==2){
if((this.board[33]==2 || this.board[33]==4)
Expand Down Expand Up @@ -682,7 +686,19 @@ public class CheckersGameState3 implements CheckersGameState{
return tot;
}


public boolean isEndGame(){
int mypieces = 0, others = 0, maxPieces =3;
for(int i=0; i<board.length; i++){
if(board[i]!=0){
if(myPiece(board[i],player)) mypieces+=1;
else others+=1;
}
}
if(mypieces <= maxPieces || others <= maxPieces){
return true;
}
else return false;
}

public void printState(){
boolean leading = false;
Expand Down
63 changes: 45 additions & 18 deletions src/Learn.java
@@ -1,14 +1,24 @@
import java.util.Random;

public class Learn{
CheckersAI alpha;
CheckersAI beta;
LearningEvaluator le;
LearningEvaluator endle;
BaseEvaluator be;
BaseEvaluator endbe;

public static void main(String[] args){
LearningEvaluator le = new LearningEvaluator("../src/weights/alpha.csv");
BaseEvaluator be = new BaseEvaluator("../src/weights/beta.csv");
CheckersAI alpha = new CheckersAI(le, 1);
CheckersAI beta = new CheckersAI(be, 2);
learn(alpha, beta, le, be);

Learn learn = new Learn();
learn.learn();
}
public Learn(){
alpha = new CheckersAI(le, 1);
beta = new CheckersAI(be, 2);
le = new LearningEvaluator("../src/weights/alpha.csv");
be = new BaseEvaluator("../src/weights/beta.csv");
endle = new LearningEvaluator("../src/weights/endalpha.csv");
endbe = new BaseEvaluator("../src/weights/endbeta.csv");
}

// need to decide what to do if we are going on the wrong track
Expand All @@ -18,20 +28,23 @@ public class Learn{
// for draws, make function called is_improved that checks if piece count is greater than 4 (king is worth 2)
// for learning rate, first 30 with .1, next 30 with .05, then final 30 with .01 and see what happens

public static void learn(CheckersAI alpha, CheckersAI beta, LearningEvaluator le, BaseEvaluator be){
public void learn(){
final int num_games = 30;
final int iterations = 7;

Random rand = new Random();
for(int j = 0; j < iterations; j++){
for(int i = 1; i <= num_games; i++){ // play num_games amount of games
alpha.eval = le;
beta.eval = be;
System.out.println("playing game " + i);
int player = rand.nextInt(2) + 1; // choose which player alpha plays as
play(alpha, beta, le, player, true); // alpha and beta play a game
play(player, true); // alpha and beta play a game
le.updateWeights(learningParameter(i, num_games)); // get new weights using data from game
endle.updateWeights(learningParameter(i, num_games)); // get new weights using data from game
//le.updateWeights(.1); // get new weights using data from game
}
faceBeta(alpha, beta, le, be);
faceBeta();
}
}

Expand All @@ -46,33 +59,38 @@ public class Learn{
}
}

public static void faceBeta(CheckersAI alpha, CheckersAI beta, LearningEvaluator le, BaseEvaluator be){
public void faceBeta(){
boolean w1;
boolean w2;
CheckersGameState s;
System.out.println("facing beta");
s = new CheckersGameState3();
w1 = play(alpha, beta, le, 1, false);
w2 = play(alpha, beta, le, 2, false);
w1 = play(1, false);
w2 = play(2, false);

System.out.println("alpha won " + w1 + " " + w2);
if(w1 && w2){
System.out.println("updating beta");
le.commitWeights("../src/weights/beta.csv");
endle.commitWeights("../src/weights/endbeta.csv");
be.refreshWeights();
endbe.refreshWeights();
}
else{
be.commitWeights("../src/weights/alpha.csv");
le.refreshWeights();
endbe.commitWeights("../src/weights/endalpha.csv");
endle.refreshWeights();
}



}



public static boolean play(CheckersAI alpha, CheckersAI beta, LearningEvaluator le, int player, boolean learning){
public boolean play(int player, boolean learning){
int min_ply = 7;
int incr_ply = 0;
boolean switchedToEndGame = false;
CheckersGameState current = new CheckersGameState3();
int other = 1 - (player - 1) + 1;
alpha.setPlayer(player);
Expand All @@ -86,23 +104,32 @@ public class Learn{
Move lastmove = null;
Move secondlast = null;
while(!current.isTerminal() && same_moves <= 3 && moves <= 200){
Move next = alpha.minimax(current, 7); // get alpha's move
if(current.isEndGame() && !switchedToEndGame){
switchedToEndGame = true;
alpha.eval = endle;
beta.eval = endbe;
min_ply += incr_ply;
}
Move next = alpha.minimax(current, min_ply); // get alpha's move
moves++;
if(secondlast != null && next.toString().equals(secondlast.toString())){
same_moves++;
}
secondlast = lastmove;
lastmove = next;
if(learning){
if(learning && !switchedToEndGame){
le.addData(current.getFeatures(alpha.getPlayer()), next.getValue()); // add this moves data to the data set (the value of the state is stored in the move. there is probably a better way to do this)
}
else if(learning && switchedToEndGame){
endle.addData(current.getEndGameFeatures(alpha.getPlayer()), next.getValue());
}
current = current.result(next); // make the move
moves++;
//current.printState();
if(current.isTerminal()){ // if alpha won, then break
break;
}
current = current.result(beta.minimax(current, 7)); // beta's move
current = current.result(beta.minimax(current, min_ply)); // beta's move

}
current.printState();
Expand Down
7 changes: 5 additions & 2 deletions src/LearningEvaluator.java
@@ -1,6 +1,7 @@
import java.util.ArrayList;
import org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression;
import org.apache.commons.math3.linear.SingularMatrixException;
import org.apache.commons.math3.exception.MathIllegalArgumentException;
import java.util.Arrays;

public class LearningEvaluator extends BaseEvaluator{
Expand Down Expand Up @@ -40,9 +41,9 @@ public class LearningEvaluator extends BaseEvaluator{
System.out.println(Arrays.toString(params.get(i)));
}
//System.out.println(pars);
reg.newSampleData(vals, pars); //add data
reg.setNoIntercept(true);
try {
reg.newSampleData(vals, pars); //add data
reg.setNoIntercept(true);
double[] new_weights = reg.estimateRegressionParameters(); //get parameters
for(double x: new_weights){
if(Math.abs(x) > 100000){
Expand All @@ -57,6 +58,8 @@ public class LearningEvaluator extends BaseEvaluator{
commitWeights(this.file);
} catch(SingularMatrixException e) {
System.out.println("Matrix was singular, not updating weights");
} catch(MathIllegalArgumentException e){
System.out.println("Not enough data, not updating end game weights");
}
values.clear();
params.clear();
Expand Down
10 changes: 7 additions & 3 deletions src/RmCheckersClient.java
Expand Up @@ -49,12 +49,12 @@ public class RmCheckersClient {

public Evaluator e;
public CheckersAI ai;
public CheckersGameState currentState;
public CheckersGameState3 currentState;

public RmCheckersClient(){
_socket = openSocket();
//e = new Evaluator00();
e = new BaseEvaluator("weights/beta.csv");
e = new BaseEvaluator("weights/beta-hisotry.csv");
currentState = new CheckersGameState3();
user = _user1;
password = _password1;
Expand All @@ -63,7 +63,7 @@ public class RmCheckersClient {

public RmCheckersClient(int player, String opponent){
_socket = openSocket();
e = new BaseEvaluator("weights/beta.csv");
e = new BaseEvaluator("../src/weights/beta-history.csv");
currentState = new CheckersGameState3();
user = player==1 ? _user1 : _user2;
password = player==1 ? _password1 : _password2;
Expand Down Expand Up @@ -150,6 +150,7 @@ public class RmCheckersClient {

public void playGame(int player) {
int minPly = 8;
int maxPly = 15;
try {
String msg = readAndEcho(); // initial message
if(player == 1) { // black
Expand All @@ -161,6 +162,9 @@ public class RmCheckersClient {
readAndEcho(); // move query
}
while(currentState.actions().size()>0){
if(currentState.isEndGame() && minPly < maxPly){
minPly = maxPly;
}
currentState.printState();
Move myMove = ai.minimax(currentState, minPly);
writeMessageAndEcho(myMove.toString());
Expand Down

0 comments on commit a7779ca

Please sign in to comment.