add new example model download links; implementing new doudizhu replay probability view

This commit is contained in:
Songyi Huang 2021-06-01 23:40:38 -07:00
parent 983a9c8b43
commit 31723396ea
2 changed files with 354 additions and 217 deletions

View File

@ -115,6 +115,7 @@ function MenuBar(props) {
}; };
const [uploadDialogOpen, setUploadDialogOpen] = React.useState(false); const [uploadDialogOpen, setUploadDialogOpen] = React.useState(false);
const [downloadChannelDialogOpen, setDownloadChannelDialogOpen] = React.useState(false);
const openUploadDialog = () => { const openUploadDialog = () => {
setUploadDialogOpen(true); setUploadDialogOpen(true);
@ -133,6 +134,10 @@ function MenuBar(props) {
setUploadDialogOpen(false); setUploadDialogOpen(false);
}; };
const handleDownloadChannelDialogClose = () => {
setDownloadChannelDialogOpen(false);
};
let uploadRef = React.createRef(); let uploadRef = React.createRef();
const handleSubmitUpload = () => { const handleSubmitUpload = () => {
// check if data to upload is legal // check if data to upload is legal
@ -326,12 +331,14 @@ function MenuBar(props) {
DQN model DQN model
</Link>{' '} </Link>{' '}
for Leduc Holdem or{' '} for Leduc Holdem or{' '}
<Link <a
href={apiUrl + '/tournament/download_examples?name=example_luduc_rule_model'} href="#"
download onClick={() => {
setDownloadChannelDialogOpen(true);
}}
> >
DMC model DMC model
</Link>{' '} </a>{' '}
for Doudizhu to test and learn about model upload functionality. for Doudizhu to test and learn about model upload functionality.
</Typography> </Typography>
</CardContent> </CardContent>
@ -408,16 +415,46 @@ function MenuBar(props) {
</Loading> </Loading>
</Dialog> </Dialog>
<Dialog <Dialog
open={uploadDialogOpen} open={downloadChannelDialogOpen}
onClose={handleUploadDialogClose} onClose={handleDownloadChannelDialogClose}
aria-labelledby="form-dialog-title" aria-labelledby="form-dialog-title"
disableBackdropClick={true}
> >
<DialogTitle id="form-dialog-title">Choose Download Channel</DialogTitle> <DialogTitle id="form-dialog-title">Choose Download Channel</DialogTitle>
<DialogContent> <DialogContent>
<Button>Google Drive</Button> <div>
<Button>百度网盘</Button> <Button
href="https://drive.google.com/file/d/127XEKfEJrYyPtobT4u7j4_KBqk19FUej/view?usp=sharing"
target="_blank"
color="primary"
variant="contained"
fullWidth
>
Google Drive
</Button>
<Button
href="https://pan.baidu.com/s/1fHH86DBpGRnN58q9ctAt6A"
target="_blank"
style={{ marginTop: '20px', marginBottom: '10px' }}
color="primary"
variant="contained"
fullWidth
>
百度网盘
</Button>
<div style={{ width: '100%', textAlign: 'center', marginBottom: '20px' }}>(提取码: s54s)</div>
</div>
</DialogContent> </DialogContent>
<DialogActions>
<Button
onClick={() => {
setDownloadChannelDialogOpen(false);
}}
variant="contained"
disableElevation
>
Cancel
</Button>
</DialogActions>
</Dialog> </Dialog>
</Drawer> </Drawer>
); );

View File

@ -1,28 +1,27 @@
import React from 'react';
import axios from 'axios';
import '../../assets/gameview.scss';
import { DoudizhuGameBoard } from '../../components/GameBoard';
import {removeCards, doubleRaf, deepCopy, computeHandCardsWidth, translateCardData} from "../../utils";
import { apiUrl } from "../../utils/config";
import { Layout, Message, Loading } from 'element-react';
import Slider from '@material-ui/core/Slider';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import Paper from '@material-ui/core/Paper'; import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import Divider from '@material-ui/core/Divider'; import Divider from '@material-ui/core/Divider';
import LinearProgress from '@material-ui/core/LinearProgress'; import LinearProgress from '@material-ui/core/LinearProgress';
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded'; import Paper from '@material-ui/core/Paper';
import Slider from '@material-ui/core/Slider';
import PauseCircleOutlineRoundedIcon from '@material-ui/icons/PauseCircleOutlineRounded'; import PauseCircleOutlineRoundedIcon from '@material-ui/icons/PauseCircleOutlineRounded';
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
import ReplayRoundedIcon from '@material-ui/icons/ReplayRounded'; import ReplayRoundedIcon from '@material-ui/icons/ReplayRounded';
// import NotInterestedIcon from '@material-ui/icons/NotInterested'; // import NotInterestedIcon from '@material-ui/icons/NotInterested';
import SkipNextIcon from '@material-ui/icons/SkipNext'; import SkipNextIcon from '@material-ui/icons/SkipNext';
import SkipPreviousIcon from '@material-ui/icons/SkipPrevious'; import SkipPreviousIcon from '@material-ui/icons/SkipPrevious';
import DialogTitle from "@material-ui/core/DialogTitle"; import axios from 'axios';
import DialogContent from "@material-ui/core/DialogContent"; import { Layout, Loading, Message } from 'element-react';
import DialogContentText from "@material-ui/core/DialogContentText"; import qs from 'query-string';
import DialogActions from "@material-ui/core/DialogActions"; import React from 'react';
import Dialog from "@material-ui/core/Dialog"; import '../../assets/gameview.scss';
import qs from "query-string"; import { DoudizhuGameBoard } from '../../components/GameBoard';
import { computeHandCardsWidth, deepCopy, doubleRaf, removeCards, translateCardData } from '../../utils';
import { apiUrl } from '../../utils/config';
class DoudizhuReplayView extends React.Component { class DoudizhuReplayView extends React.Component {
constructor(props) { constructor(props) {
@ -35,13 +34,13 @@ class DoudizhuReplayView extends React.Component {
this.moveHistory = []; this.moveHistory = [];
this.gameStateHistory = []; this.gameStateHistory = [];
this.initGameState = { this.initGameState = {
gameStatus: "ready", // "ready", "playing", "paused", "over" gameStatus: 'ready', // "ready", "playing", "paused", "over"
playerInfo: [], playerInfo: [],
hands: [], hands: [],
latestAction: [[], [], []], latestAction: [[], [], []],
mainViewerId: mainViewerId, mainViewerId: mainViewerId,
turn: 0, turn: 0,
toggleFade: "", toggleFade: '',
currentPlayer: null, currentPlayer: null,
considerationTime: this.initConsiderationTime, considerationTime: this.initConsiderationTime,
@ -53,13 +52,13 @@ class DoudizhuReplayView extends React.Component {
gameStateLoop: null, gameStateLoop: null,
gameSpeed: 0, gameSpeed: 0,
gameEndDialog: false, gameEndDialog: false,
gameEndDialogText: "", gameEndDialogText: '',
fullScreenLoading: false fullScreenLoading: false,
}; };
} }
cardStr2Arr(cardStr) { cardStr2Arr(cardStr) {
return cardStr === "pass" || cardStr === "" ? "pass" : cardStr.split(" "); return cardStr === 'pass' || cardStr === '' ? 'pass' : cardStr.split(' ');
} }
generateNewState() { generateNewState() {
@ -71,44 +70,49 @@ class DoudizhuReplayView extends React.Component {
} else { } else {
let newMove = this.moveHistory[this.state.gameInfo.turn]; let newMove = this.moveHistory[this.state.gameInfo.turn];
if (newMove.playerIdx === this.state.gameInfo.currentPlayer) { if (newMove.playerIdx === this.state.gameInfo.currentPlayer) {
gameInfo.latestAction[newMove.playerIdx] = this.cardStr2Arr(Array.isArray(newMove.move) ? newMove.move.join(" ") : newMove.move); gameInfo.latestAction[newMove.playerIdx] = this.cardStr2Arr(
Array.isArray(newMove.move) ? newMove.move.join(' ') : newMove.move,
);
gameInfo.turn++; gameInfo.turn++;
gameInfo.currentPlayer = (gameInfo.currentPlayer + 1) % 3; gameInfo.currentPlayer = (gameInfo.currentPlayer + 1) % 3;
// take away played cards from player's hands // take away played cards from player's hands
const remainedCards = removeCards(gameInfo.latestAction[newMove.playerIdx], gameInfo.hands[newMove.playerIdx]); const remainedCards = removeCards(
gameInfo.latestAction[newMove.playerIdx],
gameInfo.hands[newMove.playerIdx],
);
if (remainedCards !== false) { if (remainedCards !== false) {
gameInfo.hands[newMove.playerIdx] = remainedCards; gameInfo.hands[newMove.playerIdx] = remainedCards;
} else { } else {
Message({ Message({
message: "Cannot find cards in move from player's hand", message: "Cannot find cards in move from player's hand",
type: "error", type: 'error',
showClose: true showClose: true,
}); });
} }
// check if game ends // check if game ends
if (remainedCards.length === 0) { if (remainedCards.length === 0) {
doubleRaf(() => { doubleRaf(() => {
const winner = this.state.gameInfo.playerInfo.find(element => { const winner = this.state.gameInfo.playerInfo.find((element) => {
return element.index === newMove.playerIdx; return element.index === newMove.playerIdx;
}); });
if (winner) { if (winner) {
gameInfo.gameStatus = "over"; gameInfo.gameStatus = 'over';
this.setState({ gameInfo: gameInfo }); this.setState({ gameInfo: gameInfo });
if(winner.role === "landlord") if (winner.role === 'landlord')
setTimeout(() => { setTimeout(() => {
const mes = "Landlord Wins"; const mes = 'Landlord Wins';
this.setState({ gameEndDialog: true, gameEndDialogText: mes }); this.setState({ gameEndDialog: true, gameEndDialogText: mes });
}, 200); }, 200);
else else
setTimeout(() => { setTimeout(() => {
const mes = "Peasants Win"; const mes = 'Peasants Win';
this.setState({ gameEndDialog: true, gameEndDialogText: mes }); this.setState({ gameEndDialog: true, gameEndDialogText: mes });
}, 200); }, 200);
} else { } else {
Message({ Message({
message: "Error in finding winner", message: 'Error in finding winner',
type: "error", type: 'error',
showClose: true showClose: true,
}); });
} }
}); });
@ -118,9 +122,9 @@ class DoudizhuReplayView extends React.Component {
gameInfo.completedPercent += 100.0 / (this.moveHistory.length - 1); gameInfo.completedPercent += 100.0 / (this.moveHistory.length - 1);
} else { } else {
Message({ Message({
message: "Mismatched current player index", message: 'Mismatched current player index',
type: "error", type: 'error',
showClose: true showClose: true,
}); });
} }
// if current state is new to game state history, push it to the game state history array // if current state is new to game state history, push it to the game state history array
@ -128,9 +132,9 @@ class DoudizhuReplayView extends React.Component {
this.gameStateHistory.push(gameInfo); this.gameStateHistory.push(gameInfo);
} else { } else {
Message({ Message({
message: "inconsistent game state history length and turn number", message: 'inconsistent game state history length and turn number',
type: "error", type: 'error',
showClose: true showClose: true,
}); });
} }
} }
@ -145,7 +149,7 @@ class DoudizhuReplayView extends React.Component {
currentConsiderationTime = currentConsiderationTime < 0 ? 0 : currentConsiderationTime; currentConsiderationTime = currentConsiderationTime < 0 ? 0 : currentConsiderationTime;
if (currentConsiderationTime === 0 && this.state.gameSpeed < 2) { if (currentConsiderationTime === 0 && this.state.gameSpeed < 2) {
let gameInfo = deepCopy(this.state.gameInfo); let gameInfo = deepCopy(this.state.gameInfo);
gameInfo.toggleFade = "fade-out"; gameInfo.toggleFade = 'fade-out';
this.setState({ gameInfo: gameInfo }); this.setState({ gameInfo: gameInfo });
} }
let gameInfo = deepCopy(this.state.gameInfo); let gameInfo = deepCopy(this.state.gameInfo);
@ -154,17 +158,17 @@ class DoudizhuReplayView extends React.Component {
this.gameStateTimer(); this.gameStateTimer();
} else { } else {
let gameInfo = this.generateNewState(); let gameInfo = this.generateNewState();
if(gameInfo.gameStatus === "over") return; if (gameInfo.gameStatus === 'over') return;
gameInfo.gameStatus = "playing"; gameInfo.gameStatus = 'playing';
if(this.state.gameInfo.toggleFade === "fade-out") { if (this.state.gameInfo.toggleFade === 'fade-out') {
gameInfo.toggleFade = "fade-in"; gameInfo.toggleFade = 'fade-in';
} }
this.setState({ gameInfo: gameInfo }, () => { this.setState({ gameInfo: gameInfo }, () => {
// toggle fade in // toggle fade in
if(this.state.gameInfo.toggleFade !== ""){ if (this.state.gameInfo.toggleFade !== '') {
setTimeout(() => { setTimeout(() => {
let gameInfo = deepCopy(this.state.gameInfo); let gameInfo = deepCopy(this.state.gameInfo);
gameInfo.toggleFade = ""; gameInfo.toggleFade = '';
this.setState({ gameInfo: gameInfo }); this.setState({ gameInfo: gameInfo });
}, 200); }, 200);
} }
@ -179,20 +183,29 @@ class DoudizhuReplayView extends React.Component {
// start full screen loading // start full screen loading
this.setState({ fullScreenLoading: true }); this.setState({ fullScreenLoading: true });
axios.get(requestUrl) axios
.then(res => { .get(requestUrl)
.then((res) => {
res = res.data; res = res.data;
// for test use
if (typeof res === 'string') res = JSON.parse(res.replaceAll("'", '"').replaceAll('None', 'null'));
console.log(res);
// init replay info // init replay info
this.moveHistory = res.moveHistory; this.moveHistory = res.moveHistory;
let gameInfo = deepCopy(this.initGameState); let gameInfo = deepCopy(this.initGameState);
gameInfo.gameStatus = "playing"; gameInfo.gameStatus = 'playing';
gameInfo.playerInfo = res.playerInfo; gameInfo.playerInfo = res.playerInfo;
gameInfo.hands = res.initHands.map(element => { gameInfo.hands = res.initHands.map((element) => {
return this.cardStr2Arr(element); return this.cardStr2Arr(element);
}); });
// the first player should be landlord // the first player should be landlord
gameInfo.currentPlayer = res.playerInfo.find(element=>{return element.role === "landlord"}).index; gameInfo.currentPlayer = res.playerInfo.find((element) => {
if(this.gameStateHistory.length === 0){ // fix replay bug return element.role === 'landlord';
}).index;
if (this.gameStateHistory.length === 0) {
// fix replay bug
this.gameStateHistory.push(gameInfo); this.gameStateHistory.push(gameInfo);
} }
this.setState({ gameInfo: gameInfo, fullScreenLoading: false }, () => { this.setState({ gameInfo: gameInfo, fullScreenLoading: false }, () => {
@ -207,12 +220,12 @@ class DoudizhuReplayView extends React.Component {
.catch(() => { .catch(() => {
this.setState({ fullScreenLoading: false }); this.setState({ fullScreenLoading: false });
Message({ Message({
message: "Error in getting replay data", message: 'Error in getting replay data',
type: "error", type: 'error',
showClose: true showClose: true,
}); });
}) });
}; }
runNewTurn() { runNewTurn() {
this.gameStateTimer(); this.gameStateTimer();
@ -224,14 +237,14 @@ class DoudizhuReplayView extends React.Component {
this.gameStateTimeout = null; this.gameStateTimeout = null;
} }
let gameInfo = deepCopy(this.state.gameInfo); let gameInfo = deepCopy(this.state.gameInfo);
gameInfo.gameStatus = "paused"; gameInfo.gameStatus = 'paused';
this.setState({ gameInfo: gameInfo }); this.setState({ gameInfo: gameInfo });
} }
resumeReplay() { resumeReplay() {
this.gameStateTimer(); this.gameStateTimer();
let gameInfo = deepCopy(this.state.gameInfo); let gameInfo = deepCopy(this.state.gameInfo);
gameInfo.gameStatus = "playing"; gameInfo.gameStatus = 'playing';
this.setState({ gameInfo: gameInfo }); this.setState({ gameInfo: gameInfo });
} }
@ -241,27 +254,79 @@ class DoudizhuReplayView extends React.Component {
gameStatusButton(status) { gameStatusButton(status) {
switch (status) { switch (status) {
case "ready": case 'ready':
return <Button className={"status-button"} variant={"contained"} startIcon={<PlayArrowRoundedIcon />} color="primary" onClick={()=>{this.startReplay()}}>Start</Button>; return (
case "playing": <Button
return <Button className={"status-button"} variant={"contained"} startIcon={<PauseCircleOutlineRoundedIcon />} color="secondary" onClick={()=>{this.pauseReplay()}}>Pause</Button>; className={'status-button'}
case "paused": variant={'contained'}
return <Button className={"status-button"} variant={"contained"} startIcon={<PlayArrowRoundedIcon />} color="primary" onClick={()=>{this.resumeReplay()}}>Resume</Button>; startIcon={<PlayArrowRoundedIcon />}
case "over": color="primary"
return <Button className={"status-button"} variant={"contained"} startIcon={<ReplayRoundedIcon />} color="primary" onClick={()=>{this.startReplay()}}>Restart</Button>; onClick={() => {
this.startReplay();
}}
>
Start
</Button>
);
case 'playing':
return (
<Button
className={'status-button'}
variant={'contained'}
startIcon={<PauseCircleOutlineRoundedIcon />}
color="secondary"
onClick={() => {
this.pauseReplay();
}}
>
Pause
</Button>
);
case 'paused':
return (
<Button
className={'status-button'}
variant={'contained'}
startIcon={<PlayArrowRoundedIcon />}
color="primary"
onClick={() => {
this.resumeReplay();
}}
>
Resume
</Button>
);
case 'over':
return (
<Button
className={'status-button'}
variant={'contained'}
startIcon={<ReplayRoundedIcon />}
color="primary"
onClick={() => {
this.startReplay();
}}
>
Restart
</Button>
);
default: default:
alert(`undefined game status: ${status}`); alert(`undefined game status: ${status}`);
} }
} }
computeSingleLineHand(cards) { computeSingleLineHand(cards) {
if(cards === "pass"){ if (cards === 'pass') {
return <div className={"non-card "+this.state.gameInfo.toggleFade}><span>Pass</span></div> return (
<div className={'non-card ' + this.state.gameInfo.toggleFade}>
<span>Pass</span>
</div>
);
} else { } else {
return ( return (
<div className={"unselectable playingCards loose "+this.state.gameInfo.toggleFade}> <div className={'unselectable playingCards loose ' + this.state.gameInfo.toggleFade}>
<ul className="hand" style={{ width: computeHandCardsWidth(cards.length, 10) }}> <ul className="hand" style={{ width: computeHandCardsWidth(cards.length, 10) }}>
{cards.map(card=>{ {cards.map((card) => {
const [rankClass, suitClass, rankText, suitText] = translateCardData(card); const [rankClass, suitClass, rankText, suitText] = translateCardData(card);
return ( return (
<li key={`handCard-${card}`}> <li key={`handCard-${card}`}>
@ -274,55 +339,65 @@ class DoudizhuReplayView extends React.Component {
})} })}
</ul> </ul>
</div> </div>
) );
} }
} }
computeProbabilityItem(idx) { computeProbabilityItem(idx) {
return <span className={"waiting"}>Currently Unavailable...</span> // return <span className={'waiting'}>Currently Unavailable...</span>;
// if(this.state.gameInfo.gameStatus !== "ready" && this.state.gameInfo.turn < this.moveHistory.length){ if (this.state.gameInfo.gameStatus !== 'ready' && this.state.gameInfo.turn < this.moveHistory.length) {
// let style = {}; let style = {};
// style["backgroundColor"] = this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? `rgba(63, 81, 181, ${this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability})` : "#bdbdbd"; // style["backgroundColor"] = this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? `rgba(63, 81, 181, ${this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability})` : "#bdbdbd";
// return ( // let probabilities
// <div className={"playing"} style={style}> return (
// <div className="probability-move"> <div className={'playing'} style={style}>
// {this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? <div className="probability-move">
// this.computeSingleLineHand(this.cardStr2Arr(this.moveHistory[this.state.gameInfo.turn].probabilities[idx].move)) {this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? (
// : this.computeSingleLineHand(
// <NotInterestedIcon fontSize="large" /> this.cardStr2Arr(this.moveHistory[this.state.gameInfo.turn].probabilities[idx].move),
// } )
// </div> ) : (
// {this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? <NotInterestedIcon fontSize="large" />
// <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> {this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? (
// : <div className={'non-card'}>
// "" <span>
// } {this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx
// </div> ? `Probability ${(
// ) this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability *
// }else { 100
// return <span className={"waiting"}>Waiting...</span> ).toFixed(2)}%`
// } : ''}
</span>
</div>
) : (
''
)}
</div>
);
} else {
return <span className={'waiting'}>Waiting...</span>;
}
} }
go2PrevGameState() { go2PrevGameState() {
let gameInfo = deepCopy(this.gameStateHistory[this.state.gameInfo.turn - 1]); let gameInfo = deepCopy(this.gameStateHistory[this.state.gameInfo.turn - 1]);
gameInfo.gameStatus = "paused"; gameInfo.gameStatus = 'paused';
gameInfo.toggleFade = ""; gameInfo.toggleFade = '';
this.setState({ gameInfo: gameInfo }); this.setState({ gameInfo: gameInfo });
} }
go2NextGameState() { go2NextGameState() {
let gameInfo = this.generateNewState(); let gameInfo = this.generateNewState();
if(gameInfo.gameStatus === "over") return; if (gameInfo.gameStatus === 'over') return;
gameInfo.gameStatus = "paused"; gameInfo.gameStatus = 'paused';
gameInfo.toggleFade = ""; gameInfo.toggleFade = '';
this.setState({ gameInfo: gameInfo }); this.setState({ gameInfo: gameInfo });
} }
handleCloseGameEndDialog() { handleCloseGameEndDialog() {
this.setState({gameEndDialog: false, gameEndDialogText: ""}); this.setState({ gameEndDialog: false, gameEndDialogText: '' });
} }
render() { render() {
@ -357,34 +432,44 @@ class DoudizhuReplayView extends React.Component {
{ {
value: 3, value: 3,
label: 'x8', label: 'x8',
} },
]; ];
return ( return (
<div> <div>
<Dialog <Dialog
open={this.state.gameEndDialog} open={this.state.gameEndDialog}
onClose={()=>{this.handleCloseGameEndDialog()}} onClose={() => {
this.handleCloseGameEndDialog();
}}
aria-labelledby="alert-dialog-title" aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description" aria-describedby="alert-dialog-description"
> >
<DialogTitle id="alert-dialog-title" style={{"width": "200px"}}>{"Game Ends!"}</DialogTitle> <DialogTitle id="alert-dialog-title" style={{ width: '200px' }}>
{'Game Ends!'}
</DialogTitle>
<DialogContent> <DialogContent>
<DialogContentText id="alert-dialog-description"> <DialogContentText id="alert-dialog-description">
{this.state.gameEndDialogText} {this.state.gameEndDialogText}
</DialogContentText> </DialogContentText>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={()=>{this.handleCloseGameEndDialog()}} color="primary" autoFocus> <Button
onClick={() => {
this.handleCloseGameEndDialog();
}}
color="primary"
autoFocus
>
OK OK
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
<div className={"doudizhu-view-container"}> <div className={'doudizhu-view-container'}>
<Layout.Row style={{"height": "540px"}}> <Layout.Row style={{ height: '540px' }}>
<Layout.Col style={{"height": "100%"}} span="17"> <Layout.Col style={{ height: '100%' }} span="17">
<div style={{"height": "100%"}}> <div style={{ height: '100%' }}>
<Paper className={"doudizhu-gameboard-paper"} elevation={3}> <Paper className={'doudizhu-gameboard-paper'} elevation={3}>
<DoudizhuGameBoard <DoudizhuGameBoard
playerInfo={this.state.gameInfo.playerInfo} playerInfo={this.state.gameInfo.playerInfo}
hands={this.state.gameInfo.hands} hands={this.state.gameInfo.hands}
@ -400,27 +485,25 @@ class DoudizhuReplayView extends React.Component {
</Paper> </Paper>
</div> </div>
</Layout.Col> </Layout.Col>
<Layout.Col span="7" style={{"height": "100%"}}> <Layout.Col span="7" style={{ height: '100%' }}>
<Paper className={"doudizhu-probability-paper"} elevation={3}> <Paper className={'doudizhu-probability-paper'} elevation={3}>
<div className={"probability-player"}> <div className={'probability-player'}>
{ {this.state.gameInfo.playerInfo.length > 0 ? (
this.state.gameInfo.playerInfo.length > 0 ? <span>
<span>Current Player: {this.state.gameInfo.currentPlayer}<br/>Role: {this.state.gameInfo.playerInfo[this.state.gameInfo.currentPlayer].role}</span> Current Player: {this.state.gameInfo.currentPlayer}
: <br />
Role:{' '}
{this.state.gameInfo.playerInfo[this.state.gameInfo.currentPlayer].role}
</span>
) : (
<span>Waiting...</span> <span>Waiting...</span>
} )}
</div> </div>
<Divider /> <Divider />
<div className={"probability-table"}> <div className={'probability-table'}>
<div className={"probability-item"}> <div className={'probability-item'}>{this.computeProbabilityItem(0)}</div>
{this.computeProbabilityItem(0)} <div className={'probability-item'}>{this.computeProbabilityItem(1)}</div>
</div> <div className={'probability-item'}>{this.computeProbabilityItem(2)}</div>
<div className={"probability-item"}>
{this.computeProbabilityItem(1)}
</div>
<div className={"probability-item"}>
{this.computeProbabilityItem(2)}
</div>
</div> </div>
</Paper> </Paper>
</Layout.Col> </Layout.Col>
@ -430,15 +513,20 @@ class DoudizhuReplayView extends React.Component {
</div> </div>
<Loading loading={this.state.fullScreenLoading}> <Loading loading={this.state.fullScreenLoading}>
<div className="game-controller"> <div className="game-controller">
<Paper className={"game-controller-paper"} elevation={3}> <Paper className={'game-controller-paper'} elevation={3}>
<Layout.Row style={{"height": "51px"}}> <Layout.Row style={{ height: '51px' }}>
<Layout.Col span="7" style={{"height": "51px", "lineHeight": "48px"}}> <Layout.Col span="7" style={{ height: '51px', lineHeight: '48px' }}>
<div> <div>
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
disabled={this.state.gameInfo.gameStatus !== "paused" || this.state.gameInfo.turn === 0} disabled={
onClick={()=>{this.go2PrevGameState()}} this.state.gameInfo.gameStatus !== 'paused' ||
this.state.gameInfo.turn === 0
}
onClick={() => {
this.go2PrevGameState();
}}
> >
<SkipPreviousIcon /> <SkipPreviousIcon />
</Button> </Button>
@ -446,30 +534,42 @@ class DoudizhuReplayView extends React.Component {
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
disabled={this.state.gameInfo.gameStatus !== "paused"} disabled={this.state.gameInfo.gameStatus !== 'paused'}
onClick={()=>{this.go2NextGameState()}} onClick={() => {
this.go2NextGameState();
}}
> >
<SkipNextIcon /> <SkipNextIcon />
</Button> </Button>
</div> </div>
</Layout.Col> </Layout.Col>
<Layout.Col span="1" style={{"height": "100%", "width": "1px"}}> <Layout.Col span="1" style={{ height: '100%', width: '1px' }}>
<Divider orientation="vertical" /> <Divider orientation="vertical" />
</Layout.Col> </Layout.Col>
<Layout.Col span="3" style={{"height": "51px", "lineHeight": "51px", "marginLeft": "-1px", "marginRight": "-1px"}}> <Layout.Col
<div style={{"textAlign": "center"}}>{`Turn ${this.state.gameInfo.turn}`}</div> span="3"
style={{
height: '51px',
lineHeight: '51px',
marginLeft: '-1px',
marginRight: '-1px',
}}
>
<div style={{ textAlign: 'center' }}>{`Turn ${this.state.gameInfo.turn}`}</div>
</Layout.Col> </Layout.Col>
<Layout.Col span="1" style={{"height": "100%", "width": "1px"}}> <Layout.Col span="1" style={{ height: '100%', width: '1px' }}>
<Divider orientation="vertical" /> <Divider orientation="vertical" />
</Layout.Col> </Layout.Col>
<Layout.Col span="14"> <Layout.Col span="14">
<div> <div>
<label className={"form-label-left"}>Game Speed</label> <label className={'form-label-left'}>Game Speed</label>
<div style={{"marginLeft": "100px", "marginRight": "10px"}}> <div style={{ marginLeft: '100px', marginRight: '10px' }}>
<Slider <Slider
value={this.state.gameSpeed} value={this.state.gameSpeed}
getAriaValueText={sliderValueText} getAriaValueText={sliderValueText}
onChange={(e, newVal)=>{this.changeGameSpeed(newVal)}} onChange={(e, newVal) => {
this.changeGameSpeed(newVal);
}}
aria-labelledby="discrete-slider-custom" aria-labelledby="discrete-slider-custom"
step={1} step={1}
min={-3} min={-3}
@ -487,7 +587,7 @@ class DoudizhuReplayView extends React.Component {
</Loading> </Loading>
</div> </div>
</div> </div>
) );
} }
} }