The problem
MCTS (Monte Carlo tree search) finds a good first move by trying things out: it builds a tree of positions, plays many random games to the end, and puts more effort where the results look promising. You will implement it for a single-player problem described by three functions:
actions(state): the list of legal actions, empty whenstateis terminal (the end);step(state, action): the next state;reward(state): the final reward of a terminal state, between 0 and 1.
The balance: UCT
At every node, the question is which child to explore next: the one with the best results so far (exploitation), or one tried only a few times, which might be better than it looks (exploration)? The UCT (Upper Confidence bounds applied to Trees) score balances them:
where is the total reward collected through the child, its number of visits (so is its average reward), the visits of its parent, the natural logarithm and a constant (such as 1.4). A child with has score float("inf"): every child is tried once.
Example. A parent visited 10 times, .
- Child A: , : .
- Child B: , : .
B has the lower average but is selected: it has only been tried twice. Implement this as
uct(W, N, N_parent, c).
The four phases
Keep, for every node, its visit count , its total reward , its children (by action) and its untried actions. Repeat n_iter times:
- Selection: from the root, while the node has no untried actions and is not terminal, move to the child with the highest
uct(the first in action order on a tie). - Expansion: if the node has untried actions, take the first one, create its child, and move to it.
- Simulation: from the new node's state, play random actions,
acts[rng.integers(len(acts))], until a terminal state, and take itsreward. - Backpropagation: add 1 to and the reward to of every node on the path from the root to the new node, root included.
Return the root action whose child has the most visits (the first in action order on a tie).
Example. The root has two actions,
a(leads to the end with reward 0) andb(reward 1).
- Iteration 1: the root has untried actions
aandb; expansion takes the first,a. It is terminal: reward 0. Root: , ; childa: , .- Iteration 2: the root still has an untried action: expansion takes
b, reward 1. Root: , ; childb: , .- Iteration 3: no untried actions. , :
bis selected.- After a few more iterations
bhas most of the visits:mctsreturns"b".
What to implement
uct(W, N, N_parent, c): the score above, orfloat("inf")if .mcts(root, actions, step, reward, n_iter, c, rng): the search, returning the best root action.
Requirements
- Untried actions are tried in the order
actions(state)returns them. - Use
rngonly in the simulation, exactly as described.