add logic for request api play
This commit is contained in:
parent
58526e7fc5
commit
14ce853ce9
|
@ -1,3 +1,4 @@
|
||||||
const apiUrl = 'http://127.0.0.1:8000';
|
const apiUrl = 'http://127.0.0.1:8000';
|
||||||
|
const douzeroDemoUrl = 'http://127.0.0.1:5000';
|
||||||
|
|
||||||
export {apiUrl};
|
export { apiUrl, douzeroDemoUrl };
|
||||||
|
|
|
@ -102,10 +102,140 @@ export function computeHandCardsWidth(num, emWidth) {
|
||||||
|
|
||||||
export function card2SuiteAndRank(card) {
|
export function card2SuiteAndRank(card) {
|
||||||
if (card === 'BJ') {
|
if (card === 'BJ') {
|
||||||
return {suite: null, rank: 'X'};
|
return { suite: null, rank: 'X' };
|
||||||
} else if (card === 'RJ') {
|
} else if (card === 'RJ') {
|
||||||
return {suite: null, rank: 'D'};
|
return { suite: null, rank: 'D' };
|
||||||
} else {
|
} else {
|
||||||
return {suite: card[0], rank: card[1]};
|
return { suite: card[0], rank: card[1] };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fullDoudizhuDeck = [
|
||||||
|
'RJ',
|
||||||
|
'BJ',
|
||||||
|
'S2',
|
||||||
|
'C2',
|
||||||
|
'H2',
|
||||||
|
'D2',
|
||||||
|
'SA',
|
||||||
|
'CA',
|
||||||
|
'HA',
|
||||||
|
'DA',
|
||||||
|
'SK',
|
||||||
|
'CK',
|
||||||
|
'HK',
|
||||||
|
'DK',
|
||||||
|
'SQ',
|
||||||
|
'CQ',
|
||||||
|
'HQ',
|
||||||
|
'DQ',
|
||||||
|
'SJ',
|
||||||
|
'CJ',
|
||||||
|
'HJ',
|
||||||
|
'DJ',
|
||||||
|
'ST',
|
||||||
|
'CT',
|
||||||
|
'HT',
|
||||||
|
'DT',
|
||||||
|
'S9',
|
||||||
|
'C9',
|
||||||
|
'H9',
|
||||||
|
'D9',
|
||||||
|
'S8',
|
||||||
|
'C8',
|
||||||
|
'H8',
|
||||||
|
'D8',
|
||||||
|
'S7',
|
||||||
|
'C7',
|
||||||
|
'H7',
|
||||||
|
'D7',
|
||||||
|
'S6',
|
||||||
|
'C6',
|
||||||
|
'H6',
|
||||||
|
'D6',
|
||||||
|
'S5',
|
||||||
|
'C5',
|
||||||
|
'H5',
|
||||||
|
'D5',
|
||||||
|
'S4',
|
||||||
|
'C4',
|
||||||
|
'H4',
|
||||||
|
'D4',
|
||||||
|
'S3',
|
||||||
|
'C3',
|
||||||
|
'H3',
|
||||||
|
'D3',
|
||||||
|
];
|
||||||
|
|
||||||
|
export const fullDoudizhuDeckIndex = {
|
||||||
|
RJ: 54,
|
||||||
|
BJ: 53,
|
||||||
|
S2: 52,
|
||||||
|
C2: 51,
|
||||||
|
H2: 50,
|
||||||
|
D2: 49,
|
||||||
|
SA: 48,
|
||||||
|
CA: 47,
|
||||||
|
HA: 46,
|
||||||
|
DA: 45,
|
||||||
|
SK: 44,
|
||||||
|
CK: 43,
|
||||||
|
HK: 42,
|
||||||
|
DK: 41,
|
||||||
|
SQ: 40,
|
||||||
|
CQ: 39,
|
||||||
|
HQ: 38,
|
||||||
|
DQ: 37,
|
||||||
|
SJ: 36,
|
||||||
|
CJ: 35,
|
||||||
|
HJ: 34,
|
||||||
|
DJ: 33,
|
||||||
|
ST: 32,
|
||||||
|
CT: 31,
|
||||||
|
HT: 30,
|
||||||
|
DT: 29,
|
||||||
|
S9: 28,
|
||||||
|
C9: 27,
|
||||||
|
H9: 26,
|
||||||
|
D9: 25,
|
||||||
|
S8: 24,
|
||||||
|
C8: 23,
|
||||||
|
H8: 22,
|
||||||
|
D8: 21,
|
||||||
|
S7: 20,
|
||||||
|
C7: 19,
|
||||||
|
H7: 18,
|
||||||
|
D7: 17,
|
||||||
|
S6: 16,
|
||||||
|
C6: 15,
|
||||||
|
H6: 14,
|
||||||
|
D6: 13,
|
||||||
|
S5: 12,
|
||||||
|
C5: 11,
|
||||||
|
H5: 10,
|
||||||
|
D5: 9,
|
||||||
|
S4: 8,
|
||||||
|
C4: 7,
|
||||||
|
H4: 6,
|
||||||
|
D4: 5,
|
||||||
|
S3: 4,
|
||||||
|
C3: 3,
|
||||||
|
H3: 2,
|
||||||
|
D3: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function sortDoudizhuCards(cards, ascending = false) {
|
||||||
|
const cardsCopy = cards.slice();
|
||||||
|
return cardsCopy.sort((a, b) => {
|
||||||
|
return ascending
|
||||||
|
? fullDoudizhuDeckIndex[a] - fullDoudizhuDeckIndex[b]
|
||||||
|
: fullDoudizhuDeckIndex[b] - fullDoudizhuDeckIndex[a];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDoudizhuBomb(cards) {
|
||||||
|
if (cards.length === 2) return (cards[0] === 'RJ' && cards[1] === 'BJ') || (cards[0] === 'BJ' && cards[1] === 'RJ');
|
||||||
|
if (cards.length === 4)
|
||||||
|
return cards[0][1] === cards[1][1] && cards[0][1] === cards[2][1] && cards[0][1] === cards[3][1];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import Paper from '@material-ui/core/Paper';
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
import axios from 'axios';
|
||||||
import { Layout } from 'element-react';
|
import { Layout } from 'element-react';
|
||||||
|
import qs from 'query-string';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { DoudizhuGameBoard } from '../../components/GameBoard';
|
import { DoudizhuGameBoard } from '../../components/GameBoard';
|
||||||
import { deepCopy, card2SuiteAndRank } from '../../utils';
|
import { card2SuiteAndRank, deepCopy, isDoudizhuBomb, sortDoudizhuCards } from '../../utils';
|
||||||
|
import { douzeroDemoUrl } from '../../utils/config';
|
||||||
|
|
||||||
const initHands = [
|
const initHands = [
|
||||||
'S2 H2 HK DK HQ CQ DQ CJ S9 H9 D9 C7 S6 H6 C4 D4 S3',
|
'S2 H2 HK DK HQ CQ DQ CJ S9 H9 D9 C7 S6 H6 C4 D4 S3',
|
||||||
|
@ -10,13 +13,43 @@ const initHands = [
|
||||||
'RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3 D3',
|
'RJ BJ D2 SA SK CK SJ HJ DJ CT DT C9 S8 H8 C8 D7 D5 H3 S3 D3',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const initConsiderationTime = 2000;
|
||||||
|
const considerationTimeDeduction = 200;
|
||||||
|
const mainPlayerId = 0;
|
||||||
|
const playerInfo = [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
index: 0,
|
||||||
|
role: 'peasant',
|
||||||
|
douzeroPlayerPosition: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
index: 1,
|
||||||
|
role: 'peasant',
|
||||||
|
douzeroPlayerPosition: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
index: 2,
|
||||||
|
role: 'landlord',
|
||||||
|
douzeroPlayerPosition: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const threeLandlordCards = ['RJ', 'BJ', 'D2'];
|
||||||
|
|
||||||
let gameStateTimeout = null;
|
let gameStateTimeout = null;
|
||||||
|
|
||||||
function PvEDoudizhuDemoView() {
|
let gameHistory = [];
|
||||||
const initConsiderationTime = 2000;
|
let bombNum = 0;
|
||||||
const considerationTimeDeduction = 200;
|
let lastMoveLandlord = [];
|
||||||
const mainPlayerId = 0;
|
let lastMoveLandlordDown = [];
|
||||||
|
let lastMoveLandlordUp = [];
|
||||||
|
let playedCardsLandlord = [];
|
||||||
|
let playedCardsLandlordDown = [];
|
||||||
|
let playedCardsLandlordUp = [];
|
||||||
|
|
||||||
|
function PvEDoudizhuDemoView() {
|
||||||
const [considerationTime, setConsiderationTime] = useState(initConsiderationTime);
|
const [considerationTime, setConsiderationTime] = useState(initConsiderationTime);
|
||||||
const [toggleFade, setToggleFade] = useState('');
|
const [toggleFade, setToggleFade] = useState('');
|
||||||
const [gameStatus, setGameStatus] = useState('ready'); // "ready", "playing", "paused", "over"
|
const [gameStatus, setGameStatus] = useState('ready'); // "ready", "playing", "paused", "over"
|
||||||
|
@ -32,25 +65,18 @@ function PvEDoudizhuDemoView() {
|
||||||
return cardStr === 'pass' || cardStr === '' ? 'pass' : cardStr.split(' ');
|
return cardStr === 'pass' || cardStr === '' ? 'pass' : cardStr.split(' ');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const cardArr2DouzeroFormat = (cards) => {
|
||||||
|
return cards
|
||||||
|
.map((card) => {
|
||||||
|
if (card === 'RJ') return 'D';
|
||||||
|
if (card === 'BJ') return 'X';
|
||||||
|
return card[1];
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
};
|
||||||
|
|
||||||
// todo: generate inital player / hand states
|
// todo: generate inital player / hand states
|
||||||
// for test use
|
// for test use
|
||||||
const playerInfo = [
|
|
||||||
{
|
|
||||||
id: 0,
|
|
||||||
index: 0,
|
|
||||||
role: 'peasant',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
index: 1,
|
|
||||||
role: 'peasant',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
index: 2,
|
|
||||||
role: 'landlord',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function timeout(ms) {
|
function timeout(ms) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
@ -70,9 +96,8 @@ function PvEDoudizhuDemoView() {
|
||||||
newHand = currentHand;
|
newHand = currentHand;
|
||||||
newLatestAction = 'pass';
|
newLatestAction = 'pass';
|
||||||
} else if (rankOnly) {
|
} else if (rankOnly) {
|
||||||
newHand = currentHand.filter(card => {
|
newHand = currentHand.filter((card) => {
|
||||||
if (playingCard.length === 0)
|
if (playingCard.length === 0) return true;
|
||||||
return true;
|
|
||||||
|
|
||||||
const { rank } = card2SuiteAndRank(card);
|
const { rank } = card2SuiteAndRank(card);
|
||||||
const idx = playingCard.indexOf(rank);
|
const idx = playingCard.indexOf(rank);
|
||||||
|
@ -85,9 +110,8 @@ function PvEDoudizhuDemoView() {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
newLatestAction = playingCard.slice();
|
newLatestAction = playingCard.slice();
|
||||||
newHand = currentHand.filter(card => {
|
newHand = currentHand.filter((card) => {
|
||||||
if (playingCard.length === 0)
|
if (playingCard.length === 0) return true;
|
||||||
return true;
|
|
||||||
|
|
||||||
const idx = playingCard.indexOf(card);
|
const idx = playingCard.indexOf(card);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
|
@ -98,13 +122,33 @@ function PvEDoudizhuDemoView() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update value records for douzero
|
||||||
|
// debugger;
|
||||||
|
const newHistoryRecord = newLatestAction === 'pass' ? [] : newLatestAction;
|
||||||
|
switch (playerInfo[gameState.currentPlayer].douzeroPlayerPosition) {
|
||||||
|
case 0:
|
||||||
|
lastMoveLandlord = newHistoryRecord;
|
||||||
|
playedCardsLandlord = playedCardsLandlord.concat(newHistoryRecord);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
lastMoveLandlordDown = newHistoryRecord;
|
||||||
|
playedCardsLandlordDown = playedCardsLandlordDown.concat(newHistoryRecord);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
lastMoveLandlordUp = newHistoryRecord;
|
||||||
|
playedCardsLandlordUp = playedCardsLandlordUp.concat(newHistoryRecord);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gameHistory.push(newHistoryRecord);
|
||||||
|
if (isDoudizhuBomb(newHistoryRecord)) bombNum++;
|
||||||
|
|
||||||
newGameState.latestAction[gameState.currentPlayer] = newLatestAction;
|
newGameState.latestAction[gameState.currentPlayer] = newLatestAction;
|
||||||
newGameState.hands[gameState.currentPlayer] = newHand;
|
newGameState.hands[gameState.currentPlayer] = newHand;
|
||||||
newGameState.currentPlayer = (newGameState.currentPlayer + 1) % 3;
|
newGameState.currentPlayer = (newGameState.currentPlayer + 1) % 3;
|
||||||
newGameState.turn++;
|
newGameState.turn++;
|
||||||
setGameState(newGameState);
|
setGameState(newGameState);
|
||||||
setToggleFade('fade-in');
|
setToggleFade('fade-in');
|
||||||
setTimeout(()=> {
|
setTimeout(() => {
|
||||||
setToggleFade('');
|
setToggleFade('');
|
||||||
}, 200);
|
}, 200);
|
||||||
if (gameStateTimeout) {
|
if (gameStateTimeout) {
|
||||||
|
@ -115,15 +159,96 @@ function PvEDoudizhuDemoView() {
|
||||||
|
|
||||||
const requestApiPlay = async () => {
|
const requestApiPlay = async () => {
|
||||||
// mock delayed API play
|
// mock delayed API play
|
||||||
await timeout(1200);
|
// await timeout(1200);
|
||||||
const apiRes = [card2SuiteAndRank(gameState.hands[gameState.currentPlayer][gameState.hands[gameState.currentPlayer].length - 1]).rank];
|
// const apiRes = [
|
||||||
console.log('mock api res', apiRes, gameStateTimeout);
|
// card2SuiteAndRank(
|
||||||
proceedNextTurn(apiRes);
|
// gameState.hands[gameState.currentPlayer][gameState.hands[gameState.currentPlayer].length - 1],
|
||||||
|
// ).rank,
|
||||||
|
// ];
|
||||||
|
const player_position = playerInfo[gameState.currentPlayer].douzeroPlayerPosition;
|
||||||
|
const player_hand_cards = cardArr2DouzeroFormat(gameState.hands[gameState.currentPlayer].slice().reverse());
|
||||||
|
const num_cards_left_landlord =
|
||||||
|
gameState.hands[playerInfo.find((player) => player.douzeroPlayerPosition === 0).index].length;
|
||||||
|
const num_cards_left_landlord_down =
|
||||||
|
gameState.hands[playerInfo.find((player) => player.douzeroPlayerPosition === 1).index].length;
|
||||||
|
const num_cards_left_landlord_up =
|
||||||
|
gameState.hands[playerInfo.find((player) => player.douzeroPlayerPosition === 2).index].length;
|
||||||
|
const three_landlord_cards = cardArr2DouzeroFormat(threeLandlordCards.slice().reverse());
|
||||||
|
const card_play_action_seq = gameHistory
|
||||||
|
.map((cards) => {
|
||||||
|
return cardArr2DouzeroFormat(cards);
|
||||||
|
})
|
||||||
|
.join(',');
|
||||||
|
const other_hand_cards = cardArr2DouzeroFormat(
|
||||||
|
sortDoudizhuCards(
|
||||||
|
gameState.hands[(gameState.currentPlayer + 1) % 3].concat(
|
||||||
|
gameState.hands[(gameState.currentPlayer + 2) % 3],
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const last_move_landlord = cardArr2DouzeroFormat(lastMoveLandlord.slice().reverse());
|
||||||
|
const last_move_landlord_down = cardArr2DouzeroFormat(lastMoveLandlordDown.slice().reverse());
|
||||||
|
const last_move_landlord_up = cardArr2DouzeroFormat(lastMoveLandlordUp.slice().reverse());
|
||||||
|
const bomb_num = bombNum;
|
||||||
|
const played_cards_landlord = cardArr2DouzeroFormat(playedCardsLandlord);
|
||||||
|
const played_cards_landlord_down = cardArr2DouzeroFormat(playedCardsLandlordDown);
|
||||||
|
const played_cards_landlord_up = cardArr2DouzeroFormat(playedCardsLandlordUp);
|
||||||
|
|
||||||
|
const requestBody = {
|
||||||
|
player_position,
|
||||||
|
player_hand_cards,
|
||||||
|
num_cards_left_landlord,
|
||||||
|
num_cards_left_landlord_down,
|
||||||
|
num_cards_left_landlord_up,
|
||||||
|
three_landlord_cards,
|
||||||
|
card_play_action_seq,
|
||||||
|
other_hand_cards,
|
||||||
|
last_move_landlord,
|
||||||
|
last_move_landlord_down,
|
||||||
|
last_move_landlord_up,
|
||||||
|
bomb_num,
|
||||||
|
played_cards_landlord,
|
||||||
|
played_cards_landlord_down,
|
||||||
|
played_cards_landlord_up,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const apiRes = await axios.post(`${douzeroDemoUrl}/predict`, qs.stringify(requestBody));
|
||||||
|
console.log(apiRes.data);
|
||||||
|
const data = apiRes.data;
|
||||||
|
if (data.status !== 0) {
|
||||||
|
if (data.status === -1) {
|
||||||
|
// todo: check if no legal action can be made
|
||||||
|
proceedNextTurn([]);
|
||||||
|
}
|
||||||
|
console.log(data.status, data.message);
|
||||||
|
} else {
|
||||||
|
console.log('api res', data, gameStateTimeout);
|
||||||
|
let bestAction = '';
|
||||||
|
if (data.result && Object.keys(data.result).length > 0) {
|
||||||
|
if (Object.keys(data.result).length === 1) bestAction = Object.keys(data.result)[0];
|
||||||
|
else {
|
||||||
|
bestAction = Object.keys(data.result)[0];
|
||||||
|
let bestConfidence = Number(data.result[Object.keys(data.result)[0]]);
|
||||||
|
for (let i = 1; i < Object.keys(data.result).length; i++) {
|
||||||
|
if (Number(data.result[Object.keys(data.result)[i]]) > bestConfidence) {
|
||||||
|
bestAction = Object.keys(data.result)[i];
|
||||||
|
bestConfidence = Number(data.result[Object.keys(data.result)[i]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proceedNextTurn(bestAction.split(''));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectedCards = (cards) => {
|
const handleSelectedCards = (cards) => {
|
||||||
let newSelectedCards = selectedCards.slice();
|
let newSelectedCards = selectedCards.slice();
|
||||||
cards.forEach(card => {
|
cards.forEach((card) => {
|
||||||
if (newSelectedCards.indexOf(card) >= 0) {
|
if (newSelectedCards.indexOf(card) >= 0) {
|
||||||
newSelectedCards.splice(newSelectedCards.indexOf(card), 1);
|
newSelectedCards.splice(newSelectedCards.indexOf(card), 1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -131,7 +256,7 @@ function PvEDoudizhuDemoView() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setSelectedCards(newSelectedCards);
|
setSelectedCards(newSelectedCards);
|
||||||
}
|
};
|
||||||
|
|
||||||
const gameStateTimer = () => {
|
const gameStateTimer = () => {
|
||||||
gameStateTimeout = setTimeout(() => {
|
gameStateTimeout = setTimeout(() => {
|
||||||
|
@ -160,7 +285,7 @@ function PvEDoudizhuDemoView() {
|
||||||
const newGameState = deepCopy(gameState);
|
const newGameState = deepCopy(gameState);
|
||||||
// find landord to be the first player
|
// find landord to be the first player
|
||||||
newGameState.currentPlayer = playerInfo.find((element) => element.role === 'landlord').index;
|
newGameState.currentPlayer = playerInfo.find((element) => element.role === 'landlord').index;
|
||||||
newGameState.hands = initHands.map((element) => cardStr2Arr(element));
|
newGameState.hands = initHands.map((element) => sortDoudizhuCards(cardStr2Arr(element)));
|
||||||
setGameState(newGameState);
|
setGameState(newGameState);
|
||||||
gameStateTimer();
|
gameStateTimer();
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -169,6 +294,7 @@ function PvEDoudizhuDemoView() {
|
||||||
if (gameState.currentPlayer) {
|
if (gameState.currentPlayer) {
|
||||||
// if current player is not user, request for API player
|
// if current player is not user, request for API player
|
||||||
if (gameState.currentPlayer !== mainPlayerId) {
|
if (gameState.currentPlayer !== mainPlayerId) {
|
||||||
|
// debugger;
|
||||||
requestApiPlay();
|
requestApiPlay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,7 +305,7 @@ function PvEDoudizhuDemoView() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMainPlayerAct = (type) => {
|
const handleMainPlayerAct = (type) => {
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case 'play': {
|
case 'play': {
|
||||||
proceedNextTurn(selectedCards, false);
|
proceedNextTurn(selectedCards, false);
|
||||||
break;
|
break;
|
||||||
|
@ -194,7 +320,7 @@ function PvEDoudizhuDemoView() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
Loading…
Reference in New Issue