Last active
March 21, 2022 17:04
-
-
Save omept/c0cd822fe44c87290dbb0d930c0f0af8 to your computer and use it in GitHub Desktop.
React Tic Tac Toe
This file contains hidden or 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
| import React, { useState } from 'react'; | |
| import ReactDOM from 'react-dom'; | |
| const rowStyle = { | |
| display: 'flex' | |
| } | |
| const squareStyle = { | |
| 'width':'60px', | |
| 'height':'60px', | |
| 'backgroundColor': '#ddd', | |
| 'margin': '4px', | |
| 'display': 'flex', | |
| 'justifyContent': 'center', | |
| 'alignItems': 'center', | |
| 'fontSize': '20px', | |
| 'color': 'white' | |
| } | |
| const boardStyle = { | |
| 'backgroundColor': '#eee', | |
| 'width': '208px', | |
| 'alignItems': 'center', | |
| 'justifyContent': 'center', | |
| 'display': 'flex', | |
| 'flexDirection': 'column', | |
| 'border': '3px #eee solid' | |
| } | |
| const containerStyle = { | |
| 'display': 'flex', | |
| 'alignItems': 'center', | |
| 'flexDirection': 'column' | |
| } | |
| const instructionsStyle = { | |
| 'marginTop': '5px', | |
| 'marginBottom': '5px', | |
| 'fontWeight': 'bold', | |
| 'fontSize': '16px', | |
| } | |
| const buttonStyle = { | |
| 'marginTop': '15px', | |
| 'marginBottom': '16px', | |
| 'width': '80px', | |
| 'height': '40px', | |
| 'backgroundColor': '#8acaca', | |
| 'color': 'white', | |
| 'fontSize': '16px', | |
| } | |
| class Square extends React.Component { | |
| constructor(props){ | |
| super(props); | |
| } | |
| render() { | |
| return ( | |
| <div onClick={() => this.props.mark()} | |
| className="square" | |
| style={squareStyle}> | |
| {this.props.text()} | |
| </div> | |
| ); | |
| } | |
| } | |
| class Board extends React.Component { | |
| constructor(props){ | |
| super(props); | |
| this.nextPlayer = this.nextPlayer.bind(this); | |
| this.defaultTiles = this.defaultTiles.bind(this); | |
| this.state = { | |
| currentPlayer: 'X', | |
| clickCount: 0, | |
| winner: 'None', | |
| gameEnded: false, | |
| tiles: this.defaultTiles() | |
| }; | |
| } | |
| defaultTiles = () => { | |
| let row = 3; | |
| let col = 3; | |
| let tiles= new Array(row); | |
| for(let j =0; j<row; j++){ | |
| tiles[j] = new Array(col); | |
| } | |
| return tiles; | |
| }; | |
| markTile = (i,j) => { | |
| let {tiles, gameEnded, currentPlayer} = this.state; | |
| if(tiles[i][j] == null && !gameEnded){ | |
| tiles[i][j] = currentPlayer; | |
| let {winner, gameEnded, clickCount} = this.evalBoard(); | |
| this.setState({ | |
| currentPlayer: this.nextPlayer(), | |
| tiles, | |
| winner, | |
| clickCount, | |
| gameEnded | |
| }); | |
| } | |
| }; | |
| evalBoard = () => { | |
| let winner = 'None'; | |
| let gameEnded = false; | |
| let {tiles, clickCount} = this.state; | |
| let playerArr = ['X', 'O']; | |
| clickCount = clickCount+1; | |
| // check the 8 conditions for game completion | |
| if((tiles[0][2] == tiles[1][2]) && (tiles[0][2] == tiles[2][2]) && playerArr.indexOf(tiles[0][2]) > -1){ | |
| winner = tiles[0][2]; | |
| gameEnded = true; | |
| }else if((tiles[0][0] == tiles[0][1]) && (tiles[0][0] == tiles[0][2]) && playerArr.indexOf(tiles[0][0]) > -1){ | |
| winner = tiles[0][0]; | |
| gameEnded = true; | |
| }else if((tiles[0][0] == tiles[1][1]) && (tiles[0][0] == tiles[2][2]) && playerArr.indexOf(tiles[0][0]) > -1){ | |
| winner = tiles[0][0]; | |
| gameEnded = true; | |
| }else if((tiles[0][0] == tiles[1][0]) && (tiles[0][0] == tiles[2][0]) && playerArr.indexOf(tiles[0][0]) > -1){ | |
| winner = tiles[0][0]; | |
| gameEnded = true; | |
| }else if((tiles[2][0] == tiles[2][1]) && (tiles[2][0] == tiles[2][2]) && playerArr.indexOf(tiles[2][0]) > -1){ | |
| winner = tiles[2][0]; | |
| gameEnded = true; | |
| }else if((tiles[2][0] == tiles[1][1]) && (tiles[2][0] == tiles[0][2]) && playerArr.indexOf(tiles[2][0]) > -1){ | |
| winner = tiles[2][0]; | |
| gameEnded = true; | |
| }else if((tiles[1][0] == tiles[1][1]) && (tiles[1][0] == tiles[1][2]) && playerArr.indexOf(tiles[1][0]) > -1){ | |
| winner = tiles[1][0]; | |
| gameEnded = true; | |
| }else if((tiles[0][1] == tiles[1][1]) && (tiles[0][1] == tiles[2][1]) && playerArr.indexOf(tiles[0][1]) > -1){ | |
| winner = tiles[0][1]; | |
| gameEnded = true; | |
| }else if(clickCount == 9){ | |
| gameEnded = true; | |
| winner = 'None'; | |
| } | |
| return {winner, gameEnded, clickCount} | |
| } | |
| nextPlayer = () => { | |
| let currentPlayer = this.state.currentPlayer; | |
| let playSwitch = { | |
| 'X': 'O', | |
| 'O': 'X' | |
| }; | |
| return playSwitch[currentPlayer]; | |
| }; | |
| tileValAt = (i, j) => { | |
| return this.state.tiles[i][j]; | |
| }; | |
| resetGame = () => { | |
| let val = { | |
| currentPlayer: 'X', | |
| winner: 'None', | |
| gameEnded: false, | |
| clickCount: 0, | |
| tiles: this.defaultTiles() | |
| }; | |
| this.setState(val); | |
| } | |
| render() { | |
| let {currentPlayer, winner, gameEnded } = this.state; | |
| return ( | |
| <div style={containerStyle} className="gameBoard"> | |
| {!gameEnded ?<div id="statusArea" className="status" style={instructionsStyle}>Next player: <span>{ currentPlayer }</span></div> : null} | |
| {winner && gameEnded ? <div id="winnerArea" className="winner" style={instructionsStyle}>Winner: <span>{ winner }</span></div> : null} | |
| <button onClick={()=> this.resetGame()} style={buttonStyle}>Reset</button> | |
| <div style={boardStyle}> | |
| <div className="board-row" style={rowStyle}> | |
| <Square mark={() => this.markTile(0,0)} text={() => this.tileValAt(0,0)}/> | |
| <Square mark={() => this.markTile(0,1)} text={() => this.tileValAt(0,1)}/> | |
| <Square mark={() => this.markTile(0,2)} text={() => this.tileValAt(0,2)}/> | |
| </div> | |
| <div className="board-row" style={rowStyle}> | |
| <Square mark={() => this.markTile(1,0)} text={() => this.tileValAt(1,0)}/> | |
| <Square mark={() => this.markTile(1,1)} text={() => this.tileValAt(1,1)}/> | |
| <Square mark={() => this.markTile(1,2)} text={() => this.tileValAt(1,2)}/> | |
| </div> | |
| <div className="board-row" style={rowStyle}> | |
| <Square mark={() => this.markTile(2,0)} text={() => this.tileValAt(2,0)}/> | |
| <Square mark={() => this.markTile(2,1)} text={() => this.tileValAt(2,1)}/> | |
| <Square mark={() => this.markTile(2,2)} text={() => this.tileValAt(2,2)}/> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| } | |
| class Game extends React.Component { | |
| render() { | |
| return ( | |
| <div className="game"> | |
| <div className="game-board"> | |
| <Board /> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| } | |
| ReactDOM.render( | |
| <Game />, | |
| document.getElementById('root') | |
| ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment