I made a class that would do alpha beta pruning on a binary tree of 40 degree. However there is a time limit on a single move of 30 seconds. I am to play against my professor and his opponent class. I tried going down 6 levels but I would lose. I tried going down 7 levels and I was taking too long. Is there a way to make my code run faster? If possible can you also check my logic for the alpha beta pruning part and see if I missed anything causing it to run longer than it should. I will include all classes but I only need help with the Player class since that is the only one I'm working on. Everything else is given by the professor. I want it to run faster so I can go deeper down the tree so I have an advantage and win the game. The game is won if I end up with a positive number.
Player:
import java.util.ArrayList;
public class Player {
private Tree t;
public Player(Tree t) {
this.t = t;
}
// play will take in the moves and the player (in this case the maximizer)
// and return the best possible move
public boolean play(ArrayList<Boolean> moves, boolean maxNode) {
float alpha = Float.NEGATIVE_INFINITY;
float beta = Float.POSITIVE_INFINITY;
// a will be the two possible moves that this node can take
ArrayList<Boolean> a = (ArrayList<Boolean>) moves.clone();
a.add(true);
int level = 0; // Level is how far down it would go
if (moves.size() < 14) {
level = 19 - moves.size();
} else if (moves.size() >= 14 && moves.size() < 34) {
level = 6;
} else if (moves.size() >= 34) {
level = 39 - moves.size();
}
//System.out.println(moves.size() + " " + level);
alpha = Math.max(alpha, prun(level, a, maxNode, alpha, beta));
a.remove(a.size() - 1);
float al;
al = alpha;
alpha = Float.NEGATIVE_INFINITY;
a.add(false);
alpha = Math.max(alpha, prun(level, a, maxNode, alpha, beta));
if (al > alpha) {
return true;
} else {
return false;
}
}
// prun is a recursive function that will determine alpha and beta
public float prun(int level, ArrayList<Boolean> m, boolean maxNode, float a, float b) {
if (level <= 0) {
return t.value(m);
}
level--;
ArrayList<Boolean> moves = (ArrayList<Boolean>) m.clone();
ArrayList<Boolean> moves1 = (ArrayList<Boolean>) m.clone();
// Child is all possible moves for a node.
ArrayList<ArrayList<Boolean>> child = new ArrayList<ArrayList<Boolean>>();
child.add(moves);
child.add(moves1);
child.get(0).add(true);
child.get(1).add(false);
float score;
for (ArrayList c : child) {
score = prun(level, c, !maxNode, a, b);
if (maxNode) {
if (score > a) {
a = score;
}
} else if (!maxNode) {
if (score < b) {
b = score;
}
}
if (a >= b) {
break;
}
}
if (maxNode) {
return a;
} else {
return b;
}
}
}
Tree:
import java.util.ArrayList;
import java.util.Random;
public class Tree {
public final int TOTALNODES=2097152;
public final float EPSILON=0.00001f;
public final float distribution=10.0f;
public long randomSeed=0L;
public float[] topTree=new float[TOTALNODES];
private Random r=new Random();
public long height=40;
public Tree(long rs) {
randomSeed=rs;
r.setSeed(randomSeed);
topTree[0]=topTree[1]=0.0f;
int current=2; int levelNodes=2; float factor=1.0f;
while (current<TOTALNODES) {
for (int i=0; i<levelNodes; i++) {
int parent=current/2;
float sign=0.0f;
if (r.nextBoolean()&&r.nextBoolean())
if (topTree[parent]>EPSILON) sign=1.0f; else sign=-1.0f;
else if (topTree[parent]>EPSILON) sign=-1.0f; else sign=1.0f;
float offset=((Math.abs(topTree[parent])<EPSILON)?(r.nextFloat()*2.0f*distribution-distribution):(r.nextFloat()*distribution*factor*sign));
topTree[current]=topTree[parent]+offset;
current++; }
levelNodes*=2; factor*=0.9f; }
}
public float value(ArrayList<Boolean> moves) {
// low and high will both be values between 0 and 2^21-1=TOTALNODES.
// The depth will be the number of bits examined, starting with the low order bit of the low int.
// A depth of 0 will indicate the root.
int position=1;
for (int i=0; i<Math.min(20, moves.size()); i++) {
if (moves.get(i).booleanValue()) position=position*2+1; else position*=2; }
if (moves.size()<=20) return topTree[position];
r.setSeed(randomSeed+position);
float[] bottomTree=new float[TOTALNODES];
bottomTree[0]=bottomTree[1]=topTree[position];
int current=2; int levelNodes=2; float factor=0.12157665459056928801f;
while (current<TOTALNODES) {
for (int i=0; i<levelNodes; i++) {
int parent=current/2;
float sign=0.0f;
if (r.nextBoolean()&&r.nextBoolean())
if (bottomTree[parent]>EPSILON) sign=1.0f; else sign=-1.0f;
else if (bottomTree[parent]>EPSILON) sign=-1.0f; else sign=1.0f;
float offset=((Math.abs(bottomTree[parent])<EPSILON)?(r.nextFloat()*2.0f*distribution-distribution):(r.nextFloat()*distribution*factor*sign));
bottomTree[current]=bottomTree[parent]+offset;
current++; }
levelNodes*=2; factor*=0.9f; }
position=1;
for (int i=20; i<moves.size(); i++) {
if (moves.get(i).booleanValue()) position=position*2+1; else position*=2; }
return bottomTree[position];
}
}
Main:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
final long randomSeed=564715140;
Tree t=new Tree(randomSeed);
ArrayList<Boolean> moves=new ArrayList<Boolean>();
Player player=new Player(t);
Opponent other=new Opponent(t);
int turn=0;
for (int i=0; i<t.height; i++) {
long before=System.currentTimeMillis();
boolean maxNode=(turn==0);
Boolean newMove=((maxNode)?player.play(moves, maxNode):other.play(moves, maxNode));
if (newMove==null) throw new RuntimeException("No decision made.");
moves.add(newMove);
long after=System.currentTimeMillis();
if ((after-before)>30000) {
if (maxNode) System.out.println("The maximizer took too long: "+(after-before));
else System.out.println("The minimizer took too long: "+(after-before));
System.exit(0); }
System.out.println("Time: "+(after-before));
turn=1-turn;
}
System.out.println("Final score: "+t.value(moves));
}
}
Opponent: (This would be the professor's class which I don't have so I just have it return random)
import java.util.ArrayList;
public class Opponent {
private Tree t;
public Opponent(Tree t) {
this.t = t;
}
// play will take in the moves and the player (in this case the maximizer)
// and return the best possible move
public boolean play(ArrayList<Boolean> moves, boolean maxNode) {
int rand = (int)(Math.random() * 10) + 1;
return (rand%2 == 0);
}
}