Commit 5a8b3a4f authored by sbl1996@126.com's avatar sbl1996@126.com

Add autoSelect

parent bde80f6a
Pipeline #28166 failed with stages
in 29 seconds
......@@ -369,7 +369,7 @@ export function convertDeckCard(meta: CardMeta): Card {
}
export function convertCard(card: CardType, player: number): Card {
// TODO (ygo-agent): unseen cards
// TODO (ygo-agent): opponent's visible facedown cards (confirm_cards)
return {
code: card.code,
location: cardZoneToLocation(card.location.zone),
......@@ -478,6 +478,8 @@ interface MsgSelectCard {
selected: number[];
}
export type MultiSelectMsg = MsgSelectCard | MsgSelectSum | MsgSelectTribute;
function convertMsgSelectCard(msg: GM.MsgSelectCard): MsgSelectCard {
// response is -1 for finish
return {
......@@ -489,7 +491,6 @@ function convertMsgSelectCard(msg: GM.MsgSelectCard): MsgSelectCard {
location: convertCardLocation(c.location, msg.player),
response: c.response
})),
// TODO (ygo-agent): the indices of the selected `cards`
selected: [],
};
}
......@@ -520,7 +521,6 @@ function convertMsgSelectTribute(msg: GM.MsgSelectTribute): MsgSelectTribute {
level: c.level,
response: c.response,
})),
// TODO (ygo-agent): the indices of the selected `cards`
selected: [],
};
}
......@@ -532,7 +532,7 @@ interface SelectSumCard {
response: number;
}
interface MsgSelectSum {
export interface MsgSelectSum {
msg_type: "select_sum";
overflow: boolean;
level_sum: number;
......@@ -562,7 +562,6 @@ function convertMsgSelectSum(msg: GM.MsgSelectSum): MsgSelectSum {
level2: c.level2,
response: c.response,
})),
// TODO (ygo-agent): the indices of the selected `cards`
selected: [],
}
}
......@@ -665,7 +664,8 @@ function convertMsgSelectIdleCmd(msg: GM.MsgSelectIdleCmd): MsgSelectIdleCmd {
// response will be 6
idle_cmds.push({ cmd_type: IdleCmdType.ToBp });
}
if (msg.enable_ep) {
// TODO (ygo-agent): new models will support it
if (msg.enable_ep && !msg.enable_bp) {
// response will be 7
idle_cmds.push({ cmd_type: IdleCmdType.ToEp });
}
......@@ -724,20 +724,20 @@ function convertMsgSelectPosition(msg: GM.MsgSelectPosition): MsgSelectPosition
}
interface MsgSelectYesNo {
msg_type: "select_yes_no";
msg_type: "select_yesno";
effect_description: number;
}
function convertMsgSelectYesNo(msg: GM.MsgSelectYesNo): MsgSelectYesNo {
// response is 1 for yes and 0 for no
return {
msg_type: "select_yes_no",
msg_type: "select_yesno",
effect_description: msg.effect_description,
};
}
interface MsgSelectEffectYn {
msg_type: "select_effect_yn";
msg_type: "select_effectyn";
code: number;
location: CardLocation;
effect_description: number;
......@@ -746,7 +746,7 @@ interface MsgSelectEffectYn {
function convertMsgSelectEffectYn(msg: GM.MsgSelectEffectYn): MsgSelectEffectYn {
// response is 1 for yes and 0 for no
return {
msg_type: "select_effect_yn",
msg_type: "select_effectyn",
code: msg.code,
location: convertCardLocation(msg.location, msg.player),
effect_description: msg.effect_description,
......@@ -807,7 +807,8 @@ function convertMsgSelectBattleCmd(msg: GM.MsgSelectBattleCmd): MsgSelectBattleC
// response will be 2
battle_cmds.push({ cmd_type: BattleCmdType.ToM2 });
}
if (msg.enable_ep) {
// TODO (ygo-agent): new models will support it
if (msg.enable_ep && !msg.enable_m2) {
// response will be 3
battle_cmds.push({ cmd_type: BattleCmdType.ToEp });
}
......@@ -886,6 +887,7 @@ interface MsgSelectPlace {
places: Place[];
}
// TODO (ygo-agent): SelectDisfield is different from SelectPlace
function convertMsgSelectPlace(msg: GM.MsgSelectPlace): MsgSelectPlace {
return {
msg_type: "select_place",
......@@ -899,8 +901,6 @@ function convertMsgSelectPlace(msg: GM.MsgSelectPlace): MsgSelectPlace {
};
}
// TODO (ygo-agent): MsgSelectDisfield
interface AnnounceAttrib {
attribute: Attribute;
response: number;
......@@ -962,23 +962,6 @@ type ActionMsgData =
MsgAnnounceAttrib |
MsgAnnounceNumber;
// export enum ActionMsgName {
// AnnounceAttrib = "announce_attrib",
// AnnounceNumber = "announce_number",
// SelectBattlecmd = "select_battlecmd",
// SelectCard = "select_card",
// SelectChain = "select_chain",
// SelectDisfield = "select_disfield",
// SelectEffectyn = "select_effectyn",
// SelectIdlecmd = "select_idlecmd",
// SelectOption = "select_option",
// SelectPlace = "select_place",
// SelectPosition = "select_position",
// SelectSum = "select_sum",
// SelectTribute = "select_tribute",
// SelectUnselectCard = "select_unselect_card",
// SelectYesno = "select_yesno",
// }
interface ActionMsg {
data: ActionMsgData;
......@@ -1059,6 +1042,7 @@ export interface Input {
interface ActionPredict {
prob: number;
response: number;
can_finish: boolean;
}
export interface MsgResponse {
......
......@@ -12,7 +12,10 @@ import {
sendSortCardResponse,
} from "@/api";
import { cardStore, matStore } from "@/stores";
import { Global, convertPhase, convertCard, convertDeckCard, parsePlayerFromMsg, convertActionMsg, Input } from "@/api/ygoAgent/schema";
import {
Global, convertPhase, convertCard, convertDeckCard,
parsePlayerFromMsg, convertActionMsg, Input, MultiSelectMsg, MsgSelectSum
} from "@/api/ygoAgent/schema";
import { predictDuel } from "@/api/ygoAgent/predict";
function computeSetDifference(a1: number[], a2: number[]): number[] {
......@@ -20,10 +23,10 @@ function computeSetDifference(a1: number[], a2: number[]): number[] {
const freq2 = new Map<number, number>();
for (const num of a1) {
freq1.set(num, (freq1.get(num) || 0) + 1);
freq1.set(num, (freq1.get(num) || 0) + 1);
}
for (const num of a2) {
freq2.set(num, (freq2.get(num) || 0) + 1);
freq2.set(num, (freq2.get(num) || 0) + 1);
}
for (const [num, count] of freq2) {
......@@ -42,7 +45,7 @@ function computeSetDifference(a1: number[], a2: number[]): number[] {
}
export function genPredictReq(msg: ygopro.StocGameMessage): PredictReq {
export function genInput(msg: ygopro.StocGameMessage): Input {
// 全局信息可以从 `matStore` 里面拿
const mat = matStore;
// 卡片信息可以从 `cardStore` 里面拿
......@@ -60,7 +63,6 @@ export function genPredictReq(msg: ygopro.StocGameMessage): PredictReq {
// 这里已经保证 `msg` 是众多 `select_xxx` msg 中的一个
const player = parsePlayerFromMsg(msg);
// TODO (ygo-agent): check if this is correct
const opponent = 1 - player;
const cards = cardStore.inner
......@@ -72,15 +74,15 @@ export function genPredictReq(msg: ygopro.StocGameMessage): PredictReq {
)
.map((card) => convertCard(card, player));
const card_codes_me = cardStore.inner
.filter((card) =>
zones.includes(card.location.zone) && card.location.controller === player
)
.map((card) => card.code);
const card_codes_me_deck = computeSetDifference(mat.main_deck, card_codes_me);
const main_deck_card_meta = mat.main_deck_card_meta;
const cardCodesMe = cardStore.inner
.filter((card) =>
zones.includes(card.location.zone) && card.location.controller === player
)
.map((card) => card.code);
const cardCodesMeDeck = computeSetDifference(mat.mainDeck, cardCodesMe);
const mainDeckCardMeta = mat.mainDeckCardMeta;
// TODO (ygo-agent): 临时方案,有很多边界情况未考虑
const deck_cards_me = card_codes_me_deck.map((code) => convertDeckCard(main_deck_card_meta.get(code)!));
const deckCardsMe = cardCodesMeDeck.map((code) => convertDeckCard(mainDeckCardMeta.get(code)!));
const turnPlayer = mat.currentPlayer;
const global: Global = {
......@@ -89,28 +91,20 @@ export function genPredictReq(msg: ygopro.StocGameMessage): PredictReq {
my_lp: mat.initInfo.of(player).life,
op_lp: mat.initInfo.of(opponent).life,
phase: convertPhase(mat.phase.currentPhase),
turn: mat.turn_count,
turn: mat.turnCount,
}
const actionMsg = convertActionMsg(msg);
const input: Input = {
return {
global: global,
cards: deck_cards_me.concat(cards),
cards: deckCardsMe.concat(cards),
action_msg: actionMsg,
}
return {
index: mat.agentIndex,
input: input,
prev_action_idx: mat.prevActionIndex,
}
}
export async function sendAIPredictAsResponse(msg: ygopro.StocGameMessage) {
// const msg = matStore.actionMsg;
const req = genPredictReq(msg);
async function sendRequest(req: PredictReq) {
console.log("Sending predict request:", req);
const duelId = matStore.duelId;
const resp = await predictDuel(duelId, req);
......@@ -119,59 +113,121 @@ export async function sendAIPredictAsResponse(msg: ygopro.StocGameMessage) {
matStore.agentIndex = resp.index;
}
else {
console.error("Failed to get predict response");
return;
throw new Error("Failed to get predict response");
}
const preds = resp.predict_results.action_preds;
const action_idx = argmax(preds, (r) => r.prob);
matStore.prevActionIndex = action_idx;
const response = preds[action_idx].response;
const msg_name = req.input.action_msg.data.msg_type;
switch (msg_name) {
case "announce_attrib":
case "announce_number":
sendSelectOptionResponse(response);
break;
case "select_battle_cmd":
sendSelectBattleCmdResponse(response);
break;
case "select_chain":
sendSelectSingleResponse(response);
break;
case "select_yes_no":
case "select_effect_yn":
sendSelectEffectYnResponse(response === 1);
break;
case "select_idle_cmd":
sendSelectIdleCmdResponse(response);
break;
case "select_option":
sendSelectOptionResponse(response);
break;
case "select_position":
sendSelectPositionResponse(convertPositionResponse(response));
break;
case "select_place":
const place = (msg as unknown as ygopro.StocGameMessage.MsgSelectPlace).places[response];
sendSelectPlaceResponse({
controller: place.controller,
zone: place.zone,
sequence: place.sequence,
});
break;
case "select_unselect_card":
case "select_card":
const msg_ = msg as unknown as ygopro.StocGameMessage.MsgSelectCard;
if (msg_.min === 1 && msg_.max === 1) {
sendSelectMultiResponse([response]);
} else {
throw new Error(`Unsupported select_card for min=${msg_.min}, max=${msg_.max}`);
const actionIdx = argmax(preds, (r) => r.prob);
matStore.prevActionIndex = actionIdx;
const pred = preds[actionIdx];
return pred;
}
export async function sendAIPredictAsResponse(msg: ygopro.StocGameMessage) {
const input = genInput(msg);
const msgName = input.action_msg.data.msg_type;
const multiSelectMsgs = ["select_card", "select_tribute", "select_sum"];
if (multiSelectMsgs.includes(msgName)) {
switch (msgName) {
case "select_tribute":
case "select_card": {
const msg_ = input.action_msg.data as MultiSelectMsg;
const selected = [];
const responses = [];
while (true) {
msg_.selected = selected;
const req = {
index: matStore.agentIndex,
input: input,
prev_action_idx: matStore.prevActionIndex,
};
const response = (await sendRequest(req)).response;
if (response != -1) {
selected.push(matStore.prevActionIndex);
responses.push(response);
}
if (response == -1 || selected.length == msg_.max) {
sendSelectMultiResponse(responses);
break;
}
}
break;
}
break;
case "select_sum":
case "select_tribute":
throw new Error(`Unsupported msg_name: ${msg_name}`);
case "select_sum":
const msg_ = input.action_msg.data as MsgSelectSum;
const selected = [];
const responses = [];
for (const c of msg_.must_cards) {
responses.push(c.response);
}
while (true) {
msg_.selected = selected;
const req = {
index: matStore.agentIndex,
input: input,
prev_action_idx: matStore.prevActionIndex,
};
const pred = await sendRequest(req);
const idx = matStore.prevActionIndex
selected.push(idx);
responses.push(pred.response);
if (pred.can_finish) {
sendSelectMultiResponse(responses);
break;
}
}
break;
}
} else {
const req = {
index: matStore.agentIndex,
input: input,
prev_action_idx: matStore.prevActionIndex,
};
const response = (await sendRequest(req)).response;
switch (msgName) {
case "announce_attrib":
case "announce_number":
sendSelectOptionResponse(response);
break;
case "select_battlecmd":
sendSelectBattleCmdResponse(response);
break;
case "select_chain":
sendSelectSingleResponse(response);
break;
case "select_yesno":
case "select_effectyn":
sendSelectEffectYnResponse(response === 1);
break;
case "select_idlecmd":
sendSelectIdleCmdResponse(response);
break;
case "select_option":
sendSelectOptionResponse(response);
break;
case "select_position":
sendSelectPositionResponse(convertPositionResponse(response));
break;
case "select_place": {
const place = (msg as unknown as ygopro.StocGameMessage.MsgSelectPlace).places[response];
sendSelectPlaceResponse({
controller: place.controller,
zone: place.zone,
sequence: place.sequence,
});
break;
}
case "select_unselect_card": {
if (response == -1) {
sendSelectSingleResponse(-1);
} else {
sendSelectMultiResponse([response]);
}
break;
}
}
}
}
......
......@@ -3,11 +3,14 @@ import { displayOptionModal } from "@/ui/Duel/Message";
import MsgAnnounce = ygopro.StocGameMessage.MsgAnnounce;
import { displayAnnounceModal } from "@/ui/Duel/Message/AnnounceModal";
import { sendAIPredictAsResponse } from "@/service/duel/agent";
import { matStore } from "@/stores";
export default async (announce: MsgAnnounce) => {
console.log("intercept announce");
await sendAIPredictAsResponse(announce as unknown as ygopro.StocGameMessage);
return;
if (matStore.autoSelect) {
console.log("intercept announce");
await sendAIPredictAsResponse(announce as unknown as ygopro.StocGameMessage);
return;
}
const type_ = announce.announce_type;
let min = announce.min;
......
......@@ -100,6 +100,8 @@ export default async function handleGameMsg(
if (replayStore.isReplay && ReplayIgnoreMsg.includes(msg.gameMsg)) return;
console.log(msg.gameMsg);
switch (msg.gameMsg) {
case "start": {
await onMsgStart(msg.start);
......
......@@ -6,5 +6,5 @@ export default (newTurn: ygopro.StocGameMessage.MsgNewTurn) => {
playEffect(AudioActionType.SOUND_NEXT_TURN);
const player = newTurn.player;
matStore.currentPlayer = player;
matStore.turn_count = matStore.turn_count + 1;
matStore.turnCount = matStore.turnCount + 1;
};
......@@ -18,9 +18,11 @@ export default async (selectBattleCmd: MsgSelectBattleCmd) => {
card.idleInteractivities = [];
});
console.log("intercept selectBattleCmd");
await sendAIPredictAsResponse(selectBattleCmd as unknown as ygopro.StocGameMessage);
return;
if (matStore.autoSelect) {
console.log("intercept selectBattleCmd");
await sendAIPredictAsResponse(selectBattleCmd as unknown as ygopro.StocGameMessage);
return;
}
cmds.forEach((cmd) => {
const interactType = battleTypeToInteracType(cmd.battle_type);
......
......@@ -6,23 +6,26 @@ import { displaySelectActionsModal } from "@/ui/Duel/Message/SelectActionsModal"
import { fetchCheckCardMeta } from "../utils";
import { sendAIPredictAsResponse } from "@/service/duel/agent";
import { matStore } from "@/stores";
export default async (selectCard: MsgSelectCard) => {
const { cancelable, min, max, cards } = selectCard;
// TODO: handle release_param
if (matStore.autoSelect) {
console.log("intercept selectCard");
await sendAIPredictAsResponse(selectCard as unknown as ygopro.StocGameMessage);
return;
}
if (!cancelable && cards.length === 1) {
// auto send
sendSelectMultiResponse([cards[0].response]);
return;
}
if (min === 1 && max === 1) {
console.log("intercept selectCard");
await sendAIPredictAsResponse(selectCard as unknown as ygopro.StocGameMessage);
return;
}
const { selecteds, mustSelects, selectables } = await fetchCheckCardMeta(
cards,
......
......@@ -67,9 +67,11 @@ export default async (selectChain: MsgSelectChain) => {
}
case 2: // 处理多张
case 3: {
console.log("intercept selectChain");
await sendAIPredictAsResponse(selectChain as unknown as ygopro.StocGameMessage);
return;
if (matStore.autoSelect) {
console.log("intercept selectChain");
await sendAIPredictAsResponse(selectChain as unknown as ygopro.StocGameMessage);
return;
}
// 处理强制发动的卡
fetchSelectHintMeta({
......
......@@ -2,14 +2,17 @@ import { fetchStrings, Region, type ygopro } from "@/api";
import { CardMeta, fetchCard } from "@/api/cards";
import { displayYesNoModal } from "@/ui/Duel/Message";
import { sendAIPredictAsResponse } from "@/service/duel/agent";
import { matStore } from "@/stores";
type MsgSelectEffectYn = ygopro.StocGameMessage.MsgSelectEffectYn;
// 这里改成了 async 不知道有没有影响
export default async (selectEffectYn: MsgSelectEffectYn) => {
console.log("intercept announce");
await sendAIPredictAsResponse(selectEffectYn as unknown as ygopro.StocGameMessage);
return;
if (matStore.autoSelect) {
console.log("intercept selectEffectYn");
await sendAIPredictAsResponse(selectEffectYn as unknown as ygopro.StocGameMessage);
return;
}
const code = selectEffectYn.code;
const location = selectEffectYn.location;
......
......@@ -18,9 +18,11 @@ export default async (selectIdleCmd: MsgSelectIdleCmd) => {
card.idleInteractivities = [];
});
console.log("intercept selectIdleCmd");
await sendAIPredictAsResponse(selectIdleCmd as unknown as ygopro.StocGameMessage);
return;
if (matStore.autoSelect) {
console.log("intercept selectIdleCmd");
await sendAIPredictAsResponse(selectIdleCmd as unknown as ygopro.StocGameMessage);
return;
}
cmds.forEach((cmd) => {
const interactType = idleTypeToInteractType(cmd.idle_type);
......
......@@ -7,6 +7,7 @@ import {
} from "@/api";
import { displayOptionModal } from "@/ui/Duel/Message";
import { sendAIPredictAsResponse } from "@/service/duel/agent";
import { matStore } from "@/stores";
export default async (selectOption: ygopro.StocGameMessage.MsgSelectOption) => {
const options = selectOption.options;
......@@ -14,15 +15,18 @@ export default async (selectOption: ygopro.StocGameMessage.MsgSelectOption) => {
sendSelectOptionResponse(0);
return;
}
if (matStore.autoSelect) {
console.log("intercept selectOption");
await sendAIPredictAsResponse(selectOption as unknown as ygopro.StocGameMessage);
return;
}
if (options.length === 1) {
sendSelectOptionResponse(options[0].response);
return;
}
console.log("intercept selectOption");
await sendAIPredictAsResponse(selectOption as unknown as ygopro.StocGameMessage);
return;
await displayOptionModal(
fetchStrings(Region.System, 556),
options.map(({ code, response }) => ({
......
import { sendSelectPlaceResponse, ygopro } from "@/api";
import { InteractType, placeStore } from "@/stores";
import { InteractType, placeStore, matStore } from "@/stores";
import { sendAIPredictAsResponse } from "@/service/duel/agent";
type MsgSelectPlace = ygopro.StocGameMessage.MsgSelectPlace;
......@@ -10,6 +10,12 @@ export default async (selectPlace: MsgSelectPlace) => {
return;
}
if (matStore.autoSelect) {
console.log("intercept selectPlace");
await sendAIPredictAsResponse(selectPlace as unknown as ygopro.StocGameMessage);
return;
}
if (selectPlace.places.length === 1) {
const place = selectPlace.places[0];
sendSelectPlaceResponse({
......@@ -21,26 +27,22 @@ export default async (selectPlace: MsgSelectPlace) => {
return;
}
console.log("intercept announce");
await sendAIPredictAsResponse(selectPlace as unknown as ygopro.StocGameMessage);
return;
// for (const place of selectPlace.places) {
// switch (place.zone) {
// case ygopro.CardZone.MZONE:
// case ygopro.CardZone.SZONE:
// const block = placeStore.of(place);
// if (block) {
// block.interactivity = {
// interactType: InteractType.PLACE_SELECTABLE,
// response: {
// controller: place.controller,
// zone: place.zone,
// sequence: place.sequence,
// },
// };
// }
// break;
// }
// }
for (const place of selectPlace.places) {
switch (place.zone) {
case ygopro.CardZone.MZONE:
case ygopro.CardZone.SZONE:
const block = placeStore.of(place);
if (block) {
block.interactivity = {
interactType: InteractType.PLACE_SELECTABLE,
response: {
controller: place.controller,
zone: place.zone,
sequence: place.sequence,
},
};
}
break;
}
}
};
import { ygopro } from "@/api";
import { displayPositionModal } from "@/ui/Duel/Message";
import { sendAIPredictAsResponse } from "@/service/duel/agent";
import { matStore } from "@/stores";
type MsgSelectPosition = ygopro.StocGameMessage.MsgSelectPosition;
export default async (selectPosition: MsgSelectPosition) => {
console.log("intercept announce");
await sendAIPredictAsResponse(selectPosition as unknown as ygopro.StocGameMessage);
return;
if (matStore.autoSelect) {
console.log("intercept selectPosition");
await sendAIPredictAsResponse(selectPosition as unknown as ygopro.StocGameMessage);
return;
}
const _player = selectPosition.player;
const positions = selectPosition.positions.map(
......
......@@ -4,7 +4,16 @@ import { displaySelectActionsModal } from "@/ui/Duel/Message/SelectActionsModal"
import { fetchCheckCardMeta } from "../utils";
type MsgSelectSum = ygopro.StocGameMessage.MsgSelectSum;
import { sendAIPredictAsResponse } from "@/service/duel/agent";
import { matStore } from "@/stores";
export default async (selectSum: MsgSelectSum) => {
if (matStore.autoSelect) {
console.log("intercept selectSum");
await sendAIPredictAsResponse(selectSum as unknown as ygopro.StocGameMessage);
return;
}
const {
selecteds: selecteds1,
mustSelects: mustSelect1,
......
......@@ -4,11 +4,20 @@ import { displaySelectActionsModal } from "@/ui/Duel/Message/SelectActionsModal"
import { fetchCheckCardMeta } from "../utils";
type MsgSelectTribute = ygopro.StocGameMessage.MsgSelectTribute;
import { sendAIPredictAsResponse } from "@/service/duel/agent";
import { matStore } from "@/stores";
export default async (selectTribute: MsgSelectTribute) => {
// TODO: 当玩家选择卡数大于`max`时,是否也合法?
if (matStore.autoSelect) {
console.log("intercept selectTribute");
await sendAIPredictAsResponse(selectTribute as unknown as ygopro.StocGameMessage);
return;
}
const { selecteds, mustSelects, selectables } = await fetchCheckCardMeta(
selectTribute.selectable_cards,
);
// TODO: 当玩家选择卡数大于`max`时,是否也合法?
await displaySelectActionsModal({
overflow: true,
totalLevels: 0,
......
......@@ -6,14 +6,23 @@ import { fetchCheckCardMeta } from "../utils";
import { isAllOnField } from "./util";
type MsgSelectUnselectCard = ygopro.StocGameMessage.MsgSelectUnselectCard;
export default async ({
finishable,
cancelable,
min,
max,
selectable_cards: selectableCards,
selected_cards: selectedCards,
}: MsgSelectUnselectCard) => {
import { sendAIPredictAsResponse } from "@/service/duel/agent";
export default async (selectUnselectCards: MsgSelectUnselectCard) => {
if (matStore.autoSelect) {
console.log("intercept selectUnselectCards");
await sendAIPredictAsResponse(selectUnselectCards as unknown as ygopro.StocGameMessage);
return;
}
const {
finishable,
cancelable,
min,
max,
selectable_cards: selectableCards,
selected_cards: selectedCards,
} = selectUnselectCards;
if (
isAllOnField(
selectableCards.concat(selectedCards).map((info) => info.location),
......
import { getStrings, ygopro } from "@/api";
import { displayYesNoModal } from "@/ui/Duel/Message";
import { sendAIPredictAsResponse } from "@/service/duel/agent";
import { matStore } from "@/stores";
type MsgSelectYesNo = ygopro.StocGameMessage.MsgSelectYesNo;
export default async (selectYesNo: MsgSelectYesNo) => {
console.log("intercept selectYesNo");
await sendAIPredictAsResponse(selectYesNo as unknown as ygopro.StocGameMessage);
return;
if (matStore.autoSelect) {
console.log("intercept selectYesNo");
await sendAIPredictAsResponse(selectYesNo as unknown as ygopro.StocGameMessage);
return;
}
const _player = selectYesNo.player;
const effect_description = selectYesNo.effect_description;
......
import { fetchCard, ygopro } from "@/api";
import { displaySortCardModal } from "@/ui/Duel/Message";
import { matStore } from "@/stores";
type MsgSortCard = ygopro.StocGameMessage.MsgSortCard;
export default async (sortCard: MsgSortCard) => {
if (matStore.autoSelect) {
console.log("intercept selectTribute");
// TODO (ygo-agent): don't sort, should response 255
}
const options = await Promise.all(
sortCard.options.map(async ({ code, response }) => {
const meta = fetchCard(code!);
......
......@@ -92,7 +92,7 @@ export default async (start: ygopro.StocGameMessage.MsgStart) => {
const { duelId, index } = (await createDuel())!;
matStore.duelId = duelId;
matStore.agentIndex = index;
matStore.main_deck_card_meta = matStore.main_deck
matStore.mainDeckCardMeta = matStore.mainDeck
.reduce((map, item) => {
if (!map.has(item)) {
map.set(item, fetchCard(item));
......
......@@ -93,13 +93,13 @@ const initialState: Omit<MatState, "reset"> = {
duelEnd: false,
// methods
isMe,
turn_count: 0,
turnCount: 0,
duelId: "",
agentIndex: 0,
prevActionIndex: 0,
actionMsg: undefined,
main_deck: [],
main_deck_card_meta: new Map(),
mainDeck: [],
mainDeckCardMeta: new Map(),
autoSelect: false,
};
class MatStore implements MatState, NeosStore {
......@@ -116,13 +116,13 @@ class MatStore implements MatState, NeosStore {
tossResult = initialState.tossResult;
selectUnselectInfo = initialState.selectUnselectInfo;
duelEnd = initialState.duelEnd;
turn_count = initialState.turn_count;
turnCount = initialState.turnCount;
duelId = initialState.duelId;
agentIndex = initialState.agentIndex;
prevActionIndex = initialState.prevActionIndex;
actionMsg = initialState.actionMsg;
main_deck = initialState.main_deck;
main_deck_card_meta = initialState.main_deck_card_meta;
mainDeck = initialState.mainDeck;
mainDeckCardMeta = initialState.mainDeckCardMeta;
autoSelect = initialState.autoSelect;
// methods
isMe = initialState.isMe;
......@@ -152,13 +152,13 @@ class MatStore implements MatState, NeosStore {
selectedList: [],
};
this.duelEnd = false;
this.turn_count = 0;
this.turnCount = 0;
this.duelId = "";
this.agentIndex = 0;
this.prevActionIndex = 0;
this.actionMsg = undefined;
this.main_deck = [];
this.main_deck_card_meta = new Map();
this.mainDeck = [];
this.mainDeckCardMeta = new Map();
this.autoSelect = false;
}
}
......
......@@ -50,14 +50,13 @@ export interface MatState {
/** 根据自己的先后手判断是否是自己 */
isMe: (player: number) => boolean;
// TODO (ygo-agent): 检查实现是否正确
turn_count: number,
turnCount: number,
duelId: string;
agentIndex: number;
prevActionIndex: number;
actionMsg?: any;
main_deck: number[];
main_deck_card_meta: Map<number, CardMeta>;
mainDeck: number[];
mainDeckCardMeta: Map<number, CardMeta>;
autoSelect: boolean;
}
export interface InitInfo {
......
......@@ -5,6 +5,7 @@ import {
MessageFilled,
StepForwardFilled,
RobotFilled,
RobotOutlined,
} from "@ant-design/icons";
import {
Button,
......@@ -29,7 +30,6 @@ import {
} from "@/api";
import { ChainSetting, matStore } from "@/stores";
import { IconFont } from "@/ui/Shared";
import { sendAIPredictAsResponse } from "@/service/duel/agent";
import styles from "./index.module.scss";
import PhaseType = ygopro.StocGameMessage.MsgNewPhase.PhaseType;
......@@ -215,6 +215,7 @@ export const Menu = () => {
const [phaseSwitchItems, setPhaseSwitchItems] = useState<MenuProps["items"]>(
[],
);
const [autoSelect, setAutoSelect] = useState(false);
useEffect(() => {
const endResponse = [
......@@ -299,8 +300,10 @@ export const Menu = () => {
const globalDisable = !matStore.isMe(currentPlayer);
const aiPredict = async () => {
await sendAIPredictAsResponse();
const switchAutoSelect = () => {
const newAutoSelect = !autoSelect;
matStore.autoSelect = newAutoSelect;
setAutoSelect(newAutoSelect);
};
return (
......@@ -331,8 +334,8 @@ export const Menu = () => {
</DropdownWithTitle>
<Tooltip title="AI">
<Button
icon={<RobotFilled />}
onClick={aiPredict}
icon={autoSelect ? <RobotFilled /> : <RobotOutlined />}
onClick={switchAutoSelect}
type="text"
></Button>
</Tooltip>
......
......@@ -65,7 +65,7 @@ export const Component: React.FC = () => {
const updateDeck = (deck: IDeck) => {
sendUpdateDeck(deck);
matStore.main_deck = deck.main;
matStore.mainDeck = deck.main;
// 设置side里面的卡组
sideStore.setSideDeck(deck);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment