added react router for serving multiple games & init leduc holdem

This commit is contained in:
songyih 2020-01-28 21:29:53 -08:00
parent 376dd8c4eb
commit 3b483b477e
7 changed files with 235 additions and 189 deletions

View File

@ -3,7 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@material-ui/core": "^4.8.3", "@material-ui/core": "^4.9.0",
"@testing-library/jest-dom": "^4.2.4", "@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2", "@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2", "@testing-library/user-event": "^7.1.2",
@ -13,6 +13,7 @@
"react": "^16.12.0", "react": "^16.12.0",
"react-dom": "^16.12.0", "react-dom": "^16.12.0",
"react-hot-loader": "^4.12.18", "react-hot-loader": "^4.12.18",
"react-router-dom": "^5.1.2",
"react-scripts": "3.3.0", "react-scripts": "3.3.0",
"socket.io-client": "^2.3.0" "socket.io-client": "^2.3.0"
}, },

View File

@ -1,11 +1,14 @@
import React from 'react'; import React from 'react';
import { BrowserRouter as Router, Route } from "react-router-dom";
import DoudizhuGameView from './view/DoudizhuGameView'; import DoudizhuGameView from './view/DoudizhuGameView';
import LeducHoldemGameView from './view/LeducHoldemGameView';
function App() { function App() {
return ( return (
<div> <Router>
<DoudizhuGameView /> <Route path="/doudizhu" component={DoudizhuGameView} />
</div> <Route path="/leduc-holdem" component={LeducHoldemGameView} />
</Router>
); );
} }

View File

@ -0,0 +1,186 @@
import React from 'react';
import '../../assets/doudizhu.scss';
class DoudizhuGameBoard extends React.Component {
constructor(props) {
super(props);
this.suitMap = new Map(
[["H", "hearts"], ["D", "diams"], ["S", "spades"], ["C", "clubs"]]
);
this.suitMapSymbol = new Map(
[["H", "\u2665"], ["D", "\u2666"], ["S", "\u2660"], ["C", "\u2663"]]
)
}
translateCardData(card) {
let rankClass;
let suitClass = "";
let rankText;
let suitText = "";
// translate rank
if(card === "RJ"){
rankClass = "big";
rankText = "+";
suitClass = "joker";
suitText = "Joker";
}else if(card === "BJ"){
rankClass = "little";
rankText = "-";
suitClass = "joker";
suitText = "Joker";
}else{
rankClass = card.charAt(1) === "T" ? `10` : card.charAt(1).toLowerCase();
rankClass = `rank-${rankClass}`;
rankText = card.charAt(1) === "T" ? `10` : card.charAt(1);
}
// translate suitClass
if(card !== "RJ" && card !== "BJ"){
suitClass = this.suitMap.get(card.charAt(0));
suitText = this.suitMapSymbol.get(card.charAt(0));
}
return (
<li key={`handCard-${card}`}>
<a className={`card ${rankClass} ${suitClass}`} href="/#">
<span className="rank">{rankText}</span>
<span className="suit">{suitText}</span>
</a>
</li>
)
}
computeSingleLineHand(cards) {
if(cards === "P"){
return <div className="non-card"><span>Pass</span></div>
}else{
return (
<div className="playingCards">
<ul className="hand" style={{width: this.computeHandCardsWidth(cards.length, 12)}}>
{cards.map(card=>{
return this.translateCardData(card);
})}
</ul>
</div>
)
}
}
computeSideHand(cards) {
let upCards;
let downCards = [];
if(cards.length > 10){
upCards = cards.slice(0, 10);
downCards = cards.slice(10, );
}else{
upCards = cards;
}
return (
<div>
<div className="player-hand-up">
<div className="playingCards">
<ul className="hand">
{upCards.map(element => {return this.translateCardData(element)})}
</ul>
</div>
</div>
<div className="player-hand-down">
<div className="playingCards">
<ul className="hand">
{downCards.map(element => {return this.translateCardData(element)})}
</ul>
</div>
</div>
</div>
)
}
computeHandCardsWidth(num, emWidth) {
if(num === 0)
return 0;
return (num-1)*1.1*emWidth + 4.3*emWidth*1.2 + 2;
}
millisecond2Second(t){
return Math.ceil(t/1000);
}
playerDecisionArea(playerIdx){
if(this.props.currentPlayer === playerIdx){
return <div className="non-card"><span>{`Consideration Time: ${this.millisecond2Second(this.props.considerationTime)}s`}</span></div>
}else{
return this.computeSingleLineHand(this.props.latestAction[playerIdx])
}
}
componentDidUpdate(prevProps, prevState, snapshot) {
if(prevProps.turn !== this.props.turn && this.props.turn !== 0){
// new turn starts
this.props.runNewTurn(prevProps);
}
}
render() {
// compute the id as well as index in list for every player
const bottomId = this.props.mainPlayerId;
let found = this.props.playerInfo.find(element=>{
return element.id === bottomId;
});
const bottomIdx = found ? found.index : -1;
const rightIdx = bottomIdx >= 0 ? (bottomIdx+1)%3 : -1;
const leftIdx = rightIdx >= 0 ? (rightIdx+1)%3 : -1;
let rightId = -1;
let leftId = -1;
if(rightIdx >= 0 && leftIdx >= 0){
found = this.props.playerInfo.find(element=>{
return element.index === rightIdx;
});
if(found)
rightId = found.id;
found = this.props.playerInfo.find(element=>{
return element.index === leftIdx;
});
if(found)
leftId = found.id;
}
return (
<div style={{width: "100%", height: "100%", backgroundColor: "#ffcc99", position: "relative"}}>
<div id={"left-player"}>
<div className="player-main-area">
<div className="player-info">
<span>{`Player Id ${leftId}\n${this.props.playerInfo.length > 0 ? this.props.playerInfo[leftIdx].role : ""}`}</span>
</div>
{leftIdx >= 0 ? this.computeSideHand(this.props.hands[leftIdx]) : <div className="player-hand-placeholder"><span>Waiting...</span></div>}
</div>
<div className="played-card-area">
{leftIdx >= 0 ? this.playerDecisionArea(leftIdx) : ""}
</div>
</div>
<div id={"right-player"}>
<div className="player-main-area">
<div className="player-info">
<span>{`Player Id ${rightId}\n${this.props.playerInfo.length > 0 ? this.props.playerInfo[rightIdx].role : ""}`}</span>
</div>
{rightIdx >= 0 ? this.computeSideHand(this.props.hands[rightIdx]) : <div className="player-hand-placeholder"><span>Waiting...</span></div>}
</div>
<div className="played-card-area">
{rightIdx >= 0 ? this.playerDecisionArea(rightIdx) : ""}
</div>
</div>
<div id={"bottom-player"}>
<div className="played-card-area">
{bottomIdx >= 0 ? this.playerDecisionArea(bottomIdx) : ""}
</div>
<div className="player-main-area">
<div className="player-info">
<span>{`Player Id ${bottomId}\n${this.props.playerInfo.length > 0 ? this.props.playerInfo[bottomIdx].role : ""}`}</span>
</div>
{bottomIdx >= 0 ? <div className="player-hand">{this.computeSingleLineHand(this.props.hands[bottomIdx])}</div> : <div className="player-hand-placeholder"><span>Waiting...</span></div>}
</div>
</div>
</div>
);
}
}
export default DoudizhuGameBoard;

View File

@ -0,0 +1,16 @@
import React from 'react';
class LeducHoldemGameBoard extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>Leduc Holdem GameBoard Placeholder</div>
);
}
}
export default LeducHoldemGameBoard;

View File

@ -1,186 +1,5 @@
import React from 'react'; import React from 'react';
import DoudizhuGameBoard from "./DoudizhuGameBoard";
import LeducHoldemGameBoard from "./LeducHoldemGameBoard";
import '../../assets/doudizhu.scss'; export {DoudizhuGameBoard, LeducHoldemGameBoard};
class DoudizhuGameBoard extends React.Component {
constructor(props) {
super(props);
this.suitMap = new Map(
[["H", "hearts"], ["D", "diams"], ["S", "spades"], ["C", "clubs"]]
);
this.suitMapSymbol = new Map(
[["H", "\u2665"], ["D", "\u2666"], ["S", "\u2660"], ["C", "\u2663"]]
)
}
translateCardData(card) {
let rankClass;
let suitClass = "";
let rankText;
let suitText = "";
// translate rank
if(card === "RJ"){
rankClass = "big";
rankText = "+";
suitClass = "joker";
suitText = "Joker";
}else if(card === "BJ"){
rankClass = "little";
rankText = "-";
suitClass = "joker";
suitText = "Joker";
}else{
rankClass = card.charAt(1) === "T" ? `10` : card.charAt(1).toLowerCase();
rankClass = `rank-${rankClass}`;
rankText = card.charAt(1) === "T" ? `10` : card.charAt(1);
}
// translate suitClass
if(card !== "RJ" && card !== "BJ"){
suitClass = this.suitMap.get(card.charAt(0));
suitText = this.suitMapSymbol.get(card.charAt(0));
}
return (
<li key={`handCard-${card}`}>
<a className={`card ${rankClass} ${suitClass}`} href="/#">
<span className="rank">{rankText}</span>
<span className="suit">{suitText}</span>
</a>
</li>
)
}
computeSingleLineHand(cards) {
if(cards === "P"){
return <div className="non-card"><span>Pass</span></div>
}else{
return (
<div className="playingCards">
<ul className="hand" style={{width: this.computeHandCardsWidth(cards.length, 12)}}>
{cards.map(card=>{
return this.translateCardData(card);
})}
</ul>
</div>
)
}
}
computeSideHand(cards) {
let upCards;
let downCards = [];
if(cards.length > 10){
upCards = cards.slice(0, 10);
downCards = cards.slice(10, );
}else{
upCards = cards;
}
return (
<div>
<div className="player-hand-up">
<div className="playingCards">
<ul className="hand">
{upCards.map(element => {return this.translateCardData(element)})}
</ul>
</div>
</div>
<div className="player-hand-down">
<div className="playingCards">
<ul className="hand">
{downCards.map(element => {return this.translateCardData(element)})}
</ul>
</div>
</div>
</div>
)
}
computeHandCardsWidth(num, emWidth) {
if(num === 0)
return 0;
return (num-1)*1.1*emWidth + 4.3*emWidth*1.2 + 2;
}
millisecond2Second(t){
return Math.ceil(t/1000);
}
playerDecisionArea(playerIdx){
if(this.props.currentPlayer === playerIdx){
return <div className="non-card"><span>{`Consideration Time: ${this.millisecond2Second(this.props.considerationTime)}s`}</span></div>
}else{
return this.computeSingleLineHand(this.props.latestAction[playerIdx])
}
}
componentDidUpdate(prevProps, prevState, snapshot) {
if(prevProps.turn !== this.props.turn && this.props.turn !== 0){
// new turn starts
this.props.runNewTurn(prevProps);
}
}
render() {
// compute the id as well as index in list for every player
const bottomId = this.props.mainPlayerId;
let found = this.props.playerInfo.find(element=>{
return element.id === bottomId;
});
const bottomIdx = found ? found.index : -1;
const rightIdx = bottomIdx >= 0 ? (bottomIdx+1)%3 : -1;
const leftIdx = rightIdx >= 0 ? (rightIdx+1)%3 : -1;
let rightId = -1;
let leftId = -1;
if(rightIdx >= 0 && leftIdx >= 0){
found = this.props.playerInfo.find(element=>{
return element.index === rightIdx;
});
if(found)
rightId = found.id;
found = this.props.playerInfo.find(element=>{
return element.index === leftIdx;
});
if(found)
leftId = found.id;
}
return (
<div style={{width: "100%", height: "100%", backgroundColor: "#ffcc99", position: "relative"}}>
<div id={"left-player"}>
<div className="player-main-area">
<div className="player-info">
<span>{`Player Id ${leftId}\n${this.props.playerInfo.length > 0 ? this.props.playerInfo[leftIdx].role : ""}`}</span>
</div>
{leftIdx >= 0 ? this.computeSideHand(this.props.hands[leftIdx]) : <div className="player-hand-placeholder"><span>Waiting...</span></div>}
</div>
<div className="played-card-area">
{leftIdx >= 0 ? this.playerDecisionArea(leftIdx) : ""}
</div>
</div>
<div id={"right-player"}>
<div className="player-main-area">
<div className="player-info">
<span>{`Player Id ${rightId}\n${this.props.playerInfo.length > 0 ? this.props.playerInfo[rightIdx].role : ""}`}</span>
</div>
{rightIdx >= 0 ? this.computeSideHand(this.props.hands[rightIdx]) : <div className="player-hand-placeholder"><span>Waiting...</span></div>}
</div>
<div className="played-card-area">
{rightIdx >= 0 ? this.playerDecisionArea(rightIdx) : ""}
</div>
</div>
<div id={"bottom-player"}>
<div className="played-card-area">
{bottomIdx >= 0 ? this.playerDecisionArea(bottomIdx) : ""}
</div>
<div className="player-main-area">
<div className="player-info">
<span>{`Player Id ${bottomId}\n${this.props.playerInfo.length > 0 ? this.props.playerInfo[bottomIdx].role : ""}`}</span>
</div>
{bottomIdx >= 0 ? <div className="player-hand">{this.computeSingleLineHand(this.props.hands[bottomIdx])}</div> : <div className="player-hand-placeholder"><span>Waiting...</span></div>}
</div>
</div>
</div>
);
}
}
export default DoudizhuGameBoard;

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import '../assets/gameview.scss'; import '../assets/gameview.scss';
import DoudizhuGameBoard from '../components/GameBoard'; import { DoudizhuGameBoard } from '../components/GameBoard';
import webSocket from "socket.io-client"; import webSocket from "socket.io-client";
import {removeCards, doubleRaf} from "../utils"; import {removeCards, doubleRaf} from "../utils";

View File

@ -0,0 +1,21 @@
import React from 'react';
import '../assets/gameview.scss';
import { LeducHoldemGameBoard } from '../components/GameBoard';
import {removeCards, doubleRaf} from "../utils";
import { Button, Layout, Slider as elSlider } from 'element-react';
import Slider from '@material-ui/core/Slider';
class LeducHoldemGameView extends React.Component {
constructor(props) {
super(props);
}
render(){
return (
<div>Leduc Holdem Placeholder <LeducHoldemGameBoard /></div>
);
}
}
export default LeducHoldemGameView;