Skip to content

Commit

Permalink
add async mode to MCTS bot
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolodavis committed Nov 21, 2019
1 parent 7d22a47 commit f19f1de
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 16 deletions.
15 changes: 15 additions & 0 deletions src/ai/ai.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,21 @@ describe('MCTSBot', () => {
}
});

test('async mode', async () => {
const initialState = InitializeGame({ game: TicTacToe });
const bot = new MCTSBot({
seed: '0',
game: TicTacToe,
enumerate,
playerID: '0',
iterations: 10,
playoutDepth: 10,
});
bot.setOpt('async', true);
const action = await bot.play(initialState, '0');
expect(action).not.toBeUndefined();
});

describe('iterations & playout depth', () => {
test('set opts', () => {
const bot = new MCTSBot({ game: TicTacToe, enumerate: jest.fn() });
Expand Down
1 change: 1 addition & 0 deletions src/ai/bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export class Bot {
constructor({ enumerate, seed }) {
this.enumerateFn = enumerate;
this.seed = seed;
this.iterationCounter = 0;
this._opts = {};
}

Expand Down
48 changes: 37 additions & 11 deletions src/ai/mcts-bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export class MCTSBot extends Bot {
this.iterations = iterations;
this.playoutDepth = playoutDepth;

this.addOpt({
key: 'async',
initial: false,
});

this.addOpt({
key: 'iterations',
initial: typeof iterations === 'number' ? iterations : 1000,
Expand Down Expand Up @@ -195,19 +200,12 @@ export class MCTSBot extends Bot {
play(state, playerID) {
const root = this.createNode({ state, playerID });

let iterations = this.getOpt('iterations');
let numIterations = this.getOpt('iterations');
if (typeof this.iterations === 'function') {
iterations = this.iterations(state.G, state.ctx);
numIterations = this.iterations(state.G, state.ctx);
}

return new Promise(resolve => {
for (let i = 0; i < iterations; i++) {
const leaf = this.select(root);
const child = this.expand(leaf);
const result = this.playout(child);
this.backpropagate(child, result);
}

const getResult = () => {
let selectedChild = null;
for (const child of root.children) {
if (selectedChild == null || child.visits > selectedChild.visits) {
Expand All @@ -217,8 +215,36 @@ export class MCTSBot extends Bot {

const action = selectedChild && selectedChild.parentAction;
const metadata = root;
return { action, metadata };
};

resolve({ action, metadata });
return new Promise(resolve => {
const iteration = () => {
const leaf = this.select(root);
const child = this.expand(leaf);
const result = this.playout(child);
this.backpropagate(child, result);
this.iterationCounter++;
};

this.iterationCounter = 0;

if (this.getOpt('async')) {
const asyncIteration = () => {
if (this.iterationCounter < numIterations) {
iteration();
setTimeout(asyncIteration, 0);
} else {
resolve(getResult());
}
};
asyncIteration();
} else {
while (this.iterationCounter < numIterations) {
iteration();
}
resolve(getResult());
}
});
}
}
19 changes: 14 additions & 5 deletions src/client/debug/ai/Options.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,23 @@
.value {
font-weight: bold;
}
input[type='checkbox'] {
vertical-align: middle;
}
</style>

{#each Object.entries(bot.opts()) as [key, value]}
<div class="option">
<label>{key}</label>
<span class="value">{values[key]}</span>
{#if value.range}
<input type=range bind:value={values[key]} min={value.range.min} max={value.range.max} on:change={OnChange}>
{/if}
<label>{key}</label>

{#if value.range}
<span class="value">{values[key]}</span>
<input type=range bind:value={values[key]} min={value.range.min} max={value.range.max} on:change={OnChange}>
{/if}

{#if typeof value.value === 'boolean'}
<input type=checkbox bind:checked={values[key]} on:change={OnChange}>
{/if}
</div>
{/each}

0 comments on commit f19f1de

Please sign in to comment.