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 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) {
|
||||
if (card === 'BJ') {
|
||||
return {suite: null, rank: 'X'};
|
||||
return { suite: null, rank: 'X' };
|
||||
} else if (card === 'RJ') {
|
||||
return {suite: null, rank: 'D'};
|
||||
return { suite: null, rank: 'D' };
|
||||
} 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 axios from 'axios';
|
||||
import { Layout } from 'element-react';
|
||||
import qs from 'query-string';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { DoudizhuGameBoard } from '../../components/GameBoard';
|
||||
import { deepCopy, card2SuiteAndRank } from '../../utils';
|
||||
import { card2SuiteAndRank, deepCopy, isDoudizhuBomb, sortDoudizhuCards } from '../../utils';
|
||||
import { douzeroDemoUrl } from '../../utils/config';
|
||||
|
||||
const initHands = [
|
||||
'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',
|
||||
];
|
||||
|
||||
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;
|
||||
|
||||
function PvEDoudizhuDemoView() {
|
||||
const initConsiderationTime = 2000;
|
||||
const considerationTimeDeduction = 200;
|
||||
const mainPlayerId = 0;
|
||||
let gameHistory = [];
|
||||
let bombNum = 0;
|
||||
let lastMoveLandlord = [];
|
||||
let lastMoveLandlordDown = [];
|
||||
let lastMoveLandlordUp = [];
|
||||
let playedCardsLandlord = [];
|
||||
let playedCardsLandlordDown = [];
|
||||
let playedCardsLandlordUp = [];
|
||||
|
||||
function PvEDoudizhuDemoView() {
|
||||
const [considerationTime, setConsiderationTime] = useState(initConsiderationTime);
|
||||
const [toggleFade, setToggleFade] = useState('');
|
||||
const [gameStatus, setGameStatus] = useState('ready'); // "ready", "playing", "paused", "over"
|
||||
|
@ -32,25 +65,18 @@ function PvEDoudizhuDemoView() {
|
|||
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
|
||||
// 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) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
@ -70,9 +96,8 @@ function PvEDoudizhuDemoView() {
|
|||
newHand = currentHand;
|
||||
newLatestAction = 'pass';
|
||||
} else if (rankOnly) {
|
||||
newHand = currentHand.filter(card => {
|
||||
if (playingCard.length === 0)
|
||||
return true;
|
||||
newHand = currentHand.filter((card) => {
|
||||
if (playingCard.length === 0) return true;
|
||||
|
||||
const { rank } = card2SuiteAndRank(card);
|
||||
const idx = playingCard.indexOf(rank);
|
||||
|
@ -85,9 +110,8 @@ function PvEDoudizhuDemoView() {
|
|||
});
|
||||
} else {
|
||||
newLatestAction = playingCard.slice();
|
||||
newHand = currentHand.filter(card => {
|
||||
if (playingCard.length === 0)
|
||||
return true;
|
||||
newHand = currentHand.filter((card) => {
|
||||
if (playingCard.length === 0) return true;
|
||||
|
||||
const idx = playingCard.indexOf(card);
|
||||
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.hands[gameState.currentPlayer] = newHand;
|
||||
newGameState.currentPlayer = (newGameState.currentPlayer + 1) % 3;
|
||||
newGameState.turn++;
|
||||
setGameState(newGameState);
|
||||
setToggleFade('fade-in');
|
||||
setTimeout(()=> {
|
||||
setTimeout(() => {
|
||||
setToggleFade('');
|
||||
}, 200);
|
||||
if (gameStateTimeout) {
|
||||
|
@ -115,15 +159,96 @@ function PvEDoudizhuDemoView() {
|
|||
|
||||
const requestApiPlay = async () => {
|
||||
// mock delayed API play
|
||||
await timeout(1200);
|
||||
const apiRes = [card2SuiteAndRank(gameState.hands[gameState.currentPlayer][gameState.hands[gameState.currentPlayer].length - 1]).rank];
|
||||
console.log('mock api res', apiRes, gameStateTimeout);
|
||||
proceedNextTurn(apiRes);
|
||||
// await timeout(1200);
|
||||
// const apiRes = [
|
||||
// card2SuiteAndRank(
|
||||
// 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) => {
|
||||
let newSelectedCards = selectedCards.slice();
|
||||
cards.forEach(card => {
|
||||
cards.forEach((card) => {
|
||||
if (newSelectedCards.indexOf(card) >= 0) {
|
||||
newSelectedCards.splice(newSelectedCards.indexOf(card), 1);
|
||||
} else {
|
||||
|
@ -131,7 +256,7 @@ function PvEDoudizhuDemoView() {
|
|||
}
|
||||
});
|
||||
setSelectedCards(newSelectedCards);
|
||||
}
|
||||
};
|
||||
|
||||
const gameStateTimer = () => {
|
||||
gameStateTimeout = setTimeout(() => {
|
||||
|
@ -160,7 +285,7 @@ function PvEDoudizhuDemoView() {
|
|||
const newGameState = deepCopy(gameState);
|
||||
// find landord to be the first player
|
||||
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);
|
||||
gameStateTimer();
|
||||
}, []);
|
||||
|
@ -169,6 +294,7 @@ function PvEDoudizhuDemoView() {
|
|||
if (gameState.currentPlayer) {
|
||||
// if current player is not user, request for API player
|
||||
if (gameState.currentPlayer !== mainPlayerId) {
|
||||
// debugger;
|
||||
requestApiPlay();
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +305,7 @@ function PvEDoudizhuDemoView() {
|
|||
};
|
||||
|
||||
const handleMainPlayerAct = (type) => {
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case 'play': {
|
||||
proceedNextTurn(selectedCards, false);
|
||||
break;
|
||||
|
@ -194,7 +320,7 @@ function PvEDoudizhuDemoView() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
Loading…
Reference in New Issue