Added Probability for doudizhu, added transition animation for doudizhu probability
This commit is contained in:
parent
19fafcb832
commit
c47eac7e5a
|
@ -3,12 +3,13 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/core": "^4.9.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"element-react": "^1.4.34",
|
||||
"element-theme-default": "^1.4.13",
|
||||
"node-sass": "^4.13.0",
|
||||
"react": "^16.12.0",
|
||||
"react-addons-css-transition-group": "^15.6.2",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-hot-loader": "^4.12.19",
|
||||
"react-router-dom": "^5.1.2",
|
||||
|
|
|
@ -24,23 +24,49 @@
|
|||
"moveHistory": [
|
||||
{
|
||||
"playerIdx": 2,
|
||||
"move": "H3 S3 D3 D5"
|
||||
"move": "RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3",
|
||||
"probabilities": [
|
||||
{
|
||||
"move": "RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3",
|
||||
"probability": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"playerIdx": 0,
|
||||
"move": "S9 H9 D9 S3"
|
||||
"move": "S2 H2 HK DK HQ CQ DQ CJ S9 H9 D9 C7 S6 H6 C4 D4",
|
||||
"probabilities": [
|
||||
{
|
||||
"move": "RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3",
|
||||
"probability": 1
|
||||
},
|
||||
{
|
||||
"move": "RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3",
|
||||
"probability": 1
|
||||
},
|
||||
{
|
||||
"move": "RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3",
|
||||
"probability": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"playerIdx": 1,
|
||||
"move": "P"
|
||||
"move": "C2 HA CA DA SQ ST HT D8 S7 H7 C6 D6 S5 H5 C5 S4",
|
||||
"probabilities": [
|
||||
{
|
||||
"move": "RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3",
|
||||
"probability": 1
|
||||
},
|
||||
{
|
||||
"playerIdx": 2,
|
||||
"move": "SJ HJ DJ D7"
|
||||
"move": "RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3",
|
||||
"probability": 1
|
||||
},
|
||||
{
|
||||
"playerIdx": 0,
|
||||
"move": "P"
|
||||
"move": "RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3",
|
||||
"probability": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -87,7 +87,7 @@
|
|||
|
||||
.played-card-area {
|
||||
position: relative;
|
||||
left: 100px;
|
||||
left: 20px;
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,7 @@
|
|||
|
||||
.played-card-area {
|
||||
position: relative;
|
||||
right: 100px;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,3 +5,99 @@
|
|||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.doudizhu-view-container {
|
||||
width: 1000px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
|
||||
|
||||
.doudizhu-gameboard-paper {
|
||||
height: calc(100% - 7px*2);
|
||||
margin: 5px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.doudizhu-probability-paper {
|
||||
height: calc(100% - 5px*2);
|
||||
margin: 5px;
|
||||
|
||||
.probability-player {
|
||||
height: calc(72px - 16px*2);
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.probability-table {
|
||||
display: table;
|
||||
border-collapse: collapse;
|
||||
|
||||
width: 100%;
|
||||
height: calc(100% - 72px);
|
||||
|
||||
.probability-item {
|
||||
display: table-row;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
.waiting {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
}
|
||||
.playing {
|
||||
-webkit-transition: background-color 250ms ease;
|
||||
-ms-transition: background-color 250ms ease;
|
||||
transition: background-color 250ms ease;
|
||||
display: table-cell;
|
||||
height: 152px;
|
||||
vertical-align: middle;
|
||||
.playingCards {
|
||||
visibility: visible;
|
||||
transition: visibility 0s, opacity 0.5s;
|
||||
opacity: 1;
|
||||
}
|
||||
.playingCards.hide {
|
||||
visibility: hidden;
|
||||
transition: visibility 0.1s, opacity 0.05s;
|
||||
opacity: 0;
|
||||
pointer-events:none;
|
||||
}
|
||||
.playingCards > ul.hand {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.probability-move {
|
||||
font-size: 10px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.non-card {
|
||||
visibility: visible;
|
||||
transition: visibility 0s, opacity 0.5s;
|
||||
opacity: 1;
|
||||
display: table;
|
||||
width: 100%;
|
||||
margin-top: 5%;
|
||||
height: 25px;
|
||||
|
||||
span {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.non-card.hide {
|
||||
visibility: hidden;
|
||||
transition: visibility 0.1s, opacity 0.05s;
|
||||
opacity: 0;
|
||||
pointer-events:none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { translateCardData, millisecond2Second } from '../../utils'
|
||||
import { translateCardData, millisecond2Second, computeHandCardsWidth } from '../../utils'
|
||||
|
||||
import '../../assets/doudizhu.scss';
|
||||
|
||||
|
@ -15,7 +15,7 @@ class DoudizhuGameBoard extends React.Component {
|
|||
}else{
|
||||
return (
|
||||
<div className="playingCards">
|
||||
<ul className="hand" style={{width: this.computeHandCardsWidth(cards.length, 12)}}>
|
||||
<ul className="hand" style={{width: computeHandCardsWidth(cards.length, 12)}}>
|
||||
{cards.map(card=>{
|
||||
const [rankClass, suitClass, rankText, suitText] = translateCardData(card);
|
||||
return (
|
||||
|
@ -82,12 +82,6 @@ class DoudizhuGameBoard extends React.Component {
|
|||
)
|
||||
}
|
||||
|
||||
computeHandCardsWidth(num, emWidth) {
|
||||
if(num === 0)
|
||||
return 0;
|
||||
return (num-1)*1.1*emWidth + 4.3*emWidth*1.2 + 2;
|
||||
}
|
||||
|
||||
playerDecisionArea(playerIdx){
|
||||
if(this.props.currentPlayer === playerIdx){
|
||||
return <div className="non-card"><span>{`Consideration Time: ${millisecond2Second(this.props.considerationTime)}s`}</span></div>
|
||||
|
|
|
@ -88,3 +88,9 @@ export function debounce(func, wait, immediate) {
|
|||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
}
|
||||
|
||||
export function computeHandCardsWidth(num, emWidth) {
|
||||
if(num === 0)
|
||||
return 0;
|
||||
return (num-1)*1.1*emWidth + 4.3*emWidth*1.2 + 2;
|
||||
}
|
|
@ -2,11 +2,13 @@ import React from 'react';
|
|||
import axios from 'axios';
|
||||
import '../assets/gameview.scss';
|
||||
import { DoudizhuGameBoard } from '../components/GameBoard';
|
||||
import { removeCards, doubleRaf, deepCopy } from "../utils";
|
||||
import {removeCards, doubleRaf, deepCopy, computeHandCardsWidth, translateCardData} from "../utils";
|
||||
|
||||
import { Layout } from 'element-react';
|
||||
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 PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
|
||||
import PauseCircleOutlineRoundedIcon from '@material-ui/icons/PauseCircleOutlineRounded';
|
||||
import ReplayRoundedIcon from '@material-ui/icons/ReplayRounded';
|
||||
|
@ -29,6 +31,7 @@ class DoudizhuGameView extends React.Component {
|
|||
latestAction: [[], [], []],
|
||||
mainViewerId: mainViewerId,
|
||||
turn: 0,
|
||||
toggleFadeIn: "",
|
||||
currentPlayer: null,
|
||||
considerationTime: this.initConsiderationTime,
|
||||
};
|
||||
|
@ -40,12 +43,21 @@ class DoudizhuGameView extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
cardStr2Arr(cardStr){
|
||||
return cardStr === "P" ? cardStr : cardStr.split(" ");
|
||||
}
|
||||
|
||||
gameStateTimer() {
|
||||
this.gameStateTimeout = setTimeout(()=>{
|
||||
let currentConsiderationTime = this.state.gameInfo.considerationTime;
|
||||
if(currentConsiderationTime > 0) {
|
||||
currentConsiderationTime -= this.considerationTimeDeduction * Math.pow(2, this.state.gameSpeed);
|
||||
currentConsiderationTime = currentConsiderationTime < 0 ? 0 : currentConsiderationTime;
|
||||
if(currentConsiderationTime === 0 && this.state.gameSpeed < 2){
|
||||
let gameInfo = deepCopy(this.state.gameInfo);
|
||||
gameInfo.toggleFadeIn = "hide";
|
||||
this.setState({gameInfo: gameInfo});
|
||||
}
|
||||
let gameInfo = deepCopy(this.state.gameInfo);
|
||||
gameInfo.considerationTime = currentConsiderationTime;
|
||||
this.setState({gameInfo: gameInfo});
|
||||
|
@ -54,8 +66,9 @@ class DoudizhuGameView extends React.Component {
|
|||
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] = res.move === "P" ? "P" : res.move.split(" ");
|
||||
gameInfo.latestAction[res.playerIdx] = this.cardStr2Arr(res.move);
|
||||
gameInfo.turn++;
|
||||
|
||||
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]);
|
||||
|
@ -65,7 +78,16 @@ class DoudizhuGameView extends React.Component {
|
|||
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.toggleFadeIn !== ""){
|
||||
setTimeout(()=>{
|
||||
let gameInfo = deepCopy(this.state.gameInfo);
|
||||
gameInfo.toggleFadeIn = "";
|
||||
this.setState({gameInfo: gameInfo});
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
console.log("Mismatched current player index");
|
||||
}
|
||||
|
@ -86,7 +108,7 @@ class DoudizhuGameView extends React.Component {
|
|||
gameInfo.gameStatus = "playing";
|
||||
gameInfo.playerInfo = res.playerInfo;
|
||||
gameInfo.hands = res.initHands.map(element => {
|
||||
return element.split(" ");
|
||||
return this.cardStr2Arr(element);
|
||||
});
|
||||
// the first player should be landlord
|
||||
gameInfo.currentPlayer = res.playerInfo.find(element=>{return element.role === "landlord"}).index;
|
||||
|
@ -161,6 +183,53 @@ class DoudizhuGameView extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
computeSingleLineHand(cards) {
|
||||
if(cards === "P"){
|
||||
return <div className={"non-card "+this.state.gameInfo.toggleFadeIn}><span>Pass</span></div>
|
||||
}else{
|
||||
return (
|
||||
<div className={"playingCards "+this.state.gameInfo.toggleFadeIn}>
|
||||
<ul className="hand" style={{width: computeHandCardsWidth(cards.length, 10)}}>
|
||||
{cards.map(card=>{
|
||||
const [rankClass, suitClass, rankText, suitText] = translateCardData(card);
|
||||
return (
|
||||
<li key={`handCard-${card}`}>
|
||||
<a className={`card ${rankClass} ${suitClass}`} href="/#">
|
||||
<span className="rank">{rankText}</span>
|
||||
<span className="suit">{suitText}</span>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
computeProbabilityItem(idx){
|
||||
if(this.state.gameInfo.gameStatus !== "ready" && this.state.gameInfo.turn < this.moveHistory.length){
|
||||
let style = {};
|
||||
style["backgroundColor"] = this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? `rgba(255, 193, 7,${this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability})` : "#bdbdbd";
|
||||
return (
|
||||
<div className={"playing"} style={style}>
|
||||
<div className="probability-move">
|
||||
{this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ?
|
||||
this.computeSingleLineHand(this.cardStr2Arr(this.moveHistory[this.state.gameInfo.turn].probabilities[idx].move))
|
||||
:
|
||||
'\u00A0'
|
||||
}
|
||||
</div>
|
||||
<div className={"non-card"}>
|
||||
<span>{ this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? `Probability: ${(this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability*100).toFixed(2)}%` : ""}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}else {
|
||||
return <span className={"waiting"}>Waiting...</span>
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
let sliderValueText = (value) => {
|
||||
return `${value}°C`;
|
||||
|
@ -197,8 +266,11 @@ class DoudizhuGameView extends React.Component {
|
|||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{width: "960px", height: "540px"}}>
|
||||
<div className={"doudizhu-view-container"}>
|
||||
<Layout.Row style={{"height": "540px"}}>
|
||||
<Layout.Col style={{"height": "100%"}} span="17">
|
||||
<div style={{"height": "100%"}}>
|
||||
<Paper className={"doudizhu-gameboard-paper"} elevation={3}>
|
||||
<DoudizhuGameBoard
|
||||
playerInfo={this.state.gameInfo.playerInfo}
|
||||
hands={this.state.gameInfo.hands}
|
||||
|
@ -209,7 +281,27 @@ class DoudizhuGameView extends React.Component {
|
|||
turn={this.state.gameInfo.turn}
|
||||
runNewTurn={(prevTurn)=>this.runNewTurn(prevTurn)}
|
||||
/>
|
||||
</Paper>
|
||||
</div>
|
||||
</Layout.Col>
|
||||
<Layout.Col span="7" style={{"height": "100%"}}>
|
||||
<Paper className={"doudizhu-probability-paper"} elevation={3}>
|
||||
<div className={"probability-player"}>Current: 0</div>
|
||||
<Divider />
|
||||
<div className={"probability-table"}>
|
||||
<div className={"probability-item"}>
|
||||
{this.computeProbabilityItem(0)}
|
||||
</div>
|
||||
<div className={"probability-item"}>
|
||||
{this.computeProbabilityItem(1)}
|
||||
</div>
|
||||
<div className={"probability-item"}>
|
||||
{this.computeProbabilityItem(2)}
|
||||
</div>
|
||||
</div>
|
||||
</Paper>
|
||||
</Layout.Col>
|
||||
</Layout.Row>
|
||||
<div className="game-controller">
|
||||
<Layout.Row>
|
||||
<Layout.Col span="24">
|
||||
|
|
Loading…
Reference in New Issue