check if the game ends
|
@ -0,0 +1,150 @@
|
||||||
|
{
|
||||||
|
"initHands": [
|
||||||
|
"S2 H2 HK DK HQ CQ DQ CJ S9 H9 D9 C7 S6 H6 C4 D4 S3",
|
||||||
|
"C2 HA CA DA SQ ST HT D8 S7 H7 C6 D6 S5 H5 C5 S4 H4",
|
||||||
|
"RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3 D3"
|
||||||
|
],
|
||||||
|
"playerInfo": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"index": 0,
|
||||||
|
"role": "peasant"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"index": 1,
|
||||||
|
"role": "peasant"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"index": 2,
|
||||||
|
"role": "landlord"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"moveHistory": [
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "H3 S3 D3 D5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 0,
|
||||||
|
"move": "S9 H9 D9 S3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 1,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "SJ HJ DJ D7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 0,
|
||||||
|
"move": "HQ CQ DQ C7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 1,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 0,
|
||||||
|
"move": "C4 D4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 1,
|
||||||
|
"move": "ST HT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "SK CK"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 0,
|
||||||
|
"move": "S2 H2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 1,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 0,
|
||||||
|
"move": "S6 H6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 1,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "CT DT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 0,
|
||||||
|
"move": "HK DK"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 1,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "RJ BJ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 0,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 1,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "S8 H8 C8 C9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 0,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 1,
|
||||||
|
"move": "HA CA DA H5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 0,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 1,
|
||||||
|
"move": "SQ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "D2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 0,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 1,
|
||||||
|
"move": "P"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"playerIdx": 2,
|
||||||
|
"move": "SA"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import './index.scss';
|
import '../../assets/doudizhu.scss';
|
||||||
|
|
||||||
class DoudizhuGameBoard extends React.Component {
|
class DoudizhuGameBoard extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -15,9 +15,9 @@ class DoudizhuGameBoard extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
translateCardData(card) {
|
translateCardData(card) {
|
||||||
let rankClass = "";
|
let rankClass;
|
||||||
let suitClass = "";
|
let suitClass = "";
|
||||||
let rankText = "";
|
let rankText;
|
||||||
let suitText = "";
|
let suitText = "";
|
||||||
// translate rank
|
// translate rank
|
||||||
if(card === "RJ"){
|
if(card === "RJ"){
|
||||||
|
@ -51,7 +51,6 @@ class DoudizhuGameBoard extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
computeSingleLineHand(cards) {
|
computeSingleLineHand(cards) {
|
||||||
console.log(cards);
|
|
||||||
if(cards === "P"){
|
if(cards === "P"){
|
||||||
return <div className="non-card"><span>Pass</span></div>
|
return <div className="non-card"><span>Pass</span></div>
|
||||||
}else{
|
}else{
|
||||||
|
@ -68,7 +67,7 @@ class DoudizhuGameBoard extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
computeSideHand(cards) {
|
computeSideHand(cards) {
|
||||||
let upCards = [];
|
let upCards;
|
||||||
let downCards = [];
|
let downCards = [];
|
||||||
if(cards.length > 10){
|
if(cards.length > 10){
|
||||||
upCards = cards.slice(0, 10);
|
upCards = cards.slice(0, 10);
|
||||||
|
@ -107,7 +106,6 @@ class DoudizhuGameBoard extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
playerDecisionArea(playerIdx){
|
playerDecisionArea(playerIdx){
|
||||||
console.log(this.props.currentPlayer, playerIdx);
|
|
||||||
if(this.props.currentPlayer === playerIdx){
|
if(this.props.currentPlayer === playerIdx){
|
||||||
return <div className="non-card"><span>{`Consideration Time: ${this.millisecond2Second(this.props.considerationTime)}s`}</span></div>
|
return <div className="non-card"><span>{`Consideration Time: ${this.millisecond2Second(this.props.considerationTime)}s`}</span></div>
|
||||||
}else{
|
}else{
|
||||||
|
@ -115,6 +113,13 @@ class DoudizhuGameBoard extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||||
|
if(prevProps.turn !== this.props.turn){
|
||||||
|
// new turn starts
|
||||||
|
this.props.runNewTurn(prevProps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
// compute the id as well as index in list for every player
|
// compute the id as well as index in list for every player
|
||||||
const bottomId = this.props.mainPlayerId;
|
const bottomId = this.props.mainPlayerId;
|
||||||
|
@ -140,7 +145,6 @@ class DoudizhuGameBoard extends React.Component {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div style={{width: "100%", height: "100%", backgroundColor: "#ffcc99", position: "relative"}}>
|
<div style={{width: "100%", height: "100%", backgroundColor: "#ffcc99", position: "relative"}}>
|
||||||
<div>{`Current Player: ${this.props.currentPlayer} , Consideration Time: ${this.props.considerationTime}`}</div>
|
|
||||||
<div id={"left-player"}>
|
<div id={"left-player"}>
|
||||||
<div className="player-main-area">
|
<div className="player-main-area">
|
||||||
<div className="player-info">
|
<div className="player-info">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import './index.css';
|
import './assets/index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import * as serviceWorker from './serviceWorker';
|
import * as serviceWorker from './serviceWorker';
|
||||||
|
|
||||||
|
|
|
@ -19,3 +19,10 @@ export function removeCards(cards, hands){ // remove cards from hands, retur
|
||||||
return remainedHands;
|
return remainedHands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doubleRaf (callback) {
|
||||||
|
// secure all the animation got rendered before callback function gets executed
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
requestAnimationFrame(callback)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import DoudizhuGameBoard from '../components/GameBoard';
|
import DoudizhuGameBoard from '../components/GameBoard';
|
||||||
import webSocket from "socket.io-client";
|
import webSocket from "socket.io-client";
|
||||||
import {removeCards} from "../utils";
|
import {removeCards, doubleRaf} from "../utils";
|
||||||
|
|
||||||
class DoudizhuGameView extends React.Component {
|
class DoudizhuGameView extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const mainViewerId = 0; // Id of the player at the bottom of screen
|
const mainViewerId = 0; // Id of the player at the bottom of screen
|
||||||
this.initConsiderationTime = 2000;
|
this.initConsiderationTime = 0;
|
||||||
this.considerationTimeDeduction = 1000;
|
this.considerationTimeDeduction = 100;
|
||||||
this.gameStateTimeout = null;
|
this.gameStateTimeout = null;
|
||||||
|
|
||||||
this.initGameState = {
|
this.initGameState = {
|
||||||
|
@ -20,7 +20,7 @@ class DoudizhuGameView extends React.Component {
|
||||||
turn: 0,
|
turn: 0,
|
||||||
currentPlayer: null,
|
currentPlayer: null,
|
||||||
considerationTime: this.initConsiderationTime,
|
considerationTime: this.initConsiderationTime,
|
||||||
}
|
};
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
ws: null,
|
ws: null,
|
||||||
|
@ -86,7 +86,6 @@ class DoudizhuGameView extends React.Component {
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// getting player actions
|
// getting player actions
|
||||||
console.log(message.message);
|
|
||||||
let res = message.message;
|
let res = message.message;
|
||||||
if(res.turn === this.state.gameInfo.turn && res.playerIdx === this.state.gameInfo.currentPlayer){
|
if(res.turn === this.state.gameInfo.turn && res.playerIdx === this.state.gameInfo.currentPlayer){
|
||||||
let gameInfo = JSON.parse(JSON.stringify(this.state.gameInfo));
|
let gameInfo = JSON.parse(JSON.stringify(this.state.gameInfo));
|
||||||
|
@ -101,8 +100,9 @@ class DoudizhuGameView extends React.Component {
|
||||||
console.log("Cannot find cards in move from player's hand");
|
console.log("Cannot find cards in move from player's hand");
|
||||||
}
|
}
|
||||||
gameInfo.considerationTime = this.initConsiderationTime;
|
gameInfo.considerationTime = this.initConsiderationTime;
|
||||||
this.setState({gameInfo: gameInfo});
|
this.setState({gameInfo: gameInfo}, ()=>{
|
||||||
this.gameStateTimer();
|
|
||||||
|
});
|
||||||
}else{
|
}else{
|
||||||
console.log("Mismatched game turn or current player index", message);
|
console.log("Mismatched game turn or current player index", message);
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,26 @@ class DoudizhuGameView extends React.Component {
|
||||||
this.setState({ws: ws});
|
this.setState({ws: ws});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
runNewTurn(prevTurn){
|
||||||
|
// check if the game ends
|
||||||
|
if(this.state.gameInfo.hands[prevTurn.currentPlayer].length === 0){
|
||||||
|
doubleRaf(()=>{
|
||||||
|
const winner = this.state.gameInfo.playerInfo.find(element => {
|
||||||
|
return element.index === prevTurn.currentPlayer;
|
||||||
|
});
|
||||||
|
if(winner){
|
||||||
|
if(winner.role === "landlord")
|
||||||
|
alert("Landlord Wins");
|
||||||
|
else
|
||||||
|
alert("Peasants Win");
|
||||||
|
}else{
|
||||||
|
console.log("Error in finding winner");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}else
|
||||||
|
this.gameStateTimer();
|
||||||
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -127,12 +147,17 @@ class DoudizhuGameView extends React.Component {
|
||||||
mainPlayerId={this.state.gameInfo.mainViewerId}
|
mainPlayerId={this.state.gameInfo.mainViewerId}
|
||||||
currentPlayer={this.state.gameInfo.currentPlayer}
|
currentPlayer={this.state.gameInfo.currentPlayer}
|
||||||
considerationTime={this.state.gameInfo.considerationTime}
|
considerationTime={this.state.gameInfo.considerationTime}
|
||||||
|
turn={this.state.gameInfo.turn}
|
||||||
|
runNewTurn={(prevTurn)=>this.runNewTurn(prevTurn)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{marginTop: "10px"}}>
|
<div style={{marginTop: "10px"}}>
|
||||||
<input type='button' value='Connect' onClick={()=>{this.connectWebSocket()}} />
|
<input type='button' value='Connect' onClick={()=>{this.connectWebSocket()}} />
|
||||||
<input style={{marginLeft: "10px"}} type='button' value='Start Replay' onClick={()=>{this.startReplay()}} />
|
<input style={{marginLeft: "10px"}} type='button' value='Start Replay' onClick={()=>{this.startReplay()}} />
|
||||||
</div>
|
</div>
|
||||||
|
<div style={{marginTop: "10px"}}>
|
||||||
|
{`Current Player: ${this.state.gameInfo.currentPlayer} , Consideration Time: ${this.state.gameInfo.considerationTime}, Turn: ${this.state.gameInfo.turn}`}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|