From 1468cf5e245674d2f657180e654f32862507519d Mon Sep 17 00:00:00 2001 From: Songyi Huang Date: Tue, 11 Feb 2020 13:21:55 -0800 Subject: [PATCH] added game state traveler --- server/index.js | 2 +- server/sample_data/sample_doudizhu.json | 4 +- src/assets/doudizhu.scss | 8 +- src/assets/gameview.scss | 10 +- src/components/GameBoard/DoudizhuGameBoard.js | 3 +- .../GameBoard/LeducHoldemGameBoard.js | 6 +- src/view/DoudizhuGameView.js | 131 ++++++++++++------ 7 files changed, 114 insertions(+), 50 deletions(-) diff --git a/server/index.js b/server/index.js index 2edf4b0..3ce7d60 100644 --- a/server/index.js +++ b/server/index.js @@ -32,7 +32,7 @@ function getGameHistory(){ console.log(testDoudizhuData); }); - fs.readFile("./sample_data/sample_leduc_holdem-test.json", (err, data) => { + fs.readFile("./sample_data/sample_leduc_holdem.json", (err, data) => { if (err) throw err; testLeducHoldemData = JSON.parse(data); console.log(testLeducHoldemData); diff --git a/server/sample_data/sample_doudizhu.json b/server/sample_data/sample_doudizhu.json index cfa93f1..f5a1e86 100644 --- a/server/sample_data/sample_doudizhu.json +++ b/server/sample_data/sample_doudizhu.json @@ -269,11 +269,11 @@ "probability": 0.5 }, { - "move": "S7 H7", + "move": "CT DT", "probability": 0.1 }, { - "move": "HA CA", + "move": "RJ BJ", "probability": 0.05 } ] diff --git a/src/assets/doudizhu.scss b/src/assets/doudizhu.scss index c849213..1e01a4c 100644 --- a/src/assets/doudizhu.scss +++ b/src/assets/doudizhu.scss @@ -168,11 +168,15 @@ .played-card-area { width: 100%; position: relative; - transform: translateY(25px); + //transform: translateY(25px); + + .playingCards ul.hand { + margin-bottom: 0; + } .non-card { height: 138px; - transform: translateY(-25px); + //transform: translateY(-25px); } } } diff --git a/src/assets/gameview.scss b/src/assets/gameview.scss index 4f5738a..c9b98f2 100644 --- a/src/assets/gameview.scss +++ b/src/assets/gameview.scss @@ -1,9 +1,15 @@ .game-controller { - width: 500px; + width: 100%; padding: 20px; .el-row { margin-bottom: 10px; } + + .status-button { + margin-left: 5px; + margin-right: 5px; + width: 125px; + } } .doudizhu-view-container { @@ -82,7 +88,7 @@ } .non-card.hide { visibility: hidden; - transition: visibility 0.1s, opacity 0.05s; + transition: visibility 0.2s, opacity 0.15s; opacity: 0; pointer-events:none; } diff --git a/src/components/GameBoard/DoudizhuGameBoard.js b/src/components/GameBoard/DoudizhuGameBoard.js index d231416..09cfc8c 100644 --- a/src/components/GameBoard/DoudizhuGameBoard.js +++ b/src/components/GameBoard/DoudizhuGameBoard.js @@ -2,6 +2,7 @@ import React from 'react'; import { translateCardData, millisecond2Second, computeHandCardsWidth } from '../../utils' import '../../assets/doudizhu.scss'; +import {fade} from "@material-ui/core"; class DoudizhuGameBoard extends React.Component { constructor(props) { @@ -97,7 +98,7 @@ class DoudizhuGameBoard extends React.Component { } componentDidUpdate(prevProps, prevState, snapshot) { - if(prevProps.turn !== this.props.turn && this.props.turn !== 0){ + if(prevProps.turn !== this.props.turn && this.props.turn !== 0 && this.props.gameStatus === "playing"){ // new turn starts this.props.runNewTurn(prevProps); } diff --git a/src/components/GameBoard/LeducHoldemGameBoard.js b/src/components/GameBoard/LeducHoldemGameBoard.js index a4ad2e4..097946e 100644 --- a/src/components/GameBoard/LeducHoldemGameBoard.js +++ b/src/components/GameBoard/LeducHoldemGameBoard.js @@ -11,7 +11,7 @@ class LeducHoldemGameBoard extends React.Component { computeHand(card) { const [rankClass, suitClass, rankText, suitText] = translateCardData(card); return ( -
+
{rankText} {suitText} @@ -31,14 +31,14 @@ class LeducHoldemGameBoard extends React.Component { displayPublicCard(){ if(this.props.round === 0){ return ( -
+
*
) }else{ const [rankClass, suitClass, rankText, suitText] = translateCardData(this.props.publicCard); return ( -
+
{rankText} {suitText} diff --git a/src/view/DoudizhuGameView.js b/src/view/DoudizhuGameView.js index 8861297..877d862 100644 --- a/src/view/DoudizhuGameView.js +++ b/src/view/DoudizhuGameView.js @@ -9,10 +9,14 @@ import Slider from '@material-ui/core/Slider'; import Button from '@material-ui/core/Button'; import Paper from '@material-ui/core/Paper'; import Divider from '@material-ui/core/Divider'; +import ButtonGroup from '@material-ui/core/ButtonGroup'; import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded'; import PauseCircleOutlineRoundedIcon from '@material-ui/icons/PauseCircleOutlineRounded'; import ReplayRoundedIcon from '@material-ui/icons/ReplayRounded'; import NotInterestedIcon from '@material-ui/icons/NotInterested'; +import PlayArrowIcon from '@material-ui/icons/PlayArrow'; +import SkipNextIcon from '@material-ui/icons/SkipNext'; +import SkipPreviousIcon from '@material-ui/icons/SkipPrevious'; class DoudizhuGameView extends React.Component { constructor(props) { @@ -20,11 +24,11 @@ class DoudizhuGameView extends React.Component { const mainViewerId = 0; // Id of the player at the bottom of screen this.initConsiderationTime = 2000; - this.considerationTimeDeduction = 100; + this.considerationTimeDeduction = 200; this.gameStateTimeout = null; this.apiUrl = window.g.apiUrl; this.moveHistory = []; - + this.gameStateHistory = []; this.initGameState = { gameStatus: "ready", // "ready", "playing", "paused", "over" playerInfo: [], @@ -49,6 +53,38 @@ class DoudizhuGameView extends React.Component { return cardStr === "P" ? cardStr : cardStr.split(" "); } + generateNewState(){ + let gameInfo = deepCopy(this.state.gameInfo); + // check if the game state of next turn is already in game state history + if(this.state.gameInfo.turn+1 < this.gameStateHistory.length){ + gameInfo = deepCopy(this.gameStateHistory[this.state.gameInfo.turn+1]); + }else{ + let newMove = this.moveHistory[this.state.gameInfo.turn]; + if(newMove.playerIdx === this.state.gameInfo.currentPlayer) { + gameInfo.latestAction[newMove.playerIdx] = this.cardStr2Arr(newMove.move); + gameInfo.turn++; + gameInfo.currentPlayer = (gameInfo.currentPlayer + 1) % 3; + // take away played cards from player's hands + const remainedCards = removeCards(gameInfo.latestAction[newMove.playerIdx], gameInfo.hands[newMove.playerIdx]); + if (remainedCards !== false) { + gameInfo.hands[newMove.playerIdx] = remainedCards; + } else { + console.log("Cannot find cards in move from player's hand"); + } + gameInfo.considerationTime = this.initConsiderationTime; + }else { + console.log("Mismatched current player index"); + } + } + // if current state is new to game state history, push it to the game state history array + if(gameInfo.turn === this.gameStateHistory.length){ + this.gameStateHistory.push(gameInfo); + }else{ + console.log("inconsistent game state history length and turn number"); + } + return gameInfo; + } + gameStateTimer() { this.gameStateTimeout = setTimeout(()=>{ let currentConsiderationTime = this.state.gameInfo.considerationTime; @@ -65,39 +101,21 @@ class DoudizhuGameView extends React.Component { this.setState({gameInfo: gameInfo}); this.gameStateTimer(); }else{ - let res = this.moveHistory[this.state.gameInfo.turn]; - if(res.playerIdx === this.state.gameInfo.currentPlayer){ - let gameInfo = deepCopy(this.state.gameInfo); - gameInfo.latestAction[res.playerIdx] = this.cardStr2Arr(res.move); - gameInfo.turn++; + let gameInfo = this.generateNewState(); + gameInfo.gameStatus = "playing"; + if(this.state.gameInfo.toggleFade === "fade-out") { gameInfo.toggleFade = "fade-in"; - gameInfo.currentPlayer = (gameInfo.currentPlayer+1)%3; - // take away played cards from player's hands - const remainedCards = removeCards(gameInfo.latestAction[res.playerIdx], gameInfo.hands[res.playerIdx]); - if(remainedCards !== false){ - gameInfo.hands[res.playerIdx] = remainedCards; - }else{ - console.log("Cannot find cards in move from player's hand"); - } - gameInfo.considerationTime = this.initConsiderationTime; - this.setState({gameInfo: gameInfo}, ()=>{ - // toggle fade in - if(this.state.gameInfo.toggleFade !== ""){ - // doubleRaf(()=>{ - // let gameInfo = deepCopy(this.state.gameInfo); - // gameInfo.toggleFade = ""; - // this.setState({gameInfo: gameInfo}); - // }); - setTimeout(()=>{ - let gameInfo = deepCopy(this.state.gameInfo); - gameInfo.toggleFade = ""; - this.setState({gameInfo: gameInfo}); - }, 200); - } - }); - }else{ - console.log("Mismatched current player index"); } + this.setState({gameInfo: gameInfo}, ()=>{ + // toggle fade in + if(this.state.gameInfo.toggleFade !== ""){ + setTimeout(()=>{ + let gameInfo = deepCopy(this.state.gameInfo); + gameInfo.toggleFade = ""; + this.setState({gameInfo: gameInfo}); + }, 200); + } + }); } }, this.considerationTimeDeduction); } @@ -119,6 +137,7 @@ class DoudizhuGameView extends React.Component { }); // the first player should be landlord gameInfo.currentPlayer = res.playerInfo.find(element=>{return element.role === "landlord"}).index; + this.gameStateHistory.push(gameInfo); this.setState({gameInfo: gameInfo}, ()=>{ if(this.gameStateTimeout){ window.clearTimeout(this.gameStateTimeout); @@ -182,13 +201,13 @@ class DoudizhuGameView extends React.Component { gameStatusButton(status){ switch (status) { case "ready": - return ; + return ; case "playing": - return ; + return ; case "paused": - return ; + return ; case "over": - return ; + return ; default: alert(`undefined game status: ${status}`); } @@ -245,6 +264,20 @@ class DoudizhuGameView extends React.Component { } } + go2PrevGameState() { + let gameInfo = deepCopy(this.gameStateHistory[this.state.gameInfo.turn - 1]); + gameInfo.gameStatus = "paused"; + gameInfo.toggleFade = ""; + this.setState({gameInfo: gameInfo}); + } + + go2NextGameState() { + let gameInfo = this.generateNewState(); + gameInfo.gameStatus = "paused"; + gameInfo.toggleFade = ""; + this.setState({gameInfo: gameInfo}); + } + render(){ let sliderValueText = (value) => { return `${value}°C`; @@ -296,6 +329,7 @@ class DoudizhuGameView extends React.Component { turn={this.state.gameInfo.turn} runNewTurn={(prevTurn)=>this.runNewTurn(prevTurn)} toggleFade={this.state.gameInfo.toggleFade} + gameStatus={this.state.gameInfo.gameStatus} />
@@ -320,9 +354,28 @@ class DoudizhuGameView extends React.Component {
- + {/**/} - { this.gameStatusButton(this.state.gameInfo.gameStatus) } + + + + + { this.gameStatusButton(this.state.gameInfo.gameStatus) } +