中间状态,添加记牌器

This commit is contained in:
zhiyang7 2021-12-31 17:51:32 +08:00
parent a1fdb90abe
commit c3fbd52383
4 changed files with 115 additions and 5 deletions

View File

@ -8,7 +8,8 @@
"doudizhu": {
"ai_hand_faceup": "Hand Face-Up",
"ai_prediction": "AI Prediction",
"ai_prediction": "Prediction",
"card_recorder": "Card Recorder",
"play_as_landlord": "Play As Landlord",
"play_as_peasant": "Play As Peasant",
"landlord_up": "Landlord Up",

View File

@ -7,8 +7,9 @@
"reset": "重置",
"doudizhu": {
"ai_hand_faceup": "显示手牌",
"ai_prediction": "显示预测",
"ai_hand_faceup": "明牌",
"ai_prediction": "预测",
"card_recorder": "记牌器",
"play_as_landlord": "扮演地主",
"play_as_peasant": "扮演农民",
"landlord_up": "地主上家",

View File

@ -45,6 +45,36 @@ export function deepCopy(toCopy) {
return JSON.parse(JSON.stringify(toCopy));
}
export function translateDouzeroCardData(card) {
let rankClass;
let suitClass = '';
let rankText;
let suitText = '';
// translate rank
if (card === 'D') {
rankClass = 'big';
rankText = '+';
suitClass = 'joker';
suitText = 'Joker';
} else if (card === 'X') {
rankClass = 'little';
rankText = '-';
suitClass = 'joker';
suitText = 'Joker';
} else {
rankClass = card.charAt(0) === 'T' ? `10` : card.charAt(0).toLowerCase();
rankClass = `rank-${rankClass}`;
rankText = 'H';
}
// translate suitClass
if (card !== 'X' && card !== 'D') {
suitClass = suitMap.get('H');
suitText = suitMapSymbol.get('H');
}
return [rankClass, suitClass, rankText, suitText];
}
export function translateCardData(card) {
let rankClass;
let suitClass = '';
@ -110,6 +140,8 @@ export function card2SuiteAndRank(card) {
}
}
export const fullDouzeroDeck = ['3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A', '2', 'X', 'D']
export const fullDoudizhuDeck = [
'RJ',
'BJ',

View File

@ -23,6 +23,7 @@ import {
card2SuiteAndRank,
computeHandCardsWidth,
deepCopy,
fullDouzeroDeck,
fullDoudizhuDeck,
isDoudizhuBomb,
shuffleArray,
@ -67,6 +68,7 @@ let legalActions = { turn: -1, actions: [] };
let hintIdx = -1;
let gameEndDialogTitle = '';
let syncGameStatus = localStorage.getItem('LOCALE') ? 'ready' : 'localeSelection';
let cardRecorder = {};
function PvEDoudizhuDemoView() {
const { t, i18n } = useTranslation();
@ -87,6 +89,7 @@ function PvEDoudizhuDemoView() {
const [predictionRes, setPredictionRes] = useState({ prediction: [], hands: [] });
const [hideRivalHand, setHideRivalHand] = useState(true);
const [hidePredictionArea, setHidePredictionArea] = useState(true);
const [showCardRecorder, setShowCardRecorder] = useState(true);
const [locale, setLocale] = useState(localStorage.getItem('LOCALE') || 'en');
const [statisticRows, setStatisticRows] = useState([]);
@ -350,6 +353,23 @@ function PvEDoudizhuDemoView() {
setIsGameEndDialogOpen(true);
}, 2000);
} else {
// update card recorder
if(showCardRecorder) {
const cardArr = cardArr2DouzeroFormat(
sortDoudizhuCards(
gameState.hands[(gameState.currentPlayer + 1) % 4].concat(
gameState.hands[(gameState.currentPlayer + 2) % 4],
gameState.hands[(gameState.currentPlayer + 3) % 4],
),
true,
),
)
fullDouzeroDeck.forEach((card) => {
cardRecorder[card] = cardArr.split('').reduce((acc, ch) => ch === 'card' ? acc + 1: acc, 0)
})
}
setConsiderationTime(initConsiderationTime);
// manually trigger timer if consideration time equals initConsiderationTime
if (initConsiderationTime === considerationTime) gameStateTimer();
@ -518,6 +538,10 @@ function PvEDoudizhuDemoView() {
setHidePredictionArea(!hidePredictionArea);
};
const toggleShowCardRecorder = () => {
setShowCardRecorder(!showCardRecorder);
};
const handleSelectedCards = (cards) => {
let newSelectedCards = selectedCards.slice();
cards.forEach((card) => {
@ -679,7 +703,7 @@ function PvEDoudizhuDemoView() {
});
setSelectedCards([]); // user selected hand card
setPredictionRes({ prediction: [], hands: [] });
setHideRivalHand(hideRivalHand);
setHideRivalHand(true);
setGameStatus('ready');
syncGameStatus = 'ready';
@ -844,6 +868,27 @@ function PvEDoudizhuDemoView() {
}
};
const computeCardRecorderCards = (cards) => {
return (
<div className={'unselectable playingCards loose ' + toggleFade}>
<ul className="hand" style={{ width: computeHandCardsWidth(computedCards.length, 10) }}>
{cards.map((card) => {
const [rankClass, suitClass, rankText, suitText] = translateDouzeroCardData(card);
return (
<li key={`handCard-${card}`}>
<label className={`card ${rankClass} ${suitClass}`} href="/#">
<span className="rank">{rankText}</span>
<span className="suit">{suitText}</span>
<span className="count">{cards[card]}</span>
</label>
</li>
);
})}
</ul>
</div>
);
};
const computeProbabilityItem = (idx) => {
if (gameStatus !== 'ready') {
if (hidePredictionArea) {
@ -880,6 +925,29 @@ function PvEDoudizhuDemoView() {
}
};
const computeCardRecorder = () => {
if (gameStatus !== 'ready') {
if (!showCardRecorder) {
return (
<div className={'playing'}>
<div className={'non-card'}>
<span>{t('hidden')}</span>
</div>
</div>
);
}
return (
<div className={'playing'}>
<div className="probability-move">
{computeCardRecorderCards(cardRecorder)}
</div>
</div>
);
} else {
return <span className={'waiting'}>{t('waiting...')}</span>;
}
};
const gameSpeedMarks = [
{
value: 0,
@ -1053,7 +1121,7 @@ function PvEDoudizhuDemoView() {
<div className={'probability-item'}>{computeProbabilityItem(0)}</div>
<div className={'probability-item'}>{computeProbabilityItem(1)}</div>
<div className={'probability-item'}>{computeProbabilityItem(2)}</div>
<div className={'probability-item'}>{computeProbabilityItem(3)}</div>
<div className={'probability-item'}>{computeCardRecorder()}</div>
</div>
</Paper>
</Layout.Col>
@ -1079,6 +1147,14 @@ function PvEDoudizhuDemoView() {
}
label={t('doudizhu.ai_prediction')}
/>
<FormControlLabel
style={{ textAlign: 'center', height: '100%', display: 'inline-block' }}
className="switch-control"
control={
<Switch checked={!showCardRecorder} onChange={toggleShowCardRecorder} />
}
label={t('doudizhu.card_recorder')}
/>
</FormGroup>
</Layout.Col>
<Layout.Col span="1" style={{ height: '100%', width: '1px' }}>