Spaces:
Sleeping
Sleeping
| /** | |
| * 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 | |
| }; | |
| }); | |