import React from 'react'; import Grid from './grid/grid'; import GridControl from './grid/grid-control'; class MineSeeker extends React.Component { constructor(props) { super(props); let gameAssoc = props.gameId !== '' ? props.gameId : this.makeGameAssoc(50); let channel = "mineseeker/channel/" + gameAssoc; this.state = { env: props.env, gameInherited: props.gameId !== '', gameAssoc: gameAssoc, channel: channel, session: null, createGrid: false, stepCache: [], disconnect: false } } makeGameAssoc(len) { let text = ""; let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (let i = 0; i < len; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; } /** STEP */ makePointsCalcAndStep(coords) { let users = this.refs.gridControl.refs.userControl, activePlayer = users.state.activePlayer ? 'blue' : 'red', inactivePlayer = users.state.activePlayer ? 'red' : 'blue', redPoints = activePlayer === 'red' ? users.refs[activePlayer].state.mines : users.refs[inactivePlayer].state.mines, bluePoints = activePlayer === 'blue' ? users.refs[activePlayer].state.mines : users.refs[inactivePlayer].state.mines; this.refs.gridControl.stepEvent(coords); let mineCache = this.refs.gridControl.state.foundUserMineCache; redPoints += activePlayer === 'red' ? mineCache : 0; bluePoints += activePlayer === 'blue' ? mineCache : 0; return {red: redPoints, blue: bluePoints}; } /** THE END */ makeGameEndIfItEnds(bluePoints, redPoints, resign = false) { let redWins = redPoints > 25, blueWins = bluePoints > 25; if (redWins || blueWins || resign) { this.refs.gridControl.state.sound.won.play(); if (false === resign) { this.refs.gridControl.setState({ overlay: true, overlayTitle: (redWins ? 'Red' : 'Blue') + " wins the game!", overlaySubTitle: "Play again!" }); } this.refs.gridControl.showLeftMines(); this.refs.gridControl.refs.userControl.setState({activePlayer: false}); this.refs.gridControl.refs.userControl.refs.red.setState({desc: ""}); this.refs.gridControl.refs.userControl.refs.blue.setState({desc: ""}); } } resignProcess(color) { this.refs.gridControl.setState({ overlay: true, overlayTitle: color === this.refs.gridControl.state.webPlayer ? "You have been give up" : "Your opponent has been resigned", overlaySubTitle: color === this.refs.gridControl.state.webPlayer ? "You LOSE!" : "You WIN!" }); this.makeGameEndIfItEnds(0, 0, true); } clickResign() { this.state.session.publish(this.state.channel, { 'resign': this.refs.gridControl.refs.userControl.state.activePlayer ? 'blue' : 'red' }); this.resignProcess(this.refs.gridControl.state.webPlayer); } clickResignCancel() { this.refs.gridControl.setState({ overlay: false }); } /** RESIGN */ resign() { let users = this.refs.gridControl.refs.userControl, activePlayer = users.state.activePlayer ? 'blue' : 'red'; if (this.refs.gridControl.state.webPlayer === activePlayer) { this.refs.gridControl.setState({ overlay: true, overlayTitle: "Are u sure u want to resign?!", overlaySubTitle:
Yes No!
}); } } wInit(session, gridServer, gridClient) { this.setState({session: session}); /** save session to GridControl */ /** render grid fields - #12 */ this.refs.gridControl.setState({ grid: this.state.gameInherited ? JSON.parse(Base64.decode(gridServer)) : gridClient, channel: this.state.channel, desc: { buddy:
Your buddy is
making a
move.
, you:
It is your turn!
Make a move.
}, overlay: true, overlayTitle: "We are waiting for your opponent...", overlaySubTitle: this.state.gameAssoc ?
Play w/ me!
: '', renderGridFields: this.state.gameAssoc }); } wSubscribe(payload) { this.state.env === 'dev' && console.info( (typeof payload.user !== 'undefined' ? payload.user : 'user') + " has been subscribed to the channel!" ); if (!this.state.disconnect) { /** setup the web player */ null === this.refs.gridControl.state.webPlayer && this.refs.gridControl.setState({ webPlayer: payload.user === payload.users.blue || payload.user === payload.users.blueAnon ? 'blue' : 'red' }); /** every user has been came */ if (payload.userCnt === 2) { /** every time the blue starts */ this.refs.gridControl.refs.userControl.setState({activePlayer: 1}); /** Set up player names w/ server data */ this.refs.gridControl.refs.userControl.refs.red.setState({ name: payload.users.red !== '' ? payload.users.red : payload.users.redAnon, }); this.refs.gridControl.refs.userControl.refs.blue.setState({ name: payload.users.blue !== '' ? payload.users.blue : payload.users.blueAnon, desc: this.refs.gridControl.state.webPlayer === 'blue' ? this.refs.gridControl.state.desc.you : this.refs.gridControl.state.desc.buddy, active: true, }); this.refs.gridControl.setState({overlay: false}); } } } wUnsubscribe(payload) { this.state.env === 'dev' && console.info(payload.msg); this.refs.gridControl.setState({ overlay: true, overlayTitle: "The connection has been lost w/ your friend...", overlaySubTitle: "Please, restart the game!" }); } wTopic(payload) { /** Auto-Step if this player is not the current user */ if (this.refs.gridControl.state.webPlayer !== payload.data.player) { if (null === payload.data.resign) { this.state.env === 'dev' && console.warn(payload.user + " has been stepped to coords: " + payload.data.coords[0] + ', ' + payload.data.coords[1]); this.state.env === 'dev' && console.warn('Opponent stepped: Auto-Step process'); this.refs.gridControl.refs.userControl.setState({bombSelected: payload.data.bomb}); /** STEP */ let points = this.makePointsCalcAndStep(payload.data.coords); /** THE END */ this.makeGameEndIfItEnds(points.blue, points.red); } else { /** RESIGN */ /** THE END */ this.resignProcess(payload.data.resign); } } } /** Connect - Subscribe */ subscribe() { this.state.session.subscribe( this.state.channel, (uri, payload, log) => { let isTopicEvent = typeof payload.data !== 'undefined', isNotUnsubscribe = typeof payload.msg === 'undefined'; /** CONNECTION */ if (isTopicEvent) { this.wTopic(payload); } else { if (isNotUnsubscribe) { this.wSubscribe(payload); } else { this.wUnsubscribe(payload); } } /** RECONNECTION */ if (payload.userCnt === 2 && this.state.disconnect) { this.state.env === 'dev' && console.info('Reconnection process'); let cache = this.state.stepCache; cache.forEach((item) => this.state.session.publish(this.state.channel, item)); this.setState({disconnect: false, stepCache: []}); } }); } /** after rendering */ componentDidMount() { /** Create Websocket w/ Bahnhof.js */ let websocket = WS.connect( this.state.env === 'dev' ? "ws://mine.dev:6450" : "ws://www.mineseeker.ninja:6450" ); /** * Connect * Session is an Autobahn JS WAMP session. */ websocket.on("socket/connect", (session) => { this.state.env === 'dev' && console.info("Successfully connected to the Server!"); if (!this.state.disconnect) { let gridClient = this.state.gameInherited || new Grid().state.grid; /** * Connect - RPC * Send grid information to the server */ session .call( this.state.gameInherited ? "mineseeker-rpc/connectGame" : "mineseeker-rpc/startGame", this.state.gameInherited ? this.state.gameAssoc : [Base64.encode(JSON.stringify(gridClient)), this.state.gameAssoc] ) .then( (gridServer) => { this.state.env === 'dev' && console.info("Grid has been created! Return w/ gameAssoc."); this.wInit(session, gridServer, gridClient); this.subscribe(); }, (error, desc) => this.state.env === 'dev' && console.error(["RPC Error", error, desc]) ); } else { this.setState({session: session}); this.subscribe(); } }); /** * DisConnect * Error provides us with some insight into the disconnection: error.reason and error.code */ websocket.on("socket/disconnect", (error) => { this.state.env === 'dev' && console.error("Disconnected for " + error.reason + " with code " + error.code); this.setState({disconnect: true}); }); } /** * Cache the steps unless reconnection * * @param dataPack */ cachePublish(dataPack) { let cache = this.state.stepCache; cache.push(dataPack); this.setState({stepCache: cache}); } onClick(coords) { let activePlayer = this.refs.gridControl.refs.userControl.state.activePlayer ? 'blue' : 'red'; /** if the clicked field is NEVER CLICKED */ if (this.refs.gridControl.checkFieldHasBeenNeverClicked(coords[0], coords[1])) { /** Player step and it is the current player */ if (activePlayer === this.refs.gridControl.state.webPlayer) { /** STEP */ let points = this.makePointsCalcAndStep(coords); /** THE END */ this.makeGameEndIfItEnds(points.blue, points.red); let dataPack = { 'coords': coords, 'player': activePlayer, 'bomb': this.refs.gridControl.refs.userControl.state.bombSelected, 'redPoints': points.red, 'bluePoints': points.blue, 'resign': null, 'redExplodedBomb': activePlayer === 'red' && this.refs.gridControl.refs.userControl.state.bombSelected, 'blueExplodedBomb': activePlayer === 'blue' && this.refs.gridControl.refs.userControl.state.bombSelected }; /** PUBLISH */ !this.state.disconnect ? this.state.session.publish(this.state.channel, dataPack) : this.cachePublish(dataPack); } } } render() { return ( ); } } export default MineSeeker;