diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js index 4aade5303..90b059e6d 100644 --- a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js +++ b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js @@ -32,6 +32,7 @@ var EXAMPLES = { 'Basic': require('./NavigationBasicExample'), 'Animated Card Stack': require('./NavigationAnimatedExample'), 'Composition': require('./NavigationCompositionExample'), + 'Tic Tac Toe': require('./NavigationTicTacToeExample'), }; var EXAMPLE_STORAGE_KEY = 'NavigationExampleExample'; diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js new file mode 100644 index 000000000..898599ad5 --- /dev/null +++ b/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js @@ -0,0 +1,303 @@ +/** + * The examples provided by Facebook are for non-commercial testing and + * evaluation purposes only. + * + * Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * @providesModule NavigationTicTacToeExample + * @flow + */ +'use strict'; + +var React = require('react-native'); +var { + // $FlowFixMe : this does exist.. + NavigationExperimental, + StyleSheet, + Text, + TouchableHighlight, + View, +} = React; +const { + Container: NavigationContainer, + RootContainer: NavigationRootContainer, +} = NavigationExperimental; + +type GameGrid = Array>; + +const evenOddPlayerMap = ['o', 'x']; +const rowLeterMap = ['a', 'b', 'c']; + +function parseGame(game: string): GameGrid { + const gameTurns = game ? game.split('-') : []; + const grid = Array(3); + for (let i = 0; i < 3; i++) { + const row = Array(3); + for (let j = 0; j < 3; j++) { + const turnIndex = gameTurns.indexOf(rowLeterMap[i]+j); + if (turnIndex === -1) { + row[j] = null; + } else { + row[j] = evenOddPlayerMap[turnIndex % 2]; + } + } + grid[i] = row; + } + return grid; +} + +function playTurn(game: string, row: number, col: number): string { + const turn = rowLeterMap[row] + col; + return game ? (game + '-' + turn) : turn; +} + +function getWinner(gameString: string): ?string { + const game = parseGame(gameString); + for (var i = 0; i < 3; i++) { + if (game[i][0] !== null && game[i][0] === game[i][1] && + game[i][0] === game[i][2]) { + return game[i][0]; + } + } + for (var i = 0; i < 3; i++) { + if (game[0][i] !== null && game[0][i] === game[1][i] && + game[0][i] === game[2][i]) { + return game[0][i]; + } + } + if (game[0][0] !== null && game[0][0] === game[1][1] && + game[0][0] === game[2][2]) { + return game[0][0]; + } + if (game[0][2] !== null && game[0][2] === game[1][1] && + game[0][2] === game[2][0]) { + return game[0][2]; + } + return null; +} + +function isGameOver(gameString: string): boolean { + if (getWinner(gameString)) { + return true; + } + const game = parseGame(gameString); + for (var i = 0; i < 3; i++) { + for (var j = 0; j < 3; j++) { + if (game[i][j] === null) { + return false; + } + } + } + return true; +} + +class Cell extends React.Component { + cellStyle() { + switch (this.props.value) { + case 'x': + return styles.cellX; + case 'o': + return styles.cellO; + default: + return null; + } + } + textStyle() { + switch (this.props.value) { + case 'x': + return styles.cellTextX; + case 'o': + return styles.cellTextO; + default: + return {}; + } + } + render() { + return ( + + + + {this.props.player} + + + + ); + } +} + +function GameEndOverlay(props) { + if (!isGameOver(props.game)) { + return ; + } + const winner = getWinner(props.game); + return ( + + + {winner ? winner + ' wins!' : 'It\'s a tie!'} + + props.onNavigate(GameActions.Reset())} + underlayColor="transparent" + activeOpacity={0.5}> + + New Game + + + + ); +} +GameEndOverlay = NavigationContainer.create(GameEndOverlay); + +function TicTacToeGame(props) { + var rows = parseGame(props.game).map((cells, row) => + + {cells.map((player, col) => + props.onNavigate(GameActions.Turn(row, col))} + /> + )} + + ); + return ( + + EXTREME T3 + + {rows} + + + + ); +} +TicTacToeGame = NavigationContainer.create(TicTacToeGame); + +const GameActions = { + Turn: (row, col) => ({gameAction: 'turn', row, col }), + Reset: (row, col) => ({gameAction: 'reset' }), +}; + +function GameReducer(lastGame: ?string, action: Object): string { + if (!lastGame || !action || !action.gameAction) { + return lastGame || ''; + } + if (action.gameAction === 'reset') { + return ''; + } + if (!isGameOver(lastGame) && action.gameAction === 'turn') { + return playTurn(lastGame, action.row, action.col); + } + return lastGame; +} + +class NavigationTicTacToeExample extends React.Component { + render() { + return ( + ( + + )} + /> + ); + } +} +NavigationTicTacToeExample.GameView = TicTacToeGame; +NavigationTicTacToeExample.GameReducer = GameReducer; +NavigationTicTacToeExample.GameActions = GameActions; + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: 'white' + }, + title: { + fontFamily: 'Chalkduster', + fontSize: 39, + marginBottom: 20, + }, + board: { + padding: 5, + backgroundColor: '#47525d', + borderRadius: 10, + }, + row: { + flexDirection: 'row', + }, + cell: { + width: 80, + height: 80, + borderRadius: 5, + backgroundColor: '#7b8994', + margin: 5, + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + cellX: { + backgroundColor: '#72d0eb', + }, + cellO: { + backgroundColor: '#7ebd26', + }, + cellText: { + borderRadius: 5, + fontSize: 50, + fontFamily: 'AvenirNext-Bold', + }, + cellTextX: { + color: '#19a9e5', + }, + cellTextO: { + color: '#b9dc2f', + }, + overlay: { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + backgroundColor: 'rgba(221, 221, 221, 0.5)', + flex: 1, + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + }, + overlayMessage: { + fontSize: 40, + marginBottom: 20, + marginLeft: 20, + marginRight: 20, + fontFamily: 'AvenirNext-DemiBold', + textAlign: 'center', + }, + newGame: { + backgroundColor: '#887766', + padding: 20, + borderRadius: 5, + }, + newGameText: { + color: 'white', + fontSize: 20, + fontFamily: 'AvenirNext-DemiBold', + }, +}); + +module.exports = NavigationTicTacToeExample;