Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(examples): Add Tic-Tac-Toe examples with AI/bots
- Loading branch information
Showing
3 changed files
with
161 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/* | ||
* Copyright 2017 The boardgame.io Authors. | ||
* | ||
* Use of this source code is governed by a MIT-style | ||
* license that can be found in the LICENSE file or at | ||
* https://opensource.org/licenses/MIT. | ||
*/ | ||
|
||
import React, { useEffect, useState } from 'react'; | ||
import { Client as PlainJSClient } from 'boardgame.io/client'; | ||
import { Client } from 'boardgame.io/react'; | ||
import { Local } from 'boardgame.io/multiplayer'; | ||
import { MCTSBot, Step } from 'boardgame.io/ai'; | ||
import TicTacToe from './game'; | ||
import Board from './board'; | ||
|
||
const App = Client({ | ||
game: TicTacToe, | ||
board: Board, | ||
debug: false, | ||
// Use Local transport for communication with bots. | ||
multiplayer: Local(), | ||
}); | ||
|
||
/** | ||
* Component that controls and runs a custom bot instance. | ||
*/ | ||
const BotControls = ({ playerID, matchID }) => { | ||
const difficulties = { | ||
easy: { | ||
iterations: 1, | ||
playoutDepth: 1, | ||
}, | ||
hard: { | ||
iterations: 1000, | ||
playoutDepth: 50, | ||
}, | ||
}; | ||
const [difficulty, setDifficulty] = useState('easy'); | ||
const [client, setClient] = useState(); | ||
|
||
// Create a plain Javascript boardgame.io client on mount. | ||
useEffect(() => { | ||
const newClient = PlainJSClient({ | ||
game: TicTacToe, | ||
debug: false, | ||
multiplayer: Local(), | ||
matchID, | ||
playerID, | ||
}); | ||
newClient.start(); | ||
setClient(newClient); | ||
// Clean up client on unmount. | ||
return () => newClient.stop(); | ||
}, []); | ||
|
||
// Update the client subscription when bot difficulty changes. | ||
useEffect(() => { | ||
if (!client) return; | ||
// Subscribe to the client with a function that will run AI on a bot | ||
// player’s turn. | ||
return client.subscribe(state => { | ||
if (!state) return; | ||
if (state.ctx.currentPlayer === playerID) { | ||
const { iterations, playoutDepth } = difficulties[difficulty]; | ||
const bot = new MCTSBot({ | ||
game: TicTacToe, | ||
enumerate: TicTacToe.ai.enumerate, | ||
iterations, | ||
playoutDepth, | ||
}); | ||
// Delay AI stepping by a tick to allow React to render before the | ||
// main thread gets blocked by AI iterations. | ||
setTimeout(() => Step(client, bot), 0); | ||
} | ||
}); | ||
}, [client, difficulty]); | ||
|
||
// Render AI difficulty toggle buttons. | ||
return ( | ||
<p> | ||
AI Difficulty:{' '} | ||
<button | ||
onClick={() => setDifficulty('easy')} | ||
disabled={difficulty === 'easy'} | ||
> | ||
Easy | ||
</button> | ||
<button | ||
onClick={() => setDifficulty('hard')} | ||
disabled={difficulty === 'hard'} | ||
> | ||
Hard | ||
</button> | ||
</p> | ||
); | ||
}; | ||
|
||
const AdvancedAI = () => { | ||
return ( | ||
<div> | ||
<h1>Advanced AI</h1> | ||
<p className="warn"> | ||
This example shows how to use a custom bot instance to play against a | ||
local player. | ||
<br /> | ||
In the future, this will be made much simpler! | ||
</p> | ||
<App playerID="0" matchID="advanced-ai" /> | ||
<BotControls playerID="1" matchID="advanced-ai" /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default AdvancedAI; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* Copyright 2017 The boardgame.io Authors. | ||
* | ||
* Use of this source code is governed by a MIT-style | ||
* license that can be found in the LICENSE file or at | ||
* https://opensource.org/licenses/MIT. | ||
*/ | ||
|
||
import React from 'react'; | ||
import { Client } from 'boardgame.io/react'; | ||
import { Local } from 'boardgame.io/multiplayer'; | ||
import { MCTSBot } from 'boardgame.io/ai'; | ||
import TicTacToe from './game'; | ||
import Board from './board'; | ||
|
||
const App = Client({ | ||
game: TicTacToe, | ||
board: Board, | ||
debug: false, | ||
multiplayer: Local({ | ||
bots: { | ||
'1': MCTSBot, | ||
}, | ||
}), | ||
}); | ||
|
||
const Bots = () => ( | ||
<div> | ||
<h1>Singleplayer vs AI</h1> | ||
<App playerID="0" matchID="single-vs-ai" /> | ||
</div> | ||
); | ||
|
||
export default Bots; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters