Создайте игру Rock Paper Scissor с помощью ReactJS
Здесь оба игрока будут ходить по очереди. Начиная с первого игрока, за которым следует второй игрок. Есть три вида оружия на выбор: камень, бумага, ножницы. После того, как второй игрок играет, результат своего хода вычисляется, обновляя статус выигрыша / проигрыша обоих игроков.
Используемые технологии / Предпосылки:
- ReactJS
- Библиотека Antd для пользовательского интерфейса
Подход: контейнеры представляют собой компоненты React с отслеживанием состояния (на основе классов). Компоненты - это компоненты React без сохранения состояния (функционально-ориентированные). В этом проекте у меня есть один контейнер - контроллер, который отвечает за управление состоянием и всю игровую логику. Также есть три компонента, а именно:
Player -> Представление сущности Player в игре; GameControls -> Выбор камня, бумаги или ножниц; DecisionBox -> Отображает статус выигрыша / проигрыша для игроков;
При нажатии кнопок оружия состояние в контроллере обновляется для соответствующего игрока. Когда обновляется оружие второго игрока, результат вычисляется функцией обработчика результатов, которая охватывает все девять комбинаций камня, бумаги и ножниц, взятых по две за раз.
Структура проекта:

Шаги:
- Настройте проект React с помощью команды create-response-app: create-response-app << имя проекта >> –scripts-version 1.1.5. С помощью этой команды будет сгенерирована структура проекта, подобная приведенной выше, за исключением компонентов и папок контейнеров, которые должны быть созданы внутри папки src вручную.
- Установите библиотеку antd с помощью команды: npm install antd
- Удалите код из App.css .
-  Отредактируйте код внутри App.js : компонент приложения отображает контроллер и отображает заголовок.
 App.jsJavascriptimport React, { Component } from"react";import Controller from"./containers/controller/controller";import { Typography } from"antd";import"antd/dist/antd.css";import"./App.css";const { Title } = Typography;class App extends Component {render() {return(<div className="App"><Title level={3} style={{ textAlign:"center"}}>Stone Paper Scissor</Title><Controller /></div>);}}exportApp;default
- Controller.js: Контроллер содержит состояние, которое включает в себя последнее использованное оружие каждым игроком, текущий статус выигрыша / проигрыша и активное состояние, указывающее, у какого игрока сейчас ход. - Javascript- import React, { Component } from- "react"- ;- import { Row, Col, Divider } from- "antd"- ;- import { Typography } from- "antd"- ;- import axios from- "axios"- ;- import- "antd/dist/antd.css"- ;- import Player from- "../../components/Player/Player"- ;- const { Title } = Typography;- class Controller extends Component {- state = {- playerOne: {- active:- true- ,- weapon:- ""- ,- status:- ""- },- playerTwo: {- active:- false- ,- weapon:- ""- ,- status:- ""- }- };- Основная идея здесь заключается в том, что при нажатии кнопок оружия соответствующее оружие игрока в состоянии должно обновляться, и должен наступить следующий ход игрока, что здесь делается с помощью функции переключения. Кроме того, если обновляется оружие второго игрока, необходимо также обновить выигрыш / проигрыш, что здесь делается с помощью функции resultHandler. Для игровой логики он содержит набор функций: -  WeaponUpdate: для обновления оружия игрока в состоянии. Он принимает два аргумента: первый - playerId, то есть playerOne или playerTwo, так как это игра для двух игроков, а второй - это оружие, которое выбирает игрок.JavascriptweaponUpdate = (player, weapon) => {this.setState({[player]: {...this.state[player],weapon: weapon}});if(player =="playerTwo") {this.resultHandler();}else{this.toggleActive();}};
-  ToggleActive: для изменения активного статуса игроков, когда любой из игроков выбирает оружие. Активное свойство в состоянии - это логическая переменная, поэтому нам просто нужно использовать оператор NOT, чтобы изменить текущее состояние каждого игрока.JavascripttoggleActive = () => {this.setState(prevState => {return{...prevState,playerOne: {...prevState.playerOne,active: !prevState.playerOne.active},playerTwo: {...prevState.playerTwo,active: !prevState.playerTwo.active}};});};
-  ResultHandler: он содержит основную игровую логику, которая определяет, какой игрок выиграл. Он использует вспомогательную функцию, называемую помощником по принятию решений, которая принимает два аргумента, которые являются оружием каждого игрока, и возвращает массив, содержащий два элемента, в которых первый элемент соответствует статусу выигрыша / проигрыша первого игрока, а второй элемент - статусу второго игрока. Затем обработчик результатов обновляет состояние значениями, возвращаемыми функцией decicerhelper.JavascriptresultHandler = () => {this.setState(prevState => {let [s1, s2] =this.deciderHelper(prevState.playerOne.weapon,prevState.playerTwo.weapon);return{...prevState,playerOne: {...prevState.playerOne,status: s1},playerTwo: {...prevState.playerTwo,status: s2}};});this.toggleActive();};
-  DeciderHelper : это вспомогательная функция, которая принимает два входа, которые являются оружием для каждого игрока, и возвращает массив, состоящий из двух элементов, каждый из которых обозначает статус выигрыша / проигрыша игрока 1 и игрока 2 соответственно. Здесь «r» означает камень, «s» означает ножницы, «p» означает бумагу, «w» - выигрыш, а «l» - проигрыш. Учитываются все возможные комбинации камень, камень, ножницы, в случае ничьей возвращаются оба игрока со статусом победы.JavascriptdeciderHelper = (p1, p2) => {if(p1 =="r"&& p2 =="s") {return["w","l"];}if(p1 =="r"&& p2 =="p") {return["l","w"];}if(p1 =="r"&& p2 =="r") {return["w","w"];}if(p1 =="p"&& p2 =="r") {return["w","l"];}if(p1 =="p"&& p2 =="s") {return["l","w"];}if(p1 =="p"&& p2 =="p") {return["w","w"];}if(p1 =="s"&& p2 =="r") {return["l","w"];}if(p1 =="s"&& p2 =="p") {return["w","l"];}if(p1 =="s"&& p2 =="s") {return["w","w"];}};
-  Метод рендеринга:Javascriptrender() {return(<Row justify="space-around"align="middle"><Col className="gutter-row"xs={15} sm={15} md={5} lg={5}><Title level={3}>Player One</Title><Playeractive={this.state.playerOne.active}weaponUpdate={weapon =>this.weaponUpdate("playerOne", weapon)}weapon={this.state.playerOne.weapon}status={this.state.playerOne.status}/></Col><Col className="gutter-row"xs={15} sm={15} md={5} lg={5}><Title level={3}>Player Two</Title><Playeractive={this.state.playerTwo.active}weaponUpdate={weapon =>this.weaponUpdate("playerTwo", weapon)}weapon={this.state.playerTwo.weapon}status={this.state.playerTwo.status}/></Col></Row>);}}exportController;default
 
-  WeaponUpdate: для обновления оружия игрока в состоянии. Он принимает два аргумента: первый - playerId, то есть playerOne или playerTwo, так как это игра для двух игроков, а второй - это оружие, которое выбирает игрок.
- Кодирование компонентов: Код в них очень прост. Здесь находится просто репрезентативная логика. -  Player.js : как упоминалось ранее, это компонент без сохранения состояния, представляющий объект игрока. Он получает четыре реквизита: активный статус игрока, текущее оружие, статус выигрыша / проигрыша и functionHandler для обновления оружия. Кроме того, он использует два компонента GameControls и блок принятия решений, которые обсуждаются ниже. Кроме того, если полученные активные реквизиты истинны, то к div применяется объект CSS с именем glowEffect.Javascriptimport React from"react";import GameControls from"../GameControls/GameControls";import DecisionBox from"../DecisionBox/DecisionBox";const Player = props => {let glowEffect = {};if(props.active) {glowEffect = {"-webkit-box-shadow":"0 0 20px blue","-moz-box-shadow":"0 0 20px blue","box-shadow":"0 0 20px blue"};}return(<div style={glowEffect}><GameControls wUpdate={props.weaponUpdate} isActive={props.active} /><DecisionBox weapon={props.weapon} status={props.status} /></div>);};exportPlayer;default
-  GameControls.js: содержит три кнопки: камень, камень, ножницы. Если плеер не активен, кнопки отключены. При нажатии кнопки вызывается функция weaponupdate, которая принимает один аргумент «p» для бумаги, «r» для камня, «s» для ножниц, и состояние соответствующего обновляется.Javascriptimport React from"react";import { Card } from"antd";import { Button } from"antd";import"antd/dist/antd.css";const GameControls = props => {return(<Cardtitle="Controls"style={{ width:"300px", height:"250px", alignItems:"center"}}><p style={{ alignItems:"center"}}><Buttontype="dashed"size="large"shape="round"blockonClick={() => props.wUpdate("r")}disabled={!props.isActive}>Rock</Button></p><p style={{ alignItems:"center"}}>{" "}<Buttontype="dashed"size="large"shape="round"blockonClick={() => props.wUpdate("p")}disabled={!props.isActive}>Paper</Button></p><p style={{ alignItems:"center"}}><Buttontype="dashed"size="large"shape="round"blockonClick={() => props.wUpdate("s")}disabled={!props.isActive}>Scissors</Button></p></Card>);};exportGameControls;default
-  DecisionBox.js : он отображает две вещи: оружие игрока и его выигрышный / проигрышный статус. Он получает два реквизита: оружие ('r' или 'p' или 's') и статус ('w' или 'l'). Два объекта: карта оружия и карта состояния используются для сопоставления сокращений с соответствующими словами, которые могут отображаться на экране.Javascriptimport React from"react";import { Card } from"antd";import { Typography } from"antd";const { Title } = Typography;const weaponMap = {s:"Scissors",p:"Paper",r:"Rock"};const statusMap = {w:"Win",l:"Loose"};const DecisionBox = props => {return(<Cardtitle="Decision Box"style={{width:"300px",height:"250px",alignItems:"center",marginTop:"15px"}}bodyStyle={{ textAlign:"center"}}><Title level={1} type="warning">{weaponMap[props.weapon]}</Title><Title level={2} mark type="secondary">{statusMap[props.status]}</Title></Card>);};exportDecisionBox;default
 
-  Player.js : как упоминалось ранее, это компонент без сохранения состояния, представляющий объект игрока. Он получает четыре реквизита: активный статус игрока, текущее оружие, статус выигрыша / проигрыша и functionHandler для обновления оружия. Кроме того, он использует два компонента GameControls и блок принятия решений, которые обсуждаются ниже. Кроме того, если полученные активные реквизиты истинны, то к div применяется объект CSS с именем glowEffect.
Выход:
