trigo / trigo-web /app /src /stores /mctsStore.ts
k-l-lambda's picture
Update trigo-web with VS People multiplayer mode
15f353f
/**
* Pinia store for MCTS visualization state
*/
import { defineStore } from "pinia";
import { ref, computed } from "vue";
import type {
MCTSMoveData,
MCTSMoveStatistic,
MCTSStatisticType,
ColorScaleType
} from "@/types/mcts";
import type { Position } from "../../../inc/trigo/types";
export const useMCTSStore = defineStore("mcts", () => {
// ============================================================================
// State
// ============================================================================
// Game data
const gameHistory = ref<MCTSMoveData[]>([]);
const currentMoveIndex = ref<number>(0);
// Visualization settings
const selectedStatistic = ref<MCTSStatisticType>("N");
const colorScale = ref<ColorScaleType>("linear");
const topNFilter = ref<number>(10); // Show top N moves in tree/table
// Selection state
const selectedActionKey = ref<string | null>(null);
// ============================================================================
// Getters
// ============================================================================
const hasData = computed(() => gameHistory.value.length > 0);
const currentMoveData = computed((): MCTSMoveData | null => {
if (!hasData.value) return null;
return gameHistory.value[currentMoveIndex.value] || null;
});
const maxMoveIndex = computed(() => {
return Math.max(0, gameHistory.value.length - 1);
});
const currentStatistics = computed((): MCTSMoveStatistic[] => {
return currentMoveData.value?.statistics || [];
});
const topMoves = computed((): MCTSMoveStatistic[] => {
const stats = currentStatistics.value;
return stats
.slice()
.sort((a, b) => b.N - a.N)
.slice(0, topNFilter.value);
});
const totalVisits = computed((): number => {
return currentStatistics.value.reduce((sum, stat) => sum + stat.N, 0);
});
const selectedMove = computed((): MCTSMoveStatistic | null => {
if (!selectedActionKey.value) return null;
return (
currentStatistics.value.find(
(stat) => stat.actionKey === selectedActionKey.value
) || null
);
});
// ============================================================================
// Actions
// ============================================================================
function setGameHistory(history: MCTSMoveData[]) {
gameHistory.value = history;
currentMoveIndex.value = 0;
selectedActionKey.value = null;
}
function clearGameHistory() {
gameHistory.value = [];
currentMoveIndex.value = 0;
selectedActionKey.value = null;
}
function setCurrentMoveIndex(index: number) {
if (index < 0 || index > maxMoveIndex.value) return;
currentMoveIndex.value = index;
// Clear selection when moving to different move
selectedActionKey.value = null;
}
function nextMove() {
if (currentMoveIndex.value < maxMoveIndex.value) {
setCurrentMoveIndex(currentMoveIndex.value + 1);
}
}
function prevMove() {
if (currentMoveIndex.value > 0) {
setCurrentMoveIndex(currentMoveIndex.value - 1);
}
}
function firstMove() {
setCurrentMoveIndex(0);
}
function lastMove() {
setCurrentMoveIndex(maxMoveIndex.value);
}
function setSelectedStatistic(stat: MCTSStatisticType) {
selectedStatistic.value = stat;
}
function setColorScale(scale: ColorScaleType) {
colorScale.value = scale;
}
function setTopNFilter(n: number) {
topNFilter.value = Math.max(3, Math.min(50, n));
}
function selectAction(actionKey: string | null) {
selectedActionKey.value = actionKey;
}
function selectPosition(position: Position | null) {
if (!position) {
selectedActionKey.value = "pass";
return;
}
selectedActionKey.value = `${position.x},${position.y},${position.z}`;
}
// ============================================================================
// Return
// ============================================================================
return {
// State
gameHistory,
currentMoveIndex,
selectedStatistic,
colorScale,
topNFilter,
selectedActionKey,
// Getters
hasData,
currentMoveData,
maxMoveIndex,
currentStatistics,
topMoves,
totalVisits,
selectedMove,
// Actions
setGameHistory,
clearGameHistory,
setCurrentMoveIndex,
nextMove,
prevMove,
firstMove,
lastMove,
setSelectedStatistic,
setColorScale,
setTopNFilter,
selectAction,
selectPosition
};
});