/* same as on main page, but translated to java */
class Node { public int wins=0; public int visits=0;
public Move move=null;
public Node bestNode=null;
public Node child=null; public Node sibling=null;
public void setBest() { Node next = child; Node best = null; double best_winrate=-1; double winrate; // 0..1 while (next!=null) { // for all children winrate = next.wins / next.visits; if (winrate>best_winrate) best=next; next = next.sibling; } bestNode=best; } }
class Board { /* BEGIN CLASS */
double UCTK = 1; // Larger values give uniform search // Smaller values give very selective search
Board clone;
public Node UCTSelect(Node node) { Node res=null; Node next = node.child; double best_uct=0; double winrate; double uct; double uctvalue;
while (next!=null) { // for all children if (next.visits > 0) { winrate = next.wins / next.visits; uct = UCTK * Math.sqrt( Math.log(node.visits) / (5*next.visits) ); uctvalue = winrate + uct; } else { // Always play a random unexplored move first uctvalue = 10000 + 1000*Math.random(); }
if (uctvalue > best_uct) { // get max uctvalue of all children best_uct = uctvalue; res = next; }
next = next.sibling; } return res; }
int randomresult=0;
void playSimulation(Node n) { if (n.visits==0) { // node exists, but no evaluation done yet (for this node) randomresult = clone.playRandomGame(); } else { if (n.child == null) createChildren(n);
Node next = UCTSelect(n); // select a move
clone.makeMove(next.move); playSimulation(next); }
n.visits++; updateWin(n, randomresult);
if (n.child!=null) n.setBest(); }
Move UCTSearch(int numsim) { for (int i=0;i<numsim;i++) { clone.copyStateFrom(this); playSimulation(root); }
return root.bestNode.move; }
// NOT IMPLEMENTED YET:
void makeMove(Move m) {
}
void copyStateFrom(Board b) {
}
void createChildren(Node n) {
}
int playRandomGame() { return 0; // or 1 }
void updateWin(Node n, int randomresult) { if (randomresult==1) n.wins++; } } /* END CLASS */