-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMCTS.js
119 lines (101 loc) · 2.56 KB
/
MCTS.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
var UCTK = 1.0;
var Tree = function(position, parent, move) {
this.parent = parent;
this.player = position.turn == 'X' ? 'O' : 'X';
this.move = move;
this.wins = 0;
this.visits = 0;
this.expanded = [];
this.notExpanded = [];
if(!position.IsEndGame()) {
var board = position.board;
var that = this;
FIELDS.forEach(function(f) {
if(board[f] == 'E')
that.notExpanded.push(f);
});
}
this.Expand = function(position) {
var len = this.notExpanded.length;
var i = Math.floor(Math.random() * len);
var move = this.notExpanded[i];
this.notExpanded.splice(i, 1);
position.DoMove(move);
var tree = new Tree(position, this, move);
this.expanded.push(tree);
return tree;
};
this.GetValue = function() {
var value = this.wins / this.visits;
var explorationBonus = UCTK * Math.sqrt(Math.log(this.parent.visits) / this.visits);
value += explorationBonus;
return value;
};
this.GetMeanValue = function() {
var value = this.wins / this.visits;
return value;
};
this.Select = function() {
var len = this.expanded.length;
var selectedChild = null;
var bestValue = -OO;
for(var i = 0; i < len; ++i) {
var child = this.expanded[i];
var value = child.GetValue();
if(bestValue < value) {
bestValue = value;
selectedChild = child
}
}
return selectedChild;
};
this.BackPropagate = function(winner) {
if(winner == 'E')
this.wins += 0.5;
else if(this.player == winner)
this.wins += 1.0;
else
this.wins += 0.0;
this.visits += 1;
};
this.IsLeaf = function() {
return (this.expanded.length + this.notExpanded.length == 0);
};
this.IsFullyExapnded = function() {
return (this.notExpanded.length == 0);
};
};
var MAX_ITERATIONS = 100;
var MCTS = function(position) {
var rootTree = new Tree(position, null, null);
for(var i = 1; i <= MAX_ITERATIONS; ++i) {
if(i%100 == 0)
console.log('iteration = ' + i);
var tree = rootTree;
var tmpPosition = position.GetCopy();
//Selection
while(tree.IsFullyExapnded() && !tree.IsLeaf()) {
tree = tree.Select();
tmpPosition.DoMove(tree.move);
}
//Expansion
if(!tree.IsLeaf()) {
tree = tree.Expand(tmpPosition);
}
//playout
while(!tmpPosition.IsEndGame()) {
tmpPosition.DoMove(tmpPosition.GetRandomMove());
}
//backpropagation
var winner = tmpPosition.winner;
while(tree != null) {
tree.BackPropagate(winner);
tree = tree.parent;
}
}
var selected = rootTree.Select();
var bestMove = selected.move;
var bestValue = selected.GetMeanValue();
var bestVisits = selected.visits;
return [bestMove, bestValue, bestVisits];
};