From 579da565021966b36f7b17566db4675397d44e9d Mon Sep 17 00:00:00 2001 From: MR0TOM Date: Tue, 17 Mar 2026 11:04:50 +0000 Subject: [PATCH 1/3] Updated Documentation in README.md --- DIRECTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index b7b8aca45d..8046a4303e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -322,8 +322,8 @@ * [TernarySearch](Search/TernarySearch.js) * [UnionFind](Search/UnionFind.js) * **Sliding-Windows** - * [MaxSumSubarrayFixed](Sliding-Windows/MaxSumSubarrayFixed.js) * [LongestSubarrayWithSumAtMost](Sliding-Windows/LongestSubarrayWithSumAtMost.js) + * [MaxSumSubarrayFixed](Sliding-Windows/MaxSumSubarrayFixed.js) * **Sorts** * [AlphaNumericalSort](Sorts/AlphaNumericalSort.js) * [BeadSort](Sorts/BeadSort.js) From 30301dc7ecadd4c4ab9f1ca6bd0710bbce030c1c Mon Sep 17 00:00:00 2001 From: Mr0Tom Date: Tue, 17 Mar 2026 20:51:43 +0800 Subject: [PATCH 2/3] Kimi-K2.5 --- 002game/algorithms.js | 661 ++++++++++++++++++++++++++++++++++ 002game/game.js | 821 ++++++++++++++++++++++++++++++++++++++++++ 002game/index.html | 147 ++++++++ 002game/styles.css | 819 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 2448 insertions(+) create mode 100644 002game/algorithms.js create mode 100644 002game/game.js create mode 100644 002game/index.html create mode 100644 002game/styles.css diff --git a/002game/algorithms.js b/002game/algorithms.js new file mode 100644 index 0000000000..35d6f79dab --- /dev/null +++ b/002game/algorithms.js @@ -0,0 +1,661 @@ +// 算法实现和可视化逻辑 + +// 工具函数 +const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); + +// 排序算法类 +class SortingAlgorithms { + constructor(visualizer) { + this.visualizer = visualizer; + this.isRunning = false; + this.speed = 500; + } + + setSpeed(speed) { + this.speed = 1100 - (speed * 100); + } + + stop() { + this.isRunning = false; + } + + // 冒泡排序 + async bubbleSort(array) { + this.isRunning = true; + const n = array.length; + const bars = this.visualizer.getBars(); + + for (let i = 0; i < n - 1 && this.isRunning; i++) { + let swapped = false; + for (let j = 0; j < n - i - 1 && this.isRunning; j++) { + // 高亮比较的元素 + bars[j].classList.add('comparing'); + bars[j + 1].classList.add('comparing'); + await sleep(this.speed); + + if (array[j] > array[j + 1]) { + // 交换 + bars[j].classList.add('swapping'); + bars[j + 1].classList.add('swapping'); + + [array[j], array[j + 1]] = [array[j + 1], array[j]]; + this.visualizer.updateBars(array); + + await sleep(this.speed); + bars[j].classList.remove('swapping'); + bars[j + 1].classList.remove('swapping'); + swapped = true; + } + + bars[j].classList.remove('comparing'); + bars[j + 1].classList.remove('comparing'); + } + + // 标记已排序的元素 + bars[n - i - 1].classList.add('sorted'); + + if (!swapped) break; + } + + // 标记第一个元素为已排序 + if (this.isRunning && bars[0]) { + bars[0].classList.add('sorted'); + } + + this.isRunning = false; + return array; + } + + // 快速排序 + async quickSort(array, low = 0, high = array.length - 1) { + // 只在初始调用时设置isRunning + if (low === 0 && high === array.length - 1) { + this.isRunning = true; + } + + if (!this.isRunning) return array; + + if (low < high) { + const pi = await this.partition(array, low, high); + await this.quickSort(array, low, pi - 1); + await this.quickSort(array, pi + 1, high); + } + + // 标记所有元素为已排序(当整个排序完成时) + if (low === 0 && high === array.length - 1) { + const bars = this.visualizer.getBars(); + for (let i = 0; i < array.length; i++) { + if (bars[i]) bars[i].classList.add('sorted'); + } + this.isRunning = false; + } + + return array; + } + + async partition(array, low, high) { + const bars = this.visualizer.getBars(); + const pivot = array[high]; + bars[high].classList.add('comparing'); + + let i = low - 1; + + for (let j = low; j < high && this.isRunning; j++) { + bars[j].classList.add('comparing'); + await sleep(this.speed); + + if (array[j] < pivot) { + i++; + [array[i], array[j]] = [array[j], array[i]]; + this.visualizer.updateBars(array); + + bars[i].classList.add('swapping'); + bars[j].classList.add('swapping'); + await sleep(this.speed); + bars[i].classList.remove('swapping'); + bars[j].classList.remove('swapping'); + } + + bars[j].classList.remove('comparing'); + } + + [array[i + 1], array[high]] = [array[high], array[i + 1]]; + this.visualizer.updateBars(array); + bars[high].classList.remove('comparing'); + bars[i + 1].classList.add('sorted'); + + return i + 1; + } + + // 归并排序 + async mergeSort(array, left = 0, right = array.length - 1) { + // 只在初始调用时设置isRunning + if (left === 0 && right === array.length - 1) { + this.isRunning = true; + } + + if (!this.isRunning) return array; + + if (left < right) { + const mid = Math.floor((left + right) / 2); + await this.mergeSort(array, left, mid); + await this.mergeSort(array, mid + 1, right); + await this.merge(array, left, mid, right); + } + + // 标记所有元素为已排序(当整个排序完成时) + if (left === 0 && right === array.length - 1) { + const bars = this.visualizer.getBars(); + for (let i = 0; i < array.length; i++) { + if (bars[i]) bars[i].classList.add('sorted'); + } + this.isRunning = false; + } + + return array; + } + + async merge(array, left, mid, right) { + const bars = this.visualizer.getBars(); + const n1 = mid - left + 1; + const n2 = right - mid; + + const L = array.slice(left, mid + 1); + const R = array.slice(mid + 1, right + 1); + + let i = 0, j = 0, k = left; + + while (i < n1 && j < n2 && this.isRunning) { + bars[k].classList.add('comparing'); + await sleep(this.speed); + + if (L[i] <= R[j]) { + array[k] = L[i]; + i++; + } else { + array[k] = R[j]; + j++; + } + + this.visualizer.updateBars(array); + bars[k].classList.remove('comparing'); + bars[k].classList.add('sorted'); + k++; + } + + while (i < n1 && this.isRunning) { + array[k] = L[i]; + this.visualizer.updateBars(array); + bars[k].classList.add('sorted'); + i++; + k++; + await sleep(this.speed / 2); + } + + while (j < n2 && this.isRunning) { + array[k] = R[j]; + this.visualizer.updateBars(array); + bars[k].classList.add('sorted'); + j++; + k++; + await sleep(this.speed / 2); + } + } + + // 堆排序 + async heapSort(array) { + this.isRunning = true; + const n = array.length; + + // 构建最大堆 + for (let i = Math.floor(n / 2) - 1; i >= 0 && this.isRunning; i--) { + await this.heapify(array, n, i); + } + + // 一个个从堆顶取出元素 + for (let i = n - 1; i > 0 && this.isRunning; i--) { + const bars = this.visualizer.getBars(); + bars[0].classList.add('swapping'); + bars[i].classList.add('swapping'); + + [array[0], array[i]] = [array[i], array[0]]; + this.visualizer.updateBars(array); + await sleep(this.speed); + + bars[0].classList.remove('swapping'); + bars[i].classList.remove('swapping'); + bars[i].classList.add('sorted'); + + await this.heapify(array, i, 0); + } + + if (this.isRunning) { + const bars = this.visualizer.getBars(); + bars[0].classList.add('sorted'); + } + + this.isRunning = false; + return array; + } + + async heapify(array, n, i) { + const bars = this.visualizer.getBars(); + let largest = i; + const left = 2 * i + 1; + const right = 2 * i + 2; + + bars[i].classList.add('comparing'); + await sleep(this.speed / 2); + + if (left < n && array[left] > array[largest]) { + largest = left; + } + + if (right < n && array[right] > array[largest]) { + largest = right; + } + + if (largest !== i) { + bars[largest].classList.add('swapping'); + + [array[i], array[largest]] = [array[largest], array[i]]; + this.visualizer.updateBars(array); + await sleep(this.speed); + + bars[largest].classList.remove('swapping'); + bars[i].classList.remove('comparing'); + + await this.heapify(array, n, largest); + } else { + bars[i].classList.remove('comparing'); + } + } +} + +// 搜索算法类 +class SearchAlgorithms { + constructor(visualizer) { + this.visualizer = visualizer; + this.isRunning = false; + this.speed = 800; + } + + setSpeed(speed) { + this.speed = 1500 - (speed * 130); + } + + stop() { + this.isRunning = false; + } + + // 线性搜索 + async linearSearch(array, target) { + this.isRunning = true; + const elements = this.visualizer.getSearchElements(); + + for (let i = 0; i < array.length && this.isRunning; i++) { + elements[i].classList.add('checking'); + await sleep(this.speed); + + if (array[i] === target) { + elements[i].classList.remove('checking'); + elements[i].classList.add('found'); + this.isRunning = false; + return i; + } + + elements[i].classList.remove('checking'); + elements[i].classList.add('not-found'); + } + + this.isRunning = false; + return -1; + } + + // 二分搜索 + async binarySearch(array, target) { + this.isRunning = true; + const elements = this.visualizer.getSearchElements(); + let left = 0; + let right = array.length - 1; + + while (left <= right && this.isRunning) { + const mid = Math.floor((left + right) / 2); + + // 高亮当前搜索范围 + for (let i = left; i <= right; i++) { + elements[i].style.opacity = '1'; + } + + elements[mid].classList.add('checking'); + await sleep(this.speed); + + if (array[mid] === target) { + elements[mid].classList.remove('checking'); + elements[mid].classList.add('found'); + this.isRunning = false; + return mid; + } + + elements[mid].classList.remove('checking'); + elements[mid].classList.add('not-found'); + + if (array[mid] < target) { + // 目标在右半部分 + for (let i = left; i <= mid; i++) { + elements[i].style.opacity = '0.3'; + } + left = mid + 1; + } else { + // 目标在左半部分 + for (let i = mid; i <= right; i++) { + elements[i].style.opacity = '0.3'; + } + right = mid - 1; + } + + await sleep(this.speed / 2); + } + + this.isRunning = false; + return -1; + } +} + +// 图算法类 +class GraphAlgorithms { + constructor(visualizer) { + this.visualizer = visualizer; + this.isRunning = false; + this.speed = 600; + } + + setSpeed(speed) { + this.speed = 1100 - (speed * 100); + } + + stop() { + this.isRunning = false; + } + + // 广度优先搜索 + async bfs(graph, startNode) { + this.isRunning = true; + const visited = new Set(); + const queue = [startNode]; + const nodes = this.visualizer.getGraphNodes(); + const edges = this.visualizer.getGraphEdges(); + + visited.add(startNode); + nodes[startNode].classList.add('visited'); + await sleep(this.speed); + + while (queue.length > 0 && this.isRunning) { + const node = queue.shift(); + nodes[node].classList.add('current'); + await sleep(this.speed); + nodes[node].classList.remove('current'); + + const neighbors = graph[node]; + for (const neighbor of neighbors) { + if (!visited.has(neighbor) && this.isRunning) { + // 高亮边 + const edge = this.visualizer.getEdge(node, neighbor); + if (edge) edge.classList.add('visited'); + + visited.add(neighbor); + nodes[neighbor].classList.add('visited'); + queue.push(neighbor); + await sleep(this.speed); + } + } + } + + this.isRunning = false; + return visited; + } + + // 深度优先搜索 + async dfs(graph, startNode) { + this.isRunning = true; + const visited = new Set(); + const nodes = this.visualizer.getGraphNodes(); + + const dfsRecursive = async (node) => { + if (!this.isRunning) return; + + visited.add(node); + nodes[node].classList.add('current'); + await sleep(this.speed); + nodes[node].classList.remove('current'); + nodes[node].classList.add('visited'); + + const neighbors = graph[node]; + for (const neighbor of neighbors) { + if (!visited.has(neighbor) && this.isRunning) { + const edge = this.visualizer.getEdge(node, neighbor); + if (edge) edge.classList.add('visited'); + await dfsRecursive(neighbor); + } + } + }; + + await dfsRecursive(startNode); + this.isRunning = false; + return visited; + } + + // Dijkstra最短路径 + async dijkstra(graph, startNode, endNode) { + this.isRunning = true; + const distances = {}; + const previous = {}; + const unvisited = new Set(); + const nodes = this.visualizer.getGraphNodes(); + + // 初始化 + for (const node in graph) { + distances[node] = node === startNode ? 0 : Infinity; + previous[node] = null; + unvisited.add(node); + } + + nodes[startNode].classList.add('visited'); + await sleep(this.speed); + + while (unvisited.size > 0 && this.isRunning) { + // 找到距离最小的未访问节点 + let current = null; + let minDistance = Infinity; + + for (const node of unvisited) { + if (distances[node] < minDistance) { + minDistance = distances[node]; + current = node; + } + } + + if (current === null || distances[current] === Infinity) break; + + unvisited.delete(current); + nodes[current].classList.add('current'); + await sleep(this.speed); + + if (current === endNode) { + // 找到路径,高亮显示 + let pathNode = endNode; + while (pathNode !== null) { + nodes[pathNode].classList.add('found'); + pathNode = previous[pathNode]; + await sleep(this.speed / 2); + } + this.isRunning = false; + return distances[endNode]; + } + + nodes[current].classList.remove('current'); + nodes[current].classList.add('visited'); + + // 更新邻居的距离 + for (const neighbor of graph[current]) { + if (unvisited.has(neighbor)) { + const alt = distances[current] + 1; // 假设权重为1 + if (alt < distances[neighbor]) { + distances[neighbor] = alt; + previous[neighbor] = current; + const edge = this.visualizer.getEdge(current, neighbor); + if (edge) edge.classList.add('visited'); + } + } + } + + await sleep(this.speed / 2); + } + + this.isRunning = false; + return distances[endNode]; + } +} + +// 树算法类 +class TreeAlgorithms { + constructor(visualizer) { + this.visualizer = visualizer; + this.isRunning = false; + this.speed = 700; + } + + setSpeed(speed) { + this.speed = 1200 - (speed * 110); + } + + stop() { + this.isRunning = false; + } + + // 二叉搜索树插入 + async bstInsert(root, value, isBatch = false) { + this.isRunning = true; + + const insertRecursive = async (node, val, parent = null, isLeft = false) => { + if (!this.isRunning) return node; + + if (node === null) { + // 创建新节点 + const newNode = { value: val, left: null, right: null }; + this.visualizer.addTreeNode(val, parent, isLeft); + await sleep(this.speed); + return newNode; + } + + const nodeEl = this.visualizer.getTreeNode(node.value); + if (nodeEl) nodeEl.classList.add('checking'); + await sleep(this.speed); + + if (val < node.value) { + if (nodeEl) nodeEl.classList.remove('checking'); + node.left = await insertRecursive(node.left, val, node, true); + } else if (val > node.value) { + if (nodeEl) nodeEl.classList.remove('checking'); + node.right = await insertRecursive(node.right, val, node, false); + } + + return node; + }; + + const result = await insertRecursive(root, value); + // 只有在非批量插入模式或手动停止时才设置isRunning为false + if (!isBatch) { + this.isRunning = false; + } + return result; + } + + // 批量插入(用于构建树) + async bstInsertBatch(values) { + this.isRunning = true; + let root = null; + + for (const value of values) { + if (!this.isRunning) break; + root = await this.bstInsert(root, value, true); + } + + this.isRunning = false; + return root; + } + + // 二叉搜索树搜索 + async bstSearch(root, target) { + this.isRunning = true; + + const searchRecursive = async (node) => { + if (!this.isRunning || node === null) { + this.isRunning = false; + return null; + } + + const nodeEl = this.visualizer.getTreeNode(node.value); + if (nodeEl) nodeEl.classList.add('checking'); + await sleep(this.speed); + + if (target === node.value) { + if (nodeEl) { + nodeEl.classList.remove('checking'); + nodeEl.classList.add('found'); + } + this.isRunning = false; + return node; + } + + if (nodeEl) nodeEl.classList.remove('checking'); + + if (target < node.value) { + return await searchRecursive(node.left); + } else { + return await searchRecursive(node.right); + } + }; + + const result = await searchRecursive(root); + this.isRunning = false; + return result; + } + + // 树遍历 - 中序 + async inorderTraversal(root) { + this.isRunning = true; + const result = []; + + const traverse = async (node) => { + if (!this.isRunning || node === null) return; + + await traverse(node.left); + + if (!this.isRunning) return; + const nodeEl = this.visualizer.getTreeNode(node.value); + if (nodeEl) { + nodeEl.classList.add('visited'); + await sleep(this.speed); + } + result.push(node.value); + + await traverse(node.right); + }; + + await traverse(root); + this.isRunning = false; + return result; + } +} + +// 导出算法类 +if (typeof module !== 'undefined' && module.exports) { + module.exports = { + SortingAlgorithms, + SearchAlgorithms, + GraphAlgorithms, + TreeAlgorithms, + sleep + }; +} diff --git a/002game/game.js b/002game/game.js new file mode 100644 index 0000000000..f99f743b50 --- /dev/null +++ b/002game/game.js @@ -0,0 +1,821 @@ +// 游戏主逻辑 + +// 关卡配置 +const LEVELS = [ + { + id: 1, + name: '冒泡排序', + category: '排序算法', + difficulty: 1, + algorithm: 'bubbleSort', + type: 'sorting', + description: '冒泡排序通过重复遍历列表,比较相邻元素并交换它们的位置来排序。', + timeComplexity: 'O(n²)', + spaceComplexity: 'O(1)', + task: '观察冒泡排序如何将最大的元素"冒泡"到数组末尾。' + }, + { + id: 2, + name: '快速排序', + category: '排序算法', + difficulty: 2, + algorithm: 'quickSort', + type: 'sorting', + description: '快速排序使用分治法,选择一个基准元素将数组分成两部分。', + timeComplexity: 'O(n log n)', + spaceComplexity: 'O(log n)', + task: '观察快速排序如何选择基准并分区。' + }, + { + id: 3, + name: '归并排序', + category: '排序算法', + difficulty: 2, + algorithm: 'mergeSort', + type: 'sorting', + description: '归并排序将数组分成两半,递归排序后再合并。', + timeComplexity: 'O(n log n)', + spaceComplexity: 'O(n)', + task: '观察归并排序的分治过程和合并操作。' + }, + { + id: 4, + name: '堆排序', + category: '排序算法', + difficulty: 3, + algorithm: 'heapSort', + type: 'sorting', + description: '堆排序利用堆数据结构,先将数组构建成最大堆,然后逐个取出最大元素。', + timeComplexity: 'O(n log n)', + spaceComplexity: 'O(1)', + task: '观察堆排序如何构建堆并提取最大元素。' + }, + { + id: 5, + name: '线性搜索', + category: '搜索算法', + difficulty: 1, + algorithm: 'linearSearch', + type: 'searching', + description: '线性搜索逐个检查数组中的每个元素,直到找到目标。', + timeComplexity: 'O(n)', + spaceComplexity: 'O(1)', + task: '观察线性搜索如何逐个检查元素。' + }, + { + id: 6, + name: '二分搜索', + category: '搜索算法', + difficulty: 2, + algorithm: 'binarySearch', + type: 'searching', + description: '二分搜索在有序数组中通过不断将搜索范围减半来查找目标。', + timeComplexity: 'O(log n)', + spaceComplexity: 'O(1)', + task: '观察二分搜索如何快速缩小搜索范围。' + }, + { + id: 7, + name: '广度优先搜索', + category: '图论算法', + difficulty: 2, + algorithm: 'bfs', + type: 'graph', + description: 'BFS从起始节点开始,先访问所有相邻节点,再访问下一层节点。', + timeComplexity: 'O(V + E)', + spaceComplexity: 'O(V)', + task: '观察BFS如何逐层遍历图。' + }, + { + id: 8, + name: '深度优先搜索', + category: '图论算法', + difficulty: 2, + algorithm: 'dfs', + type: 'graph', + description: 'DFS从起始节点开始,沿着一条路径尽可能深地探索,然后回溯。', + timeComplexity: 'O(V + E)', + spaceComplexity: 'O(V)', + task: '观察DFS如何深入探索图的分支。' + }, + { + id: 9, + name: 'Dijkstra最短路径', + category: '图论算法', + difficulty: 3, + algorithm: 'dijkstra', + type: 'graph', + description: 'Dijkstra算法找到从起点到其他所有节点的最短路径。', + timeComplexity: 'O((V + E) log V)', + spaceComplexity: 'O(V)', + task: '观察Dijkstra如何找到最短路径。' + }, + { + id: 10, + name: '二叉搜索树插入', + category: '数据结构', + difficulty: 2, + algorithm: 'bstInsert', + type: 'tree', + description: 'BST插入操作根据值的大小将新节点放到正确的位置。', + timeComplexity: 'O(log n)', + spaceComplexity: 'O(1)', + task: '观察BST如何保持有序性。' + }, + { + id: 11, + name: '二叉搜索树搜索', + category: '数据结构', + difficulty: 2, + algorithm: 'bstSearch', + type: 'tree', + description: 'BST搜索利用树的有序性,每次可以排除一半的节点。', + timeComplexity: 'O(log n)', + spaceComplexity: 'O(1)', + task: '观察BST搜索如何快速定位节点。' + }, + { + id: 12, + name: '树的中序遍历', + category: '数据结构', + difficulty: 2, + algorithm: 'inorderTraversal', + type: 'tree', + description: '中序遍历按照左-根-右的顺序访问BST节点,结果是有序的。', + timeComplexity: 'O(n)', + spaceComplexity: 'O(h)', + task: '观察中序遍历如何产生有序序列。' + } +]; + +// 可视化器类 +class Visualizer { + constructor(container) { + this.container = container; + this.currentData = null; + } + + clear() { + this.container.innerHTML = ''; + this.currentData = null; + } + + // 排序可视化 + createSortVisualization(array) { + this.clear(); + this.container.className = 'visualization-area'; + this.currentData = [...array]; + + const maxVal = Math.max(...array); + + array.forEach((val, index) => { + const bar = document.createElement('div'); + bar.className = 'sort-bar'; + bar.style.height = `${(val / maxVal) * 300}px`; + bar.setAttribute('data-value', val); + bar.setAttribute('data-index', index); + this.container.appendChild(bar); + }); + } + + updateBars(array) { + const bars = this.container.querySelectorAll('.sort-bar'); + const maxVal = Math.max(...array); + + bars.forEach((bar, index) => { + bar.style.height = `${(array[index] / maxVal) * 300}px`; + bar.setAttribute('data-value', array[index]); + }); + + this.currentData = [...array]; + } + + getBars() { + return this.container.querySelectorAll('.sort-bar'); + } + + // 搜索可视化 + createSearchVisualization(array) { + this.clear(); + this.container.className = 'visualization-area'; + this.currentData = [...array]; + + const searchArray = document.createElement('div'); + searchArray.className = 'search-array'; + + array.forEach((val, index) => { + const element = document.createElement('div'); + element.className = 'search-element'; + element.textContent = val; + element.setAttribute('data-index', index); + searchArray.appendChild(element); + }); + + this.container.appendChild(searchArray); + } + + getSearchElements() { + return this.container.querySelectorAll('.search-element'); + } + + // 图可视化 + createGraphVisualization(graphData) { + this.clear(); + this.container.className = 'visualization-area graph'; + this.currentData = graphData; + + const graphContainer = document.createElement('div'); + graphContainer.className = 'graph-container'; + graphContainer.style.width = '100%'; + graphContainer.style.height = '400px'; + + // 创建节点位置(圆形布局) + const nodes = Object.keys(graphData); + const centerX = 350; + const centerY = 200; + const radius = 150; + const nodePositions = {}; + + nodes.forEach((node, index) => { + const angle = (index / nodes.length) * 2 * Math.PI - Math.PI / 2; + nodePositions[node] = { + x: centerX + radius * Math.cos(angle), + y: centerY + radius * Math.sin(angle) + }; + }); + + // 绘制边 + const drawnEdges = new Set(); + nodes.forEach(node => { + graphData[node].forEach(neighbor => { + const edgeKey = [node, neighbor].sort().join('-'); + if (!drawnEdges.has(edgeKey)) { + drawnEdges.add(edgeKey); + + const edge = document.createElement('div'); + edge.className = 'graph-edge'; + edge.setAttribute('data-from', node); + edge.setAttribute('data-to', neighbor); + + const from = nodePositions[node]; + const to = nodePositions[neighbor]; + const length = Math.sqrt(Math.pow(to.x - from.x, 2) + Math.pow(to.y - from.y, 2)); + const angle = Math.atan2(to.y - from.y, to.x - from.x) * 180 / Math.PI; + + edge.style.width = `${length}px`; + edge.style.left = `${from.x}px`; + edge.style.top = `${from.y}px`; + edge.style.transform = `rotate(${angle}deg)`; + + graphContainer.appendChild(edge); + } + }); + }); + + // 绘制节点 + nodes.forEach(node => { + const nodeEl = document.createElement('div'); + nodeEl.className = 'graph-node'; + nodeEl.textContent = node; + nodeEl.setAttribute('data-node', node); + nodeEl.style.left = `${nodePositions[node].x - 25}px`; + nodeEl.style.top = `${nodePositions[node].y - 25}px`; + graphContainer.appendChild(nodeEl); + }); + + this.container.appendChild(graphContainer); + this.nodePositions = nodePositions; + } + + getGraphNodes() { + const nodes = {}; + this.container.querySelectorAll('.graph-node').forEach(node => { + nodes[node.getAttribute('data-node')] = node; + }); + return nodes; + } + + getGraphEdges() { + return this.container.querySelectorAll('.graph-edge'); + } + + getEdge(from, to) { + const edge1 = this.container.querySelector(`[data-from="${from}"][data-to="${to}"]`); + const edge2 = this.container.querySelector(`[data-from="${to}"][data-to="${from}"]`); + return edge1 || edge2; + } + + // 树可视化 + createTreeVisualization() { + this.clear(); + this.container.className = 'visualization-area'; + this.currentData = { root: null, nodes: {} }; + + const treeContainer = document.createElement('div'); + treeContainer.className = 'tree-container'; + treeContainer.id = 'tree-root'; + this.container.appendChild(treeContainer); + } + + addTreeNode(value, parent = null, isLeft = false) { + const treeRoot = document.getElementById('tree-root'); + + if (parent === null) { + // 根节点 + treeRoot.innerHTML = ''; + const level = document.createElement('div'); + level.className = 'tree-level'; + + const node = document.createElement('div'); + node.className = 'tree-node inserting'; + node.textContent = value; + node.setAttribute('data-value', value); + + level.appendChild(node); + treeRoot.appendChild(level); + } else { + // 查找父节点并添加子节点 + const parentValue = parent.value; + const parentNode = treeRoot.querySelector(`[data-value="${parentValue}"]`); + + if (parentNode) { + let level = parentNode.closest('.tree-level'); + let nextLevel = level.nextElementSibling; + + if (!nextLevel) { + nextLevel = document.createElement('div'); + nextLevel.className = 'tree-level'; + treeRoot.appendChild(nextLevel); + } + + const node = document.createElement('div'); + node.className = 'tree-node inserting'; + node.textContent = value; + node.setAttribute('data-value', value); + + nextLevel.appendChild(node); + + setTimeout(() => { + node.classList.remove('inserting'); + }, 500); + } + } + } + + getTreeNode(value) { + return document.querySelector(`.tree-node[data-value="${value}"]`); + } +} + +// 游戏主类 +class Game { + constructor() { + this.currentLevel = null; + this.score = 0; + this.isPlaying = false; + this.visualizer = null; + this.algorithmInstance = null; + this.currentAlgorithm = null; + this.startTime = null; + this.completedLevels = new Set(); + + this.init(); + } + + init() { + this.visualizer = new Visualizer(document.getElementById('visualization-area')); + this.generateLevelGrid(); + + // 加载保存的进度 + const saved = localStorage.getItem('algorithmGameProgress'); + if (saved) { + const progress = JSON.parse(saved); + this.score = progress.score || 0; + this.completedLevels = new Set(progress.completedLevels || []); + } + + this.updateScore(); + } + + // 屏幕切换 + showScreen(screenId) { + document.querySelectorAll('.screen').forEach(screen => { + screen.classList.remove('active'); + }); + document.getElementById(screenId).classList.add('active'); + } + + showStart() { + this.showScreen('start-screen'); + } + + start() { + this.showLevels(); + } + + showLevels() { + this.generateLevelGrid(); + this.showScreen('level-screen'); + } + + showHelp() { + this.showScreen('help-screen'); + } + + // 生成关卡网格 + generateLevelGrid() { + const grid = document.getElementById('level-grid'); + grid.innerHTML = ''; + + LEVELS.forEach((level, index) => { + const card = document.createElement('div'); + card.className = 'level-card'; + + // 检查是否锁定 + if (index > 0 && !this.completedLevels.has(LEVELS[index - 1].id)) { + card.classList.add('locked'); + } + + // 检查是否已完成 + if (this.completedLevels.has(level.id)) { + card.classList.add('completed'); + } + + // 生成难度星星 + const stars = '★'.repeat(level.difficulty) + '☆'.repeat(3 - level.difficulty); + + card.innerHTML = ` +
关卡 ${level.id}
+
${level.name}
+
${level.category}
+
+ ${stars.split('').map(star => + `${star}` + ).join('')} +
+ `; + + if (!card.classList.contains('locked')) { + card.onclick = () => this.loadLevel(level); + } + + grid.appendChild(card); + }); + } + + // 加载关卡 + loadLevel(level) { + this.currentLevel = level; + this.isPlaying = false; + this.startTime = Date.now(); + + // 更新UI + document.getElementById('level-title').textContent = `关卡 ${level.id}: ${level.name}`; + document.getElementById('algorithm-name').textContent = level.name; + document.getElementById('algorithm-desc').textContent = level.description; + document.getElementById('time-complexity').textContent = `时间复杂度: ${level.timeComplexity}`; + document.getElementById('space-complexity').textContent = `空间复杂度: ${level.spaceComplexity}`; + document.getElementById('game-task').innerHTML = ` +

🎯 任务

+

${level.task}

+ `; + + // 初始化可视化 + this.visualizer.clear(); + this.initializeAlgorithm(level); + + // 生成初始数据 + this.generateNew(); + + this.showScreen('game-screen'); + } + + // 初始化算法 + initializeAlgorithm(level) { + // 停止之前的算法 + if (this.algorithmInstance) { + this.algorithmInstance.stop(); + } + + const speed = document.getElementById('speed-slider').value; + + switch (level.type) { + case 'sorting': + this.algorithmInstance = new SortingAlgorithms(this.visualizer); + this.currentAlgorithm = () => { + const array = this.generateRandomArray(15, 100); + this.visualizer.createSortVisualization(array); + return this.algorithmInstance[level.algorithm](array); + }; + break; + + case 'searching': + this.algorithmInstance = new SearchAlgorithms(this.visualizer); + this.currentAlgorithm = () => { + const array = this.generateSortedArray(15, 100); + const target = array[Math.floor(Math.random() * array.length)]; + this.visualizer.createSearchVisualization(array); + document.getElementById('game-task').innerHTML += ` +

🔍 搜索目标: ${target}

+ `; + return this.algorithmInstance[level.algorithm](array, target); + }; + break; + + case 'graph': + this.algorithmInstance = new GraphAlgorithms(this.visualizer); + this.currentAlgorithm = () => { + const graph = this.generateRandomGraph(); + this.visualizer.createGraphVisualization(graph); + const startNode = Object.keys(graph)[0]; + + if (level.algorithm === 'dijkstra') { + const endNode = Object.keys(graph)[Object.keys(graph).length - 1]; + return this.algorithmInstance[level.algorithm](graph, startNode, endNode); + } + return this.algorithmInstance[level.algorithm](graph, startNode); + }; + break; + + case 'tree': + this.algorithmInstance = new TreeAlgorithms(this.visualizer); + this.currentAlgorithm = async () => { + this.visualizer.createTreeVisualization(); + const values = this.generateRandomArray(7, 99); + let root = null; + + if (level.algorithm === 'bstInsert') { + // 使用批量插入,完成后isRunning会自动设为false + root = await this.algorithmInstance.bstInsertBatch(values); + return root; + } else if (level.algorithm === 'bstSearch') { + // 先构建树(使用临时实例,不影响当前算法实例的状态) + const buildAlgo = new TreeAlgorithms(this.visualizer); + root = await buildAlgo.bstInsertBatch(values); + + const target = values[Math.floor(Math.random() * values.length)]; + document.getElementById('game-task').innerHTML += ` +

🔍 搜索目标: ${target}

+ `; + return this.algorithmInstance.bstSearch(root, target); + } else if (level.algorithm === 'inorderTraversal') { + // 先构建树 + const buildAlgo = new TreeAlgorithms(this.visualizer); + root = await buildAlgo.bstInsertBatch(values); + return this.algorithmInstance.inorderTraversal(root); + } + }; + break; + } + + this.algorithmInstance.setSpeed(speed); + } + + // 生成随机数组 + generateRandomArray(size, max) { + const array = []; + for (let i = 0; i < size; i++) { + array.push(Math.floor(Math.random() * max) + 1); + } + return array; + } + + // 生成有序数组 + generateSortedArray(size, max) { + const array = this.generateRandomArray(size, max); + return array.sort((a, b) => a - b); + } + + // 生成随机图 + generateRandomGraph() { + const nodes = ['A', 'B', 'C', 'D', 'E', 'F']; + const graph = {}; + + nodes.forEach(node => { + graph[node] = []; + }); + + // 随机添加边 + nodes.forEach((node, i) => { + const numEdges = Math.floor(Math.random() * 2) + 1; + for (let j = 0; j < numEdges; j++) { + const target = nodes[Math.floor(Math.random() * nodes.length)]; + if (target !== node && !graph[node].includes(target)) { + graph[node].push(target); + if (!graph[target].includes(node)) { + graph[target].push(node); + } + } + } + }); + + return graph; + } + + // 控制方法 + togglePlay() { + const btn = document.getElementById('btn-play'); + + if (this.isPlaying) { + this.isPlaying = false; + btn.textContent = '▶ 播放'; + if (this.algorithmInstance) { + this.algorithmInstance.stop(); + } + } else { + this.isPlaying = true; + btn.textContent = '⏸ 暂停'; + this.runAlgorithm(); + } + } + + async runAlgorithm() { + if (this.currentAlgorithm) { + this.algorithmCompleted = false; + await this.currentAlgorithm(); + + // 等待算法真正完成(检查isRunning状态) + if (this.algorithmInstance) { + await this.waitForAlgorithmComplete(); + } + + if (!this.algorithmCompleted) { + this.algorithmCompleted = true; + this.isPlaying = false; + document.getElementById('btn-play').textContent = '▶ 播放'; + this.completeLevel(); + } + } + } + + async waitForAlgorithmComplete() { + // 等待算法实例的isRunning变为false + return new Promise(resolve => { + const checkInterval = setInterval(() => { + // 检查算法实例是否存在且isRunning为false + if (this.algorithmInstance && !this.algorithmInstance.isRunning) { + clearInterval(checkInterval); + resolve(); + } + }, 100); + // 超时处理(最多等60秒) + setTimeout(() => { + clearInterval(checkInterval); + resolve(); + }, 60000); + }); + } + + step() { + // 单步执行(简化版本,实际实现需要更复杂的逻辑) + if (!this.isPlaying) { + this.togglePlay(); + } + } + + reset() { + this.isPlaying = false; + document.getElementById('btn-play').textContent = '▶ 播放'; + if (this.algorithmInstance) { + this.algorithmInstance.stop(); + } + this.initializeAlgorithm(this.currentLevel); + } + + generateNew() { + // 停止当前算法 + this.isPlaying = false; + document.getElementById('btn-play').textContent = '▶ 播放'; + if (this.algorithmInstance) { + this.algorithmInstance.stop(); + } + // 重新生成数据但不重新初始化整个算法 + if (this.currentAlgorithm && this.currentLevel) { + const speed = document.getElementById('speed-slider').value; + + switch (this.currentLevel.type) { + case 'sorting': + const array = this.generateRandomArray(15, 100); + this.visualizer.createSortVisualization(array); + this.currentAlgorithm = () => { + return this.algorithmInstance[this.currentLevel.algorithm](array); + }; + break; + + case 'searching': + const searchArray = this.generateSortedArray(15, 100); + const target = searchArray[Math.floor(Math.random() * searchArray.length)]; + this.visualizer.createSearchVisualization(searchArray); + document.getElementById('game-task').innerHTML = ` +

🎯 任务

+

${this.currentLevel.task}

+

🔍 搜索目标: ${target}

+ `; + this.currentAlgorithm = () => { + return this.algorithmInstance[this.currentLevel.algorithm](searchArray, target); + }; + break; + + case 'graph': + const graph = this.generateRandomGraph(); + this.visualizer.createGraphVisualization(graph); + const startNode = Object.keys(graph)[0]; + this.currentAlgorithm = () => { + if (this.currentLevel.algorithm === 'dijkstra') { + const endNode = Object.keys(graph)[Object.keys(graph).length - 1]; + return this.algorithmInstance[this.currentLevel.algorithm](graph, startNode, endNode); + } + return this.algorithmInstance[this.currentLevel.algorithm](graph, startNode); + }; + break; + + case 'tree': + this.visualizer.createTreeVisualization(); + const values = this.generateRandomArray(7, 99); + if (this.currentLevel.algorithm === 'bstInsert') { + this.currentAlgorithm = async () => { + return this.algorithmInstance.bstInsertBatch(values); + }; + } else if (this.currentLevel.algorithm === 'bstSearch') { + const buildAlgo = new TreeAlgorithms(this.visualizer); + buildAlgo.bstInsertBatch(values).then(root => { + const target = values[Math.floor(Math.random() * values.length)]; + document.getElementById('game-task').innerHTML = ` +

🎯 任务

+

${this.currentLevel.task}

+

🔍 搜索目标: ${target}

+ `; + this.currentAlgorithm = () => { + return this.algorithmInstance.bstSearch(root, target); + }; + }); + } else if (this.currentLevel.algorithm === 'inorderTraversal') { + const buildAlgo = new TreeAlgorithms(this.visualizer); + buildAlgo.bstInsertBatch(values).then(root => { + this.currentAlgorithm = () => { + return this.algorithmInstance.inorderTraversal(root); + }; + }); + } + break; + } + + this.algorithmInstance.setSpeed(speed); + } + } + + updateSpeed(value) { + if (this.algorithmInstance) { + this.algorithmInstance.setSpeed(parseInt(value)); + } + } + + // 完成关卡 + completeLevel() { + if (!this.completedLevels.has(this.currentLevel.id)) { + this.completedLevels.add(this.currentLevel.id); + this.score += 100 * this.currentLevel.difficulty; + this.updateScore(); + this.saveProgress(); + } + + const timeElapsed = Math.floor((Date.now() - this.startTime) / 1000); + document.getElementById('complete-score').textContent = this.score; + document.getElementById('complete-time').textContent = `${timeElapsed}s`; + + setTimeout(() => { + this.showScreen('complete-screen'); + }, 1000); + } + + nextLevel() { + const currentIndex = LEVELS.findIndex(l => l.id === this.currentLevel.id); + if (currentIndex < LEVELS.length - 1) { + this.loadLevel(LEVELS[currentIndex + 1]); + } else { + this.showLevels(); + } + } + + restartLevel() { + this.loadLevel(this.currentLevel); + } + + updateScore() { + document.getElementById('score').textContent = this.score; + } + + saveProgress() { + const progress = { + score: this.score, + completedLevels: Array.from(this.completedLevels) + }; + localStorage.setItem('algorithmGameProgress', JSON.stringify(progress)); + } +} + +// 初始化游戏 +let game; +document.addEventListener('DOMContentLoaded', () => { + game = new Game(); +}); diff --git a/002game/index.html b/002game/index.html new file mode 100644 index 0000000000..531d1a14a2 --- /dev/null +++ b/002game/index.html @@ -0,0 +1,147 @@ + + + + + + 算法探险家 - Algorithm Explorer + + + +
+ +
+
+

🔍 算法探险家

+

Algorithm Explorer

+

通过可视化游戏学习经典算法

+
+ +
+
📊 排序算法
+
🔎 搜索算法
+
🌲 图论算法
+
🧩 动态规划
+
📚 数据结构
+
+
+ + +
+

选择关卡

+
+ +
+ +
+ + +
+
+ +

关卡标题

+
得分: 0
+
+
+
+

算法名称

+

算法描述

+
+ 时间复杂度: O(n²) + 空间复杂度: O(1) +
+
+
+ +
+
+
+ + + + +
+
+ + +
+
+
+ +
+
+
+ + +
+

游戏说明

+
+
+

🎯 游戏目标

+

通过可视化的方式学习和理解各种经典算法。每个关卡都会展示一个算法的执行过程,帮助你直观地理解算法的工作原理。

+
+
+

🎮 操作方法

+
    +
  • 播放/暂停: 控制算法的自动执行
  • +
  • 单步: 逐步查看算法的每一步
  • +
  • 重置: 重新开始当前关卡
  • +
  • 新数据: 生成新的随机数据
  • +
  • 速度滑块: 调整动画播放速度
  • +
+
+
+

📚 包含的算法

+
+
+

排序算法

+ 冒泡排序、快速排序、归并排序、堆排序 +
+
+

搜索算法

+ 线性搜索、二分搜索、广度优先搜索、深度优先搜索 +
+
+

图论算法

+ Dijkstra最短路径、Prim最小生成树 +
+
+

数据结构

+ 二叉搜索树、堆、链表操作 +
+
+
+
+ +
+ + +
+
+

🎉 恭喜完成!

+

你已完成本关卡!

+
+
+ 得分 + 0 +
+
+ 用时 + 0s +
+
+
+
+ + + +
+
+
+ + + + + diff --git a/002game/styles.css b/002game/styles.css new file mode 100644 index 0000000000..3ed04eb621 --- /dev/null +++ b/002game/styles.css @@ -0,0 +1,819 @@ +/* 基础样式重置 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --primary-color: #6366f1; + --primary-dark: #4f46e5; + --secondary-color: #8b5cf6; + --accent-color: #ec4899; + --success-color: #10b981; + --warning-color: #f59e0b; + --error-color: #ef4444; + --bg-dark: #0f172a; + --bg-card: #1e293b; + --bg-light: #334155; + --text-primary: #f8fafc; + --text-secondary: #94a3b8; + --border-color: #475569; + --shadow: 0 10px 40px rgba(0, 0, 0, 0.3); + --shadow-glow: 0 0 30px rgba(99, 102, 241, 0.3); +} + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background: linear-gradient(135deg, var(--bg-dark) 0%, #1a1a2e 50%, #16213e 100%); + min-height: 100vh; + color: var(--text-primary); + overflow-x: hidden; +} + +#game-container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + min-height: 100vh; +} + +/* 屏幕管理 */ +.screen { + display: none; + animation: fadeIn 0.5s ease; +} + +.screen.active { + display: block; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); } +} + +/* 开始界面 */ +#start-screen { + text-align: center; + padding: 60px 20px; +} + +.title-container { + margin-bottom: 50px; +} + +.game-title { + font-size: 4rem; + font-weight: 800; + background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + margin-bottom: 10px; + text-shadow: 0 0 60px rgba(99, 102, 241, 0.5); +} + +.subtitle { + font-size: 1.5rem; + color: var(--text-secondary); + margin-bottom: 15px; + letter-spacing: 3px; +} + +.description { + font-size: 1.2rem; + color: var(--text-secondary); +} + +.menu-buttons { + display: flex; + gap: 20px; + justify-content: center; + margin-bottom: 50px; + flex-wrap: wrap; +} + +.btn { + padding: 15px 40px; + font-size: 1.1rem; + font-weight: 600; + border: none; + border-radius: 12px; + cursor: pointer; + transition: all 0.3s ease; + text-transform: uppercase; + letter-spacing: 1px; +} + +.btn-primary { + background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); + color: white; + box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4); +} + +.btn-primary:hover { + transform: translateY(-3px); + box-shadow: 0 8px 25px rgba(99, 102, 241, 0.5); +} + +.btn-secondary { + background: var(--bg-card); + color: var(--text-primary); + border: 2px solid var(--border-color); +} + +.btn-secondary:hover { + background: var(--bg-light); + border-color: var(--primary-color); +} + +.btn-small { + padding: 8px 20px; + font-size: 0.9rem; +} + +.btn-back { + margin-top: 30px; + background: var(--bg-card); + color: var(--text-primary); + border: 2px solid var(--border-color); +} + +.btn-control { + padding: 10px 20px; + font-size: 0.9rem; + background: var(--bg-card); + color: var(--text-primary); + border: 1px solid var(--border-color); +} + +.btn-control:hover { + background: var(--primary-color); + border-color: var(--primary-color); +} + +.algorithm-categories { + display: flex; + gap: 15px; + justify-content: center; + flex-wrap: wrap; +} + +.category-tag { + padding: 10px 20px; + background: var(--bg-card); + border-radius: 25px; + border: 1px solid var(--border-color); + font-size: 0.95rem; + transition: all 0.3s ease; +} + +.category-tag:hover { + border-color: var(--primary-color); + transform: translateY(-2px); +} + +/* 关卡选择界面 */ +#level-screen { + padding: 40px 20px; +} + +#level-screen h2 { + text-align: center; + font-size: 2.5rem; + margin-bottom: 40px; + background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.level-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 25px; + margin-bottom: 40px; +} + +.level-card { + background: var(--bg-card); + border-radius: 16px; + padding: 25px; + border: 2px solid var(--border-color); + cursor: pointer; + transition: all 0.3s ease; + position: relative; + overflow: hidden; +} + +.level-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 4px; + background: linear-gradient(90deg, var(--primary-color), var(--accent-color)); + transform: scaleX(0); + transition: transform 0.3s ease; +} + +.level-card:hover::before { + transform: scaleX(1); +} + +.level-card:hover { + transform: translateY(-5px); + border-color: var(--primary-color); + box-shadow: var(--shadow-glow); +} + +.level-card.locked { + opacity: 0.5; + cursor: not-allowed; +} + +.level-card.locked:hover { + transform: none; + border-color: var(--border-color); + box-shadow: none; +} + +.level-card.completed { + border-color: var(--success-color); +} + +.level-card.completed::after { + content: '✓'; + position: absolute; + top: 15px; + right: 15px; + width: 30px; + height: 30px; + background: var(--success-color); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; +} + +.level-number { + font-size: 0.9rem; + color: var(--text-secondary); + margin-bottom: 10px; +} + +.level-name { + font-size: 1.3rem; + font-weight: 700; + margin-bottom: 10px; +} + +.level-category { + display: inline-block; + padding: 5px 12px; + background: var(--bg-light); + border-radius: 15px; + font-size: 0.8rem; + color: var(--text-secondary); +} + +.level-difficulty { + margin-top: 15px; + display: flex; + gap: 5px; +} + +.difficulty-star { + color: var(--warning-color); +} + +.difficulty-star.empty { + color: var(--bg-light); +} + +/* 游戏界面 */ +#game-screen { + padding: 20px; +} + +.game-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 30px; + padding: 20px; + background: var(--bg-card); + border-radius: 12px; + border: 1px solid var(--border-color); +} + +.game-header h3 { + font-size: 1.5rem; + background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.score-display { + font-size: 1.2rem; + font-weight: 600; + color: var(--success-color); +} + +.game-content { + background: var(--bg-card); + border-radius: 16px; + padding: 30px; + border: 1px solid var(--border-color); +} + +.algorithm-info { + margin-bottom: 30px; + padding-bottom: 20px; + border-bottom: 1px solid var(--border-color); +} + +.algorithm-info h4 { + font-size: 1.5rem; + margin-bottom: 10px; + color: var(--primary-color); +} + +.algorithm-info p { + color: var(--text-secondary); + line-height: 1.6; + margin-bottom: 15px; +} + +.complexity-info { + display: flex; + gap: 20px; + flex-wrap: wrap; +} + +.complexity { + padding: 8px 16px; + background: var(--bg-light); + border-radius: 8px; + font-size: 0.9rem; + font-family: 'Courier New', monospace; +} + +/* 可视化区域 */ +.visualization-area { + min-height: 400px; + background: var(--bg-dark); + border-radius: 12px; + padding: 30px; + margin-bottom: 30px; + display: flex; + align-items: flex-end; + justify-content: center; + gap: 5px; + position: relative; + overflow: hidden; +} + +.visualization-area.graph { + align-items: center; +} + +/* 排序可视化 */ +.sort-bar { + width: 40px; + background: linear-gradient(180deg, var(--primary-color), var(--secondary-color)); + border-radius: 4px 4px 0 0; + transition: all 0.3s ease; + position: relative; +} + +.sort-bar.comparing { + background: linear-gradient(180deg, var(--warning-color), #f97316); + transform: scaleY(1.05); +} + +.sort-bar.swapping { + background: linear-gradient(180deg, var(--error-color), #dc2626); +} + +.sort-bar.sorted { + background: linear-gradient(180deg, var(--success-color), #059669); +} + +.sort-bar::after { + content: attr(data-value); + position: absolute; + bottom: -25px; + left: 50%; + transform: translateX(-50%); + font-size: 0.8rem; + color: var(--text-secondary); +} + +/* 搜索可视化 */ +.search-array { + display: flex; + gap: 10px; + align-items: center; +} + +.search-element { + width: 60px; + height: 60px; + background: var(--bg-light); + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.2rem; + font-weight: 600; + transition: all 0.3s ease; + border: 2px solid transparent; +} + +.search-element.checking { + background: var(--warning-color); + border-color: var(--warning-color); + transform: scale(1.1); +} + +.search-element.found { + background: var(--success-color); + border-color: var(--success-color); + transform: scale(1.15); + box-shadow: 0 0 20px rgba(16, 185, 129, 0.5); +} + +.search-element.not-found { + background: var(--error-color); + opacity: 0.5; +} + +/* 图可视化 */ +.graph-container { + width: 100%; + height: 100%; + position: relative; +} + +.graph-node { + width: 50px; + height: 50px; + background: var(--bg-light); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: 600; + position: absolute; + border: 3px solid var(--border-color); + transition: all 0.3s ease; +} + +.graph-node.visited { + background: var(--primary-color); + border-color: var(--primary-color); + box-shadow: 0 0 20px rgba(99, 102, 241, 0.5); +} + +.graph-node.current { + background: var(--warning-color); + border-color: var(--warning-color); + transform: scale(1.2); +} + +.graph-edge { + position: absolute; + background: var(--border-color); + height: 2px; + transform-origin: left center; + transition: all 0.3s ease; +} + +.graph-edge.visited { + background: var(--primary-color); + height: 3px; +} + +/* 树可视化 */ +.tree-container { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; +} + +.tree-level { + display: flex; + gap: 40px; + margin: 20px 0; +} + +.tree-node { + width: 50px; + height: 50px; + background: var(--bg-light); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: 600; + border: 3px solid var(--border-color); + transition: all 0.3s ease; + position: relative; +} + +.tree-node.visited { + background: var(--primary-color); + border-color: var(--primary-color); +} + +.tree-node.inserting { + background: var(--success-color); + border-color: var(--success-color); + animation: pulse 0.5s ease; +} + +@keyframes pulse { + 0%, 100% { transform: scale(1); } + 50% { transform: scale(1.2); } +} + +/* 控制区域 */ +.controls { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 20px; + padding: 20px; + background: var(--bg-dark); + border-radius: 12px; + margin-bottom: 20px; +} + +.control-buttons { + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +.speed-control { + display: flex; + align-items: center; + gap: 10px; +} + +.speed-control label { + color: var(--text-secondary); +} + +.speed-control input[type="range"] { + width: 150px; + height: 6px; + -webkit-appearance: none; + background: var(--bg-light); + border-radius: 3px; + outline: none; +} + +.speed-control input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + width: 18px; + height: 18px; + background: var(--primary-color); + border-radius: 50%; + cursor: pointer; +} + +/* 游戏任务 */ +.game-task { + padding: 20px; + background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(236, 72, 153, 0.1)); + border-radius: 12px; + border: 1px solid var(--border-color); +} + +.game-task h4 { + color: var(--primary-color); + margin-bottom: 10px; +} + +.game-task p { + color: var(--text-secondary); +} + +/* 帮助界面 */ +#help-screen { + padding: 40px 20px; + max-width: 900px; + margin: 0 auto; +} + +#help-screen h2 { + text-align: center; + font-size: 2.5rem; + margin-bottom: 40px; + background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.help-content { + margin-bottom: 40px; +} + +.help-section { + background: var(--bg-card); + border-radius: 16px; + padding: 30px; + margin-bottom: 25px; + border: 1px solid var(--border-color); +} + +.help-section h3 { + color: var(--primary-color); + margin-bottom: 15px; + font-size: 1.3rem; +} + +.help-section p { + color: var(--text-secondary); + line-height: 1.7; +} + +.help-section ul { + list-style: none; + padding-left: 0; +} + +.help-section li { + color: var(--text-secondary); + padding: 10px 0; + padding-left: 25px; + position: relative; + border-bottom: 1px solid var(--bg-light); +} + +.help-section li:last-child { + border-bottom: none; +} + +.help-section li::before { + content: '▸'; + position: absolute; + left: 0; + color: var(--primary-color); +} + +.algorithm-list { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 20px; +} + +.algo-group { + background: var(--bg-dark); + padding: 20px; + border-radius: 12px; +} + +.algo-group h4 { + color: var(--accent-color); + margin-bottom: 10px; + font-size: 1rem; +} + +.algo-group span { + color: var(--text-secondary); + font-size: 0.9rem; +} + +/* 完成界面 */ +#complete-screen { + text-align: center; + padding: 60px 20px; +} + +.complete-message { + margin-bottom: 40px; +} + +.complete-message h2 { + font-size: 3rem; + margin-bottom: 20px; + background: linear-gradient(135deg, var(--success-color), var(--primary-color)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.complete-message p { + font-size: 1.2rem; + color: var(--text-secondary); + margin-bottom: 30px; +} + +.complete-stats { + display: flex; + justify-content: center; + gap: 60px; + margin-bottom: 40px; +} + +.stat { + display: flex; + flex-direction: column; + align-items: center; +} + +.stat-label { + color: var(--text-secondary); + font-size: 1rem; + margin-bottom: 10px; +} + +.stat-value { + font-size: 2.5rem; + font-weight: 700; + color: var(--primary-color); +} + +.complete-buttons { + display: flex; + gap: 20px; + justify-content: center; + flex-wrap: wrap; +} + +/* 响应式设计 */ +@media (max-width: 768px) { + .game-title { + font-size: 2.5rem; + } + + .level-grid { + grid-template-columns: 1fr; + } + + .game-header { + flex-direction: column; + gap: 15px; + text-align: center; + } + + .controls { + flex-direction: column; + align-items: stretch; + } + + .control-buttons { + justify-content: center; + } + + .visualization-area { + min-height: 300px; + padding: 15px; + } + + .sort-bar { + width: 25px; + } + + .search-element { + width: 45px; + height: 45px; + font-size: 1rem; + } + + .complete-stats { + flex-direction: column; + gap: 30px; + } +} + +/* 动画效果 */ +@keyframes slideIn { + from { + opacity: 0; + transform: translateX(-20px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes bounce { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-10px); } +} + +.animate-bounce { + animation: bounce 0.5s ease; +} From fdf32f0eb3fe1341c9813fbda855aadcf66c1ba6 Mon Sep 17 00:00:00 2001 From: Mr0Tom Date: Tue, 17 Mar 2026 21:42:40 +0800 Subject: [PATCH 3/3] 001 --- 002game/algorithms.js | 661 ---------------------------------- 002game/game.js | 821 ------------------------------------------ 002game/index.html | 147 -------- 002game/styles.css | 819 ----------------------------------------- 4 files changed, 2448 deletions(-) delete mode 100644 002game/algorithms.js delete mode 100644 002game/game.js delete mode 100644 002game/index.html delete mode 100644 002game/styles.css diff --git a/002game/algorithms.js b/002game/algorithms.js deleted file mode 100644 index 35d6f79dab..0000000000 --- a/002game/algorithms.js +++ /dev/null @@ -1,661 +0,0 @@ -// 算法实现和可视化逻辑 - -// 工具函数 -const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); - -// 排序算法类 -class SortingAlgorithms { - constructor(visualizer) { - this.visualizer = visualizer; - this.isRunning = false; - this.speed = 500; - } - - setSpeed(speed) { - this.speed = 1100 - (speed * 100); - } - - stop() { - this.isRunning = false; - } - - // 冒泡排序 - async bubbleSort(array) { - this.isRunning = true; - const n = array.length; - const bars = this.visualizer.getBars(); - - for (let i = 0; i < n - 1 && this.isRunning; i++) { - let swapped = false; - for (let j = 0; j < n - i - 1 && this.isRunning; j++) { - // 高亮比较的元素 - bars[j].classList.add('comparing'); - bars[j + 1].classList.add('comparing'); - await sleep(this.speed); - - if (array[j] > array[j + 1]) { - // 交换 - bars[j].classList.add('swapping'); - bars[j + 1].classList.add('swapping'); - - [array[j], array[j + 1]] = [array[j + 1], array[j]]; - this.visualizer.updateBars(array); - - await sleep(this.speed); - bars[j].classList.remove('swapping'); - bars[j + 1].classList.remove('swapping'); - swapped = true; - } - - bars[j].classList.remove('comparing'); - bars[j + 1].classList.remove('comparing'); - } - - // 标记已排序的元素 - bars[n - i - 1].classList.add('sorted'); - - if (!swapped) break; - } - - // 标记第一个元素为已排序 - if (this.isRunning && bars[0]) { - bars[0].classList.add('sorted'); - } - - this.isRunning = false; - return array; - } - - // 快速排序 - async quickSort(array, low = 0, high = array.length - 1) { - // 只在初始调用时设置isRunning - if (low === 0 && high === array.length - 1) { - this.isRunning = true; - } - - if (!this.isRunning) return array; - - if (low < high) { - const pi = await this.partition(array, low, high); - await this.quickSort(array, low, pi - 1); - await this.quickSort(array, pi + 1, high); - } - - // 标记所有元素为已排序(当整个排序完成时) - if (low === 0 && high === array.length - 1) { - const bars = this.visualizer.getBars(); - for (let i = 0; i < array.length; i++) { - if (bars[i]) bars[i].classList.add('sorted'); - } - this.isRunning = false; - } - - return array; - } - - async partition(array, low, high) { - const bars = this.visualizer.getBars(); - const pivot = array[high]; - bars[high].classList.add('comparing'); - - let i = low - 1; - - for (let j = low; j < high && this.isRunning; j++) { - bars[j].classList.add('comparing'); - await sleep(this.speed); - - if (array[j] < pivot) { - i++; - [array[i], array[j]] = [array[j], array[i]]; - this.visualizer.updateBars(array); - - bars[i].classList.add('swapping'); - bars[j].classList.add('swapping'); - await sleep(this.speed); - bars[i].classList.remove('swapping'); - bars[j].classList.remove('swapping'); - } - - bars[j].classList.remove('comparing'); - } - - [array[i + 1], array[high]] = [array[high], array[i + 1]]; - this.visualizer.updateBars(array); - bars[high].classList.remove('comparing'); - bars[i + 1].classList.add('sorted'); - - return i + 1; - } - - // 归并排序 - async mergeSort(array, left = 0, right = array.length - 1) { - // 只在初始调用时设置isRunning - if (left === 0 && right === array.length - 1) { - this.isRunning = true; - } - - if (!this.isRunning) return array; - - if (left < right) { - const mid = Math.floor((left + right) / 2); - await this.mergeSort(array, left, mid); - await this.mergeSort(array, mid + 1, right); - await this.merge(array, left, mid, right); - } - - // 标记所有元素为已排序(当整个排序完成时) - if (left === 0 && right === array.length - 1) { - const bars = this.visualizer.getBars(); - for (let i = 0; i < array.length; i++) { - if (bars[i]) bars[i].classList.add('sorted'); - } - this.isRunning = false; - } - - return array; - } - - async merge(array, left, mid, right) { - const bars = this.visualizer.getBars(); - const n1 = mid - left + 1; - const n2 = right - mid; - - const L = array.slice(left, mid + 1); - const R = array.slice(mid + 1, right + 1); - - let i = 0, j = 0, k = left; - - while (i < n1 && j < n2 && this.isRunning) { - bars[k].classList.add('comparing'); - await sleep(this.speed); - - if (L[i] <= R[j]) { - array[k] = L[i]; - i++; - } else { - array[k] = R[j]; - j++; - } - - this.visualizer.updateBars(array); - bars[k].classList.remove('comparing'); - bars[k].classList.add('sorted'); - k++; - } - - while (i < n1 && this.isRunning) { - array[k] = L[i]; - this.visualizer.updateBars(array); - bars[k].classList.add('sorted'); - i++; - k++; - await sleep(this.speed / 2); - } - - while (j < n2 && this.isRunning) { - array[k] = R[j]; - this.visualizer.updateBars(array); - bars[k].classList.add('sorted'); - j++; - k++; - await sleep(this.speed / 2); - } - } - - // 堆排序 - async heapSort(array) { - this.isRunning = true; - const n = array.length; - - // 构建最大堆 - for (let i = Math.floor(n / 2) - 1; i >= 0 && this.isRunning; i--) { - await this.heapify(array, n, i); - } - - // 一个个从堆顶取出元素 - for (let i = n - 1; i > 0 && this.isRunning; i--) { - const bars = this.visualizer.getBars(); - bars[0].classList.add('swapping'); - bars[i].classList.add('swapping'); - - [array[0], array[i]] = [array[i], array[0]]; - this.visualizer.updateBars(array); - await sleep(this.speed); - - bars[0].classList.remove('swapping'); - bars[i].classList.remove('swapping'); - bars[i].classList.add('sorted'); - - await this.heapify(array, i, 0); - } - - if (this.isRunning) { - const bars = this.visualizer.getBars(); - bars[0].classList.add('sorted'); - } - - this.isRunning = false; - return array; - } - - async heapify(array, n, i) { - const bars = this.visualizer.getBars(); - let largest = i; - const left = 2 * i + 1; - const right = 2 * i + 2; - - bars[i].classList.add('comparing'); - await sleep(this.speed / 2); - - if (left < n && array[left] > array[largest]) { - largest = left; - } - - if (right < n && array[right] > array[largest]) { - largest = right; - } - - if (largest !== i) { - bars[largest].classList.add('swapping'); - - [array[i], array[largest]] = [array[largest], array[i]]; - this.visualizer.updateBars(array); - await sleep(this.speed); - - bars[largest].classList.remove('swapping'); - bars[i].classList.remove('comparing'); - - await this.heapify(array, n, largest); - } else { - bars[i].classList.remove('comparing'); - } - } -} - -// 搜索算法类 -class SearchAlgorithms { - constructor(visualizer) { - this.visualizer = visualizer; - this.isRunning = false; - this.speed = 800; - } - - setSpeed(speed) { - this.speed = 1500 - (speed * 130); - } - - stop() { - this.isRunning = false; - } - - // 线性搜索 - async linearSearch(array, target) { - this.isRunning = true; - const elements = this.visualizer.getSearchElements(); - - for (let i = 0; i < array.length && this.isRunning; i++) { - elements[i].classList.add('checking'); - await sleep(this.speed); - - if (array[i] === target) { - elements[i].classList.remove('checking'); - elements[i].classList.add('found'); - this.isRunning = false; - return i; - } - - elements[i].classList.remove('checking'); - elements[i].classList.add('not-found'); - } - - this.isRunning = false; - return -1; - } - - // 二分搜索 - async binarySearch(array, target) { - this.isRunning = true; - const elements = this.visualizer.getSearchElements(); - let left = 0; - let right = array.length - 1; - - while (left <= right && this.isRunning) { - const mid = Math.floor((left + right) / 2); - - // 高亮当前搜索范围 - for (let i = left; i <= right; i++) { - elements[i].style.opacity = '1'; - } - - elements[mid].classList.add('checking'); - await sleep(this.speed); - - if (array[mid] === target) { - elements[mid].classList.remove('checking'); - elements[mid].classList.add('found'); - this.isRunning = false; - return mid; - } - - elements[mid].classList.remove('checking'); - elements[mid].classList.add('not-found'); - - if (array[mid] < target) { - // 目标在右半部分 - for (let i = left; i <= mid; i++) { - elements[i].style.opacity = '0.3'; - } - left = mid + 1; - } else { - // 目标在左半部分 - for (let i = mid; i <= right; i++) { - elements[i].style.opacity = '0.3'; - } - right = mid - 1; - } - - await sleep(this.speed / 2); - } - - this.isRunning = false; - return -1; - } -} - -// 图算法类 -class GraphAlgorithms { - constructor(visualizer) { - this.visualizer = visualizer; - this.isRunning = false; - this.speed = 600; - } - - setSpeed(speed) { - this.speed = 1100 - (speed * 100); - } - - stop() { - this.isRunning = false; - } - - // 广度优先搜索 - async bfs(graph, startNode) { - this.isRunning = true; - const visited = new Set(); - const queue = [startNode]; - const nodes = this.visualizer.getGraphNodes(); - const edges = this.visualizer.getGraphEdges(); - - visited.add(startNode); - nodes[startNode].classList.add('visited'); - await sleep(this.speed); - - while (queue.length > 0 && this.isRunning) { - const node = queue.shift(); - nodes[node].classList.add('current'); - await sleep(this.speed); - nodes[node].classList.remove('current'); - - const neighbors = graph[node]; - for (const neighbor of neighbors) { - if (!visited.has(neighbor) && this.isRunning) { - // 高亮边 - const edge = this.visualizer.getEdge(node, neighbor); - if (edge) edge.classList.add('visited'); - - visited.add(neighbor); - nodes[neighbor].classList.add('visited'); - queue.push(neighbor); - await sleep(this.speed); - } - } - } - - this.isRunning = false; - return visited; - } - - // 深度优先搜索 - async dfs(graph, startNode) { - this.isRunning = true; - const visited = new Set(); - const nodes = this.visualizer.getGraphNodes(); - - const dfsRecursive = async (node) => { - if (!this.isRunning) return; - - visited.add(node); - nodes[node].classList.add('current'); - await sleep(this.speed); - nodes[node].classList.remove('current'); - nodes[node].classList.add('visited'); - - const neighbors = graph[node]; - for (const neighbor of neighbors) { - if (!visited.has(neighbor) && this.isRunning) { - const edge = this.visualizer.getEdge(node, neighbor); - if (edge) edge.classList.add('visited'); - await dfsRecursive(neighbor); - } - } - }; - - await dfsRecursive(startNode); - this.isRunning = false; - return visited; - } - - // Dijkstra最短路径 - async dijkstra(graph, startNode, endNode) { - this.isRunning = true; - const distances = {}; - const previous = {}; - const unvisited = new Set(); - const nodes = this.visualizer.getGraphNodes(); - - // 初始化 - for (const node in graph) { - distances[node] = node === startNode ? 0 : Infinity; - previous[node] = null; - unvisited.add(node); - } - - nodes[startNode].classList.add('visited'); - await sleep(this.speed); - - while (unvisited.size > 0 && this.isRunning) { - // 找到距离最小的未访问节点 - let current = null; - let minDistance = Infinity; - - for (const node of unvisited) { - if (distances[node] < minDistance) { - minDistance = distances[node]; - current = node; - } - } - - if (current === null || distances[current] === Infinity) break; - - unvisited.delete(current); - nodes[current].classList.add('current'); - await sleep(this.speed); - - if (current === endNode) { - // 找到路径,高亮显示 - let pathNode = endNode; - while (pathNode !== null) { - nodes[pathNode].classList.add('found'); - pathNode = previous[pathNode]; - await sleep(this.speed / 2); - } - this.isRunning = false; - return distances[endNode]; - } - - nodes[current].classList.remove('current'); - nodes[current].classList.add('visited'); - - // 更新邻居的距离 - for (const neighbor of graph[current]) { - if (unvisited.has(neighbor)) { - const alt = distances[current] + 1; // 假设权重为1 - if (alt < distances[neighbor]) { - distances[neighbor] = alt; - previous[neighbor] = current; - const edge = this.visualizer.getEdge(current, neighbor); - if (edge) edge.classList.add('visited'); - } - } - } - - await sleep(this.speed / 2); - } - - this.isRunning = false; - return distances[endNode]; - } -} - -// 树算法类 -class TreeAlgorithms { - constructor(visualizer) { - this.visualizer = visualizer; - this.isRunning = false; - this.speed = 700; - } - - setSpeed(speed) { - this.speed = 1200 - (speed * 110); - } - - stop() { - this.isRunning = false; - } - - // 二叉搜索树插入 - async bstInsert(root, value, isBatch = false) { - this.isRunning = true; - - const insertRecursive = async (node, val, parent = null, isLeft = false) => { - if (!this.isRunning) return node; - - if (node === null) { - // 创建新节点 - const newNode = { value: val, left: null, right: null }; - this.visualizer.addTreeNode(val, parent, isLeft); - await sleep(this.speed); - return newNode; - } - - const nodeEl = this.visualizer.getTreeNode(node.value); - if (nodeEl) nodeEl.classList.add('checking'); - await sleep(this.speed); - - if (val < node.value) { - if (nodeEl) nodeEl.classList.remove('checking'); - node.left = await insertRecursive(node.left, val, node, true); - } else if (val > node.value) { - if (nodeEl) nodeEl.classList.remove('checking'); - node.right = await insertRecursive(node.right, val, node, false); - } - - return node; - }; - - const result = await insertRecursive(root, value); - // 只有在非批量插入模式或手动停止时才设置isRunning为false - if (!isBatch) { - this.isRunning = false; - } - return result; - } - - // 批量插入(用于构建树) - async bstInsertBatch(values) { - this.isRunning = true; - let root = null; - - for (const value of values) { - if (!this.isRunning) break; - root = await this.bstInsert(root, value, true); - } - - this.isRunning = false; - return root; - } - - // 二叉搜索树搜索 - async bstSearch(root, target) { - this.isRunning = true; - - const searchRecursive = async (node) => { - if (!this.isRunning || node === null) { - this.isRunning = false; - return null; - } - - const nodeEl = this.visualizer.getTreeNode(node.value); - if (nodeEl) nodeEl.classList.add('checking'); - await sleep(this.speed); - - if (target === node.value) { - if (nodeEl) { - nodeEl.classList.remove('checking'); - nodeEl.classList.add('found'); - } - this.isRunning = false; - return node; - } - - if (nodeEl) nodeEl.classList.remove('checking'); - - if (target < node.value) { - return await searchRecursive(node.left); - } else { - return await searchRecursive(node.right); - } - }; - - const result = await searchRecursive(root); - this.isRunning = false; - return result; - } - - // 树遍历 - 中序 - async inorderTraversal(root) { - this.isRunning = true; - const result = []; - - const traverse = async (node) => { - if (!this.isRunning || node === null) return; - - await traverse(node.left); - - if (!this.isRunning) return; - const nodeEl = this.visualizer.getTreeNode(node.value); - if (nodeEl) { - nodeEl.classList.add('visited'); - await sleep(this.speed); - } - result.push(node.value); - - await traverse(node.right); - }; - - await traverse(root); - this.isRunning = false; - return result; - } -} - -// 导出算法类 -if (typeof module !== 'undefined' && module.exports) { - module.exports = { - SortingAlgorithms, - SearchAlgorithms, - GraphAlgorithms, - TreeAlgorithms, - sleep - }; -} diff --git a/002game/game.js b/002game/game.js deleted file mode 100644 index f99f743b50..0000000000 --- a/002game/game.js +++ /dev/null @@ -1,821 +0,0 @@ -// 游戏主逻辑 - -// 关卡配置 -const LEVELS = [ - { - id: 1, - name: '冒泡排序', - category: '排序算法', - difficulty: 1, - algorithm: 'bubbleSort', - type: 'sorting', - description: '冒泡排序通过重复遍历列表,比较相邻元素并交换它们的位置来排序。', - timeComplexity: 'O(n²)', - spaceComplexity: 'O(1)', - task: '观察冒泡排序如何将最大的元素"冒泡"到数组末尾。' - }, - { - id: 2, - name: '快速排序', - category: '排序算法', - difficulty: 2, - algorithm: 'quickSort', - type: 'sorting', - description: '快速排序使用分治法,选择一个基准元素将数组分成两部分。', - timeComplexity: 'O(n log n)', - spaceComplexity: 'O(log n)', - task: '观察快速排序如何选择基准并分区。' - }, - { - id: 3, - name: '归并排序', - category: '排序算法', - difficulty: 2, - algorithm: 'mergeSort', - type: 'sorting', - description: '归并排序将数组分成两半,递归排序后再合并。', - timeComplexity: 'O(n log n)', - spaceComplexity: 'O(n)', - task: '观察归并排序的分治过程和合并操作。' - }, - { - id: 4, - name: '堆排序', - category: '排序算法', - difficulty: 3, - algorithm: 'heapSort', - type: 'sorting', - description: '堆排序利用堆数据结构,先将数组构建成最大堆,然后逐个取出最大元素。', - timeComplexity: 'O(n log n)', - spaceComplexity: 'O(1)', - task: '观察堆排序如何构建堆并提取最大元素。' - }, - { - id: 5, - name: '线性搜索', - category: '搜索算法', - difficulty: 1, - algorithm: 'linearSearch', - type: 'searching', - description: '线性搜索逐个检查数组中的每个元素,直到找到目标。', - timeComplexity: 'O(n)', - spaceComplexity: 'O(1)', - task: '观察线性搜索如何逐个检查元素。' - }, - { - id: 6, - name: '二分搜索', - category: '搜索算法', - difficulty: 2, - algorithm: 'binarySearch', - type: 'searching', - description: '二分搜索在有序数组中通过不断将搜索范围减半来查找目标。', - timeComplexity: 'O(log n)', - spaceComplexity: 'O(1)', - task: '观察二分搜索如何快速缩小搜索范围。' - }, - { - id: 7, - name: '广度优先搜索', - category: '图论算法', - difficulty: 2, - algorithm: 'bfs', - type: 'graph', - description: 'BFS从起始节点开始,先访问所有相邻节点,再访问下一层节点。', - timeComplexity: 'O(V + E)', - spaceComplexity: 'O(V)', - task: '观察BFS如何逐层遍历图。' - }, - { - id: 8, - name: '深度优先搜索', - category: '图论算法', - difficulty: 2, - algorithm: 'dfs', - type: 'graph', - description: 'DFS从起始节点开始,沿着一条路径尽可能深地探索,然后回溯。', - timeComplexity: 'O(V + E)', - spaceComplexity: 'O(V)', - task: '观察DFS如何深入探索图的分支。' - }, - { - id: 9, - name: 'Dijkstra最短路径', - category: '图论算法', - difficulty: 3, - algorithm: 'dijkstra', - type: 'graph', - description: 'Dijkstra算法找到从起点到其他所有节点的最短路径。', - timeComplexity: 'O((V + E) log V)', - spaceComplexity: 'O(V)', - task: '观察Dijkstra如何找到最短路径。' - }, - { - id: 10, - name: '二叉搜索树插入', - category: '数据结构', - difficulty: 2, - algorithm: 'bstInsert', - type: 'tree', - description: 'BST插入操作根据值的大小将新节点放到正确的位置。', - timeComplexity: 'O(log n)', - spaceComplexity: 'O(1)', - task: '观察BST如何保持有序性。' - }, - { - id: 11, - name: '二叉搜索树搜索', - category: '数据结构', - difficulty: 2, - algorithm: 'bstSearch', - type: 'tree', - description: 'BST搜索利用树的有序性,每次可以排除一半的节点。', - timeComplexity: 'O(log n)', - spaceComplexity: 'O(1)', - task: '观察BST搜索如何快速定位节点。' - }, - { - id: 12, - name: '树的中序遍历', - category: '数据结构', - difficulty: 2, - algorithm: 'inorderTraversal', - type: 'tree', - description: '中序遍历按照左-根-右的顺序访问BST节点,结果是有序的。', - timeComplexity: 'O(n)', - spaceComplexity: 'O(h)', - task: '观察中序遍历如何产生有序序列。' - } -]; - -// 可视化器类 -class Visualizer { - constructor(container) { - this.container = container; - this.currentData = null; - } - - clear() { - this.container.innerHTML = ''; - this.currentData = null; - } - - // 排序可视化 - createSortVisualization(array) { - this.clear(); - this.container.className = 'visualization-area'; - this.currentData = [...array]; - - const maxVal = Math.max(...array); - - array.forEach((val, index) => { - const bar = document.createElement('div'); - bar.className = 'sort-bar'; - bar.style.height = `${(val / maxVal) * 300}px`; - bar.setAttribute('data-value', val); - bar.setAttribute('data-index', index); - this.container.appendChild(bar); - }); - } - - updateBars(array) { - const bars = this.container.querySelectorAll('.sort-bar'); - const maxVal = Math.max(...array); - - bars.forEach((bar, index) => { - bar.style.height = `${(array[index] / maxVal) * 300}px`; - bar.setAttribute('data-value', array[index]); - }); - - this.currentData = [...array]; - } - - getBars() { - return this.container.querySelectorAll('.sort-bar'); - } - - // 搜索可视化 - createSearchVisualization(array) { - this.clear(); - this.container.className = 'visualization-area'; - this.currentData = [...array]; - - const searchArray = document.createElement('div'); - searchArray.className = 'search-array'; - - array.forEach((val, index) => { - const element = document.createElement('div'); - element.className = 'search-element'; - element.textContent = val; - element.setAttribute('data-index', index); - searchArray.appendChild(element); - }); - - this.container.appendChild(searchArray); - } - - getSearchElements() { - return this.container.querySelectorAll('.search-element'); - } - - // 图可视化 - createGraphVisualization(graphData) { - this.clear(); - this.container.className = 'visualization-area graph'; - this.currentData = graphData; - - const graphContainer = document.createElement('div'); - graphContainer.className = 'graph-container'; - graphContainer.style.width = '100%'; - graphContainer.style.height = '400px'; - - // 创建节点位置(圆形布局) - const nodes = Object.keys(graphData); - const centerX = 350; - const centerY = 200; - const radius = 150; - const nodePositions = {}; - - nodes.forEach((node, index) => { - const angle = (index / nodes.length) * 2 * Math.PI - Math.PI / 2; - nodePositions[node] = { - x: centerX + radius * Math.cos(angle), - y: centerY + radius * Math.sin(angle) - }; - }); - - // 绘制边 - const drawnEdges = new Set(); - nodes.forEach(node => { - graphData[node].forEach(neighbor => { - const edgeKey = [node, neighbor].sort().join('-'); - if (!drawnEdges.has(edgeKey)) { - drawnEdges.add(edgeKey); - - const edge = document.createElement('div'); - edge.className = 'graph-edge'; - edge.setAttribute('data-from', node); - edge.setAttribute('data-to', neighbor); - - const from = nodePositions[node]; - const to = nodePositions[neighbor]; - const length = Math.sqrt(Math.pow(to.x - from.x, 2) + Math.pow(to.y - from.y, 2)); - const angle = Math.atan2(to.y - from.y, to.x - from.x) * 180 / Math.PI; - - edge.style.width = `${length}px`; - edge.style.left = `${from.x}px`; - edge.style.top = `${from.y}px`; - edge.style.transform = `rotate(${angle}deg)`; - - graphContainer.appendChild(edge); - } - }); - }); - - // 绘制节点 - nodes.forEach(node => { - const nodeEl = document.createElement('div'); - nodeEl.className = 'graph-node'; - nodeEl.textContent = node; - nodeEl.setAttribute('data-node', node); - nodeEl.style.left = `${nodePositions[node].x - 25}px`; - nodeEl.style.top = `${nodePositions[node].y - 25}px`; - graphContainer.appendChild(nodeEl); - }); - - this.container.appendChild(graphContainer); - this.nodePositions = nodePositions; - } - - getGraphNodes() { - const nodes = {}; - this.container.querySelectorAll('.graph-node').forEach(node => { - nodes[node.getAttribute('data-node')] = node; - }); - return nodes; - } - - getGraphEdges() { - return this.container.querySelectorAll('.graph-edge'); - } - - getEdge(from, to) { - const edge1 = this.container.querySelector(`[data-from="${from}"][data-to="${to}"]`); - const edge2 = this.container.querySelector(`[data-from="${to}"][data-to="${from}"]`); - return edge1 || edge2; - } - - // 树可视化 - createTreeVisualization() { - this.clear(); - this.container.className = 'visualization-area'; - this.currentData = { root: null, nodes: {} }; - - const treeContainer = document.createElement('div'); - treeContainer.className = 'tree-container'; - treeContainer.id = 'tree-root'; - this.container.appendChild(treeContainer); - } - - addTreeNode(value, parent = null, isLeft = false) { - const treeRoot = document.getElementById('tree-root'); - - if (parent === null) { - // 根节点 - treeRoot.innerHTML = ''; - const level = document.createElement('div'); - level.className = 'tree-level'; - - const node = document.createElement('div'); - node.className = 'tree-node inserting'; - node.textContent = value; - node.setAttribute('data-value', value); - - level.appendChild(node); - treeRoot.appendChild(level); - } else { - // 查找父节点并添加子节点 - const parentValue = parent.value; - const parentNode = treeRoot.querySelector(`[data-value="${parentValue}"]`); - - if (parentNode) { - let level = parentNode.closest('.tree-level'); - let nextLevel = level.nextElementSibling; - - if (!nextLevel) { - nextLevel = document.createElement('div'); - nextLevel.className = 'tree-level'; - treeRoot.appendChild(nextLevel); - } - - const node = document.createElement('div'); - node.className = 'tree-node inserting'; - node.textContent = value; - node.setAttribute('data-value', value); - - nextLevel.appendChild(node); - - setTimeout(() => { - node.classList.remove('inserting'); - }, 500); - } - } - } - - getTreeNode(value) { - return document.querySelector(`.tree-node[data-value="${value}"]`); - } -} - -// 游戏主类 -class Game { - constructor() { - this.currentLevel = null; - this.score = 0; - this.isPlaying = false; - this.visualizer = null; - this.algorithmInstance = null; - this.currentAlgorithm = null; - this.startTime = null; - this.completedLevels = new Set(); - - this.init(); - } - - init() { - this.visualizer = new Visualizer(document.getElementById('visualization-area')); - this.generateLevelGrid(); - - // 加载保存的进度 - const saved = localStorage.getItem('algorithmGameProgress'); - if (saved) { - const progress = JSON.parse(saved); - this.score = progress.score || 0; - this.completedLevels = new Set(progress.completedLevels || []); - } - - this.updateScore(); - } - - // 屏幕切换 - showScreen(screenId) { - document.querySelectorAll('.screen').forEach(screen => { - screen.classList.remove('active'); - }); - document.getElementById(screenId).classList.add('active'); - } - - showStart() { - this.showScreen('start-screen'); - } - - start() { - this.showLevels(); - } - - showLevels() { - this.generateLevelGrid(); - this.showScreen('level-screen'); - } - - showHelp() { - this.showScreen('help-screen'); - } - - // 生成关卡网格 - generateLevelGrid() { - const grid = document.getElementById('level-grid'); - grid.innerHTML = ''; - - LEVELS.forEach((level, index) => { - const card = document.createElement('div'); - card.className = 'level-card'; - - // 检查是否锁定 - if (index > 0 && !this.completedLevels.has(LEVELS[index - 1].id)) { - card.classList.add('locked'); - } - - // 检查是否已完成 - if (this.completedLevels.has(level.id)) { - card.classList.add('completed'); - } - - // 生成难度星星 - const stars = '★'.repeat(level.difficulty) + '☆'.repeat(3 - level.difficulty); - - card.innerHTML = ` -
关卡 ${level.id}
-
${level.name}
-
${level.category}
-
- ${stars.split('').map(star => - `${star}` - ).join('')} -
- `; - - if (!card.classList.contains('locked')) { - card.onclick = () => this.loadLevel(level); - } - - grid.appendChild(card); - }); - } - - // 加载关卡 - loadLevel(level) { - this.currentLevel = level; - this.isPlaying = false; - this.startTime = Date.now(); - - // 更新UI - document.getElementById('level-title').textContent = `关卡 ${level.id}: ${level.name}`; - document.getElementById('algorithm-name').textContent = level.name; - document.getElementById('algorithm-desc').textContent = level.description; - document.getElementById('time-complexity').textContent = `时间复杂度: ${level.timeComplexity}`; - document.getElementById('space-complexity').textContent = `空间复杂度: ${level.spaceComplexity}`; - document.getElementById('game-task').innerHTML = ` -

🎯 任务

-

${level.task}

- `; - - // 初始化可视化 - this.visualizer.clear(); - this.initializeAlgorithm(level); - - // 生成初始数据 - this.generateNew(); - - this.showScreen('game-screen'); - } - - // 初始化算法 - initializeAlgorithm(level) { - // 停止之前的算法 - if (this.algorithmInstance) { - this.algorithmInstance.stop(); - } - - const speed = document.getElementById('speed-slider').value; - - switch (level.type) { - case 'sorting': - this.algorithmInstance = new SortingAlgorithms(this.visualizer); - this.currentAlgorithm = () => { - const array = this.generateRandomArray(15, 100); - this.visualizer.createSortVisualization(array); - return this.algorithmInstance[level.algorithm](array); - }; - break; - - case 'searching': - this.algorithmInstance = new SearchAlgorithms(this.visualizer); - this.currentAlgorithm = () => { - const array = this.generateSortedArray(15, 100); - const target = array[Math.floor(Math.random() * array.length)]; - this.visualizer.createSearchVisualization(array); - document.getElementById('game-task').innerHTML += ` -

🔍 搜索目标: ${target}

- `; - return this.algorithmInstance[level.algorithm](array, target); - }; - break; - - case 'graph': - this.algorithmInstance = new GraphAlgorithms(this.visualizer); - this.currentAlgorithm = () => { - const graph = this.generateRandomGraph(); - this.visualizer.createGraphVisualization(graph); - const startNode = Object.keys(graph)[0]; - - if (level.algorithm === 'dijkstra') { - const endNode = Object.keys(graph)[Object.keys(graph).length - 1]; - return this.algorithmInstance[level.algorithm](graph, startNode, endNode); - } - return this.algorithmInstance[level.algorithm](graph, startNode); - }; - break; - - case 'tree': - this.algorithmInstance = new TreeAlgorithms(this.visualizer); - this.currentAlgorithm = async () => { - this.visualizer.createTreeVisualization(); - const values = this.generateRandomArray(7, 99); - let root = null; - - if (level.algorithm === 'bstInsert') { - // 使用批量插入,完成后isRunning会自动设为false - root = await this.algorithmInstance.bstInsertBatch(values); - return root; - } else if (level.algorithm === 'bstSearch') { - // 先构建树(使用临时实例,不影响当前算法实例的状态) - const buildAlgo = new TreeAlgorithms(this.visualizer); - root = await buildAlgo.bstInsertBatch(values); - - const target = values[Math.floor(Math.random() * values.length)]; - document.getElementById('game-task').innerHTML += ` -

🔍 搜索目标: ${target}

- `; - return this.algorithmInstance.bstSearch(root, target); - } else if (level.algorithm === 'inorderTraversal') { - // 先构建树 - const buildAlgo = new TreeAlgorithms(this.visualizer); - root = await buildAlgo.bstInsertBatch(values); - return this.algorithmInstance.inorderTraversal(root); - } - }; - break; - } - - this.algorithmInstance.setSpeed(speed); - } - - // 生成随机数组 - generateRandomArray(size, max) { - const array = []; - for (let i = 0; i < size; i++) { - array.push(Math.floor(Math.random() * max) + 1); - } - return array; - } - - // 生成有序数组 - generateSortedArray(size, max) { - const array = this.generateRandomArray(size, max); - return array.sort((a, b) => a - b); - } - - // 生成随机图 - generateRandomGraph() { - const nodes = ['A', 'B', 'C', 'D', 'E', 'F']; - const graph = {}; - - nodes.forEach(node => { - graph[node] = []; - }); - - // 随机添加边 - nodes.forEach((node, i) => { - const numEdges = Math.floor(Math.random() * 2) + 1; - for (let j = 0; j < numEdges; j++) { - const target = nodes[Math.floor(Math.random() * nodes.length)]; - if (target !== node && !graph[node].includes(target)) { - graph[node].push(target); - if (!graph[target].includes(node)) { - graph[target].push(node); - } - } - } - }); - - return graph; - } - - // 控制方法 - togglePlay() { - const btn = document.getElementById('btn-play'); - - if (this.isPlaying) { - this.isPlaying = false; - btn.textContent = '▶ 播放'; - if (this.algorithmInstance) { - this.algorithmInstance.stop(); - } - } else { - this.isPlaying = true; - btn.textContent = '⏸ 暂停'; - this.runAlgorithm(); - } - } - - async runAlgorithm() { - if (this.currentAlgorithm) { - this.algorithmCompleted = false; - await this.currentAlgorithm(); - - // 等待算法真正完成(检查isRunning状态) - if (this.algorithmInstance) { - await this.waitForAlgorithmComplete(); - } - - if (!this.algorithmCompleted) { - this.algorithmCompleted = true; - this.isPlaying = false; - document.getElementById('btn-play').textContent = '▶ 播放'; - this.completeLevel(); - } - } - } - - async waitForAlgorithmComplete() { - // 等待算法实例的isRunning变为false - return new Promise(resolve => { - const checkInterval = setInterval(() => { - // 检查算法实例是否存在且isRunning为false - if (this.algorithmInstance && !this.algorithmInstance.isRunning) { - clearInterval(checkInterval); - resolve(); - } - }, 100); - // 超时处理(最多等60秒) - setTimeout(() => { - clearInterval(checkInterval); - resolve(); - }, 60000); - }); - } - - step() { - // 单步执行(简化版本,实际实现需要更复杂的逻辑) - if (!this.isPlaying) { - this.togglePlay(); - } - } - - reset() { - this.isPlaying = false; - document.getElementById('btn-play').textContent = '▶ 播放'; - if (this.algorithmInstance) { - this.algorithmInstance.stop(); - } - this.initializeAlgorithm(this.currentLevel); - } - - generateNew() { - // 停止当前算法 - this.isPlaying = false; - document.getElementById('btn-play').textContent = '▶ 播放'; - if (this.algorithmInstance) { - this.algorithmInstance.stop(); - } - // 重新生成数据但不重新初始化整个算法 - if (this.currentAlgorithm && this.currentLevel) { - const speed = document.getElementById('speed-slider').value; - - switch (this.currentLevel.type) { - case 'sorting': - const array = this.generateRandomArray(15, 100); - this.visualizer.createSortVisualization(array); - this.currentAlgorithm = () => { - return this.algorithmInstance[this.currentLevel.algorithm](array); - }; - break; - - case 'searching': - const searchArray = this.generateSortedArray(15, 100); - const target = searchArray[Math.floor(Math.random() * searchArray.length)]; - this.visualizer.createSearchVisualization(searchArray); - document.getElementById('game-task').innerHTML = ` -

🎯 任务

-

${this.currentLevel.task}

-

🔍 搜索目标: ${target}

- `; - this.currentAlgorithm = () => { - return this.algorithmInstance[this.currentLevel.algorithm](searchArray, target); - }; - break; - - case 'graph': - const graph = this.generateRandomGraph(); - this.visualizer.createGraphVisualization(graph); - const startNode = Object.keys(graph)[0]; - this.currentAlgorithm = () => { - if (this.currentLevel.algorithm === 'dijkstra') { - const endNode = Object.keys(graph)[Object.keys(graph).length - 1]; - return this.algorithmInstance[this.currentLevel.algorithm](graph, startNode, endNode); - } - return this.algorithmInstance[this.currentLevel.algorithm](graph, startNode); - }; - break; - - case 'tree': - this.visualizer.createTreeVisualization(); - const values = this.generateRandomArray(7, 99); - if (this.currentLevel.algorithm === 'bstInsert') { - this.currentAlgorithm = async () => { - return this.algorithmInstance.bstInsertBatch(values); - }; - } else if (this.currentLevel.algorithm === 'bstSearch') { - const buildAlgo = new TreeAlgorithms(this.visualizer); - buildAlgo.bstInsertBatch(values).then(root => { - const target = values[Math.floor(Math.random() * values.length)]; - document.getElementById('game-task').innerHTML = ` -

🎯 任务

-

${this.currentLevel.task}

-

🔍 搜索目标: ${target}

- `; - this.currentAlgorithm = () => { - return this.algorithmInstance.bstSearch(root, target); - }; - }); - } else if (this.currentLevel.algorithm === 'inorderTraversal') { - const buildAlgo = new TreeAlgorithms(this.visualizer); - buildAlgo.bstInsertBatch(values).then(root => { - this.currentAlgorithm = () => { - return this.algorithmInstance.inorderTraversal(root); - }; - }); - } - break; - } - - this.algorithmInstance.setSpeed(speed); - } - } - - updateSpeed(value) { - if (this.algorithmInstance) { - this.algorithmInstance.setSpeed(parseInt(value)); - } - } - - // 完成关卡 - completeLevel() { - if (!this.completedLevels.has(this.currentLevel.id)) { - this.completedLevels.add(this.currentLevel.id); - this.score += 100 * this.currentLevel.difficulty; - this.updateScore(); - this.saveProgress(); - } - - const timeElapsed = Math.floor((Date.now() - this.startTime) / 1000); - document.getElementById('complete-score').textContent = this.score; - document.getElementById('complete-time').textContent = `${timeElapsed}s`; - - setTimeout(() => { - this.showScreen('complete-screen'); - }, 1000); - } - - nextLevel() { - const currentIndex = LEVELS.findIndex(l => l.id === this.currentLevel.id); - if (currentIndex < LEVELS.length - 1) { - this.loadLevel(LEVELS[currentIndex + 1]); - } else { - this.showLevels(); - } - } - - restartLevel() { - this.loadLevel(this.currentLevel); - } - - updateScore() { - document.getElementById('score').textContent = this.score; - } - - saveProgress() { - const progress = { - score: this.score, - completedLevels: Array.from(this.completedLevels) - }; - localStorage.setItem('algorithmGameProgress', JSON.stringify(progress)); - } -} - -// 初始化游戏 -let game; -document.addEventListener('DOMContentLoaded', () => { - game = new Game(); -}); diff --git a/002game/index.html b/002game/index.html deleted file mode 100644 index 531d1a14a2..0000000000 --- a/002game/index.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - 算法探险家 - Algorithm Explorer - - - -
- -
-
-

🔍 算法探险家

-

Algorithm Explorer

-

通过可视化游戏学习经典算法

-
- -
-
📊 排序算法
-
🔎 搜索算法
-
🌲 图论算法
-
🧩 动态规划
-
📚 数据结构
-
-
- - -
-

选择关卡

-
- -
- -
- - -
-
- -

关卡标题

-
得分: 0
-
-
-
-

算法名称

-

算法描述

-
- 时间复杂度: O(n²) - 空间复杂度: O(1) -
-
-
- -
-
-
- - - - -
-
- - -
-
-
- -
-
-
- - -
-

游戏说明

-
-
-

🎯 游戏目标

-

通过可视化的方式学习和理解各种经典算法。每个关卡都会展示一个算法的执行过程,帮助你直观地理解算法的工作原理。

-
-
-

🎮 操作方法

-
    -
  • 播放/暂停: 控制算法的自动执行
  • -
  • 单步: 逐步查看算法的每一步
  • -
  • 重置: 重新开始当前关卡
  • -
  • 新数据: 生成新的随机数据
  • -
  • 速度滑块: 调整动画播放速度
  • -
-
-
-

📚 包含的算法

-
-
-

排序算法

- 冒泡排序、快速排序、归并排序、堆排序 -
-
-

搜索算法

- 线性搜索、二分搜索、广度优先搜索、深度优先搜索 -
-
-

图论算法

- Dijkstra最短路径、Prim最小生成树 -
-
-

数据结构

- 二叉搜索树、堆、链表操作 -
-
-
-
- -
- - -
-
-

🎉 恭喜完成!

-

你已完成本关卡!

-
-
- 得分 - 0 -
-
- 用时 - 0s -
-
-
-
- - - -
-
-
- - - - - diff --git a/002game/styles.css b/002game/styles.css deleted file mode 100644 index 3ed04eb621..0000000000 --- a/002game/styles.css +++ /dev/null @@ -1,819 +0,0 @@ -/* 基础样式重置 */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -:root { - --primary-color: #6366f1; - --primary-dark: #4f46e5; - --secondary-color: #8b5cf6; - --accent-color: #ec4899; - --success-color: #10b981; - --warning-color: #f59e0b; - --error-color: #ef4444; - --bg-dark: #0f172a; - --bg-card: #1e293b; - --bg-light: #334155; - --text-primary: #f8fafc; - --text-secondary: #94a3b8; - --border-color: #475569; - --shadow: 0 10px 40px rgba(0, 0, 0, 0.3); - --shadow-glow: 0 0 30px rgba(99, 102, 241, 0.3); -} - -body { - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - background: linear-gradient(135deg, var(--bg-dark) 0%, #1a1a2e 50%, #16213e 100%); - min-height: 100vh; - color: var(--text-primary); - overflow-x: hidden; -} - -#game-container { - max-width: 1200px; - margin: 0 auto; - padding: 20px; - min-height: 100vh; -} - -/* 屏幕管理 */ -.screen { - display: none; - animation: fadeIn 0.5s ease; -} - -.screen.active { - display: block; -} - -@keyframes fadeIn { - from { opacity: 0; transform: translateY(20px); } - to { opacity: 1; transform: translateY(0); } -} - -/* 开始界面 */ -#start-screen { - text-align: center; - padding: 60px 20px; -} - -.title-container { - margin-bottom: 50px; -} - -.game-title { - font-size: 4rem; - font-weight: 800; - background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - margin-bottom: 10px; - text-shadow: 0 0 60px rgba(99, 102, 241, 0.5); -} - -.subtitle { - font-size: 1.5rem; - color: var(--text-secondary); - margin-bottom: 15px; - letter-spacing: 3px; -} - -.description { - font-size: 1.2rem; - color: var(--text-secondary); -} - -.menu-buttons { - display: flex; - gap: 20px; - justify-content: center; - margin-bottom: 50px; - flex-wrap: wrap; -} - -.btn { - padding: 15px 40px; - font-size: 1.1rem; - font-weight: 600; - border: none; - border-radius: 12px; - cursor: pointer; - transition: all 0.3s ease; - text-transform: uppercase; - letter-spacing: 1px; -} - -.btn-primary { - background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); - color: white; - box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4); -} - -.btn-primary:hover { - transform: translateY(-3px); - box-shadow: 0 8px 25px rgba(99, 102, 241, 0.5); -} - -.btn-secondary { - background: var(--bg-card); - color: var(--text-primary); - border: 2px solid var(--border-color); -} - -.btn-secondary:hover { - background: var(--bg-light); - border-color: var(--primary-color); -} - -.btn-small { - padding: 8px 20px; - font-size: 0.9rem; -} - -.btn-back { - margin-top: 30px; - background: var(--bg-card); - color: var(--text-primary); - border: 2px solid var(--border-color); -} - -.btn-control { - padding: 10px 20px; - font-size: 0.9rem; - background: var(--bg-card); - color: var(--text-primary); - border: 1px solid var(--border-color); -} - -.btn-control:hover { - background: var(--primary-color); - border-color: var(--primary-color); -} - -.algorithm-categories { - display: flex; - gap: 15px; - justify-content: center; - flex-wrap: wrap; -} - -.category-tag { - padding: 10px 20px; - background: var(--bg-card); - border-radius: 25px; - border: 1px solid var(--border-color); - font-size: 0.95rem; - transition: all 0.3s ease; -} - -.category-tag:hover { - border-color: var(--primary-color); - transform: translateY(-2px); -} - -/* 关卡选择界面 */ -#level-screen { - padding: 40px 20px; -} - -#level-screen h2 { - text-align: center; - font-size: 2.5rem; - margin-bottom: 40px; - background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.level-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 25px; - margin-bottom: 40px; -} - -.level-card { - background: var(--bg-card); - border-radius: 16px; - padding: 25px; - border: 2px solid var(--border-color); - cursor: pointer; - transition: all 0.3s ease; - position: relative; - overflow: hidden; -} - -.level-card::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 4px; - background: linear-gradient(90deg, var(--primary-color), var(--accent-color)); - transform: scaleX(0); - transition: transform 0.3s ease; -} - -.level-card:hover::before { - transform: scaleX(1); -} - -.level-card:hover { - transform: translateY(-5px); - border-color: var(--primary-color); - box-shadow: var(--shadow-glow); -} - -.level-card.locked { - opacity: 0.5; - cursor: not-allowed; -} - -.level-card.locked:hover { - transform: none; - border-color: var(--border-color); - box-shadow: none; -} - -.level-card.completed { - border-color: var(--success-color); -} - -.level-card.completed::after { - content: '✓'; - position: absolute; - top: 15px; - right: 15px; - width: 30px; - height: 30px; - background: var(--success-color); - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-weight: bold; -} - -.level-number { - font-size: 0.9rem; - color: var(--text-secondary); - margin-bottom: 10px; -} - -.level-name { - font-size: 1.3rem; - font-weight: 700; - margin-bottom: 10px; -} - -.level-category { - display: inline-block; - padding: 5px 12px; - background: var(--bg-light); - border-radius: 15px; - font-size: 0.8rem; - color: var(--text-secondary); -} - -.level-difficulty { - margin-top: 15px; - display: flex; - gap: 5px; -} - -.difficulty-star { - color: var(--warning-color); -} - -.difficulty-star.empty { - color: var(--bg-light); -} - -/* 游戏界面 */ -#game-screen { - padding: 20px; -} - -.game-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 30px; - padding: 20px; - background: var(--bg-card); - border-radius: 12px; - border: 1px solid var(--border-color); -} - -.game-header h3 { - font-size: 1.5rem; - background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.score-display { - font-size: 1.2rem; - font-weight: 600; - color: var(--success-color); -} - -.game-content { - background: var(--bg-card); - border-radius: 16px; - padding: 30px; - border: 1px solid var(--border-color); -} - -.algorithm-info { - margin-bottom: 30px; - padding-bottom: 20px; - border-bottom: 1px solid var(--border-color); -} - -.algorithm-info h4 { - font-size: 1.5rem; - margin-bottom: 10px; - color: var(--primary-color); -} - -.algorithm-info p { - color: var(--text-secondary); - line-height: 1.6; - margin-bottom: 15px; -} - -.complexity-info { - display: flex; - gap: 20px; - flex-wrap: wrap; -} - -.complexity { - padding: 8px 16px; - background: var(--bg-light); - border-radius: 8px; - font-size: 0.9rem; - font-family: 'Courier New', monospace; -} - -/* 可视化区域 */ -.visualization-area { - min-height: 400px; - background: var(--bg-dark); - border-radius: 12px; - padding: 30px; - margin-bottom: 30px; - display: flex; - align-items: flex-end; - justify-content: center; - gap: 5px; - position: relative; - overflow: hidden; -} - -.visualization-area.graph { - align-items: center; -} - -/* 排序可视化 */ -.sort-bar { - width: 40px; - background: linear-gradient(180deg, var(--primary-color), var(--secondary-color)); - border-radius: 4px 4px 0 0; - transition: all 0.3s ease; - position: relative; -} - -.sort-bar.comparing { - background: linear-gradient(180deg, var(--warning-color), #f97316); - transform: scaleY(1.05); -} - -.sort-bar.swapping { - background: linear-gradient(180deg, var(--error-color), #dc2626); -} - -.sort-bar.sorted { - background: linear-gradient(180deg, var(--success-color), #059669); -} - -.sort-bar::after { - content: attr(data-value); - position: absolute; - bottom: -25px; - left: 50%; - transform: translateX(-50%); - font-size: 0.8rem; - color: var(--text-secondary); -} - -/* 搜索可视化 */ -.search-array { - display: flex; - gap: 10px; - align-items: center; -} - -.search-element { - width: 60px; - height: 60px; - background: var(--bg-light); - border-radius: 12px; - display: flex; - align-items: center; - justify-content: center; - font-size: 1.2rem; - font-weight: 600; - transition: all 0.3s ease; - border: 2px solid transparent; -} - -.search-element.checking { - background: var(--warning-color); - border-color: var(--warning-color); - transform: scale(1.1); -} - -.search-element.found { - background: var(--success-color); - border-color: var(--success-color); - transform: scale(1.15); - box-shadow: 0 0 20px rgba(16, 185, 129, 0.5); -} - -.search-element.not-found { - background: var(--error-color); - opacity: 0.5; -} - -/* 图可视化 */ -.graph-container { - width: 100%; - height: 100%; - position: relative; -} - -.graph-node { - width: 50px; - height: 50px; - background: var(--bg-light); - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-weight: 600; - position: absolute; - border: 3px solid var(--border-color); - transition: all 0.3s ease; -} - -.graph-node.visited { - background: var(--primary-color); - border-color: var(--primary-color); - box-shadow: 0 0 20px rgba(99, 102, 241, 0.5); -} - -.graph-node.current { - background: var(--warning-color); - border-color: var(--warning-color); - transform: scale(1.2); -} - -.graph-edge { - position: absolute; - background: var(--border-color); - height: 2px; - transform-origin: left center; - transition: all 0.3s ease; -} - -.graph-edge.visited { - background: var(--primary-color); - height: 3px; -} - -/* 树可视化 */ -.tree-container { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; -} - -.tree-level { - display: flex; - gap: 40px; - margin: 20px 0; -} - -.tree-node { - width: 50px; - height: 50px; - background: var(--bg-light); - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-weight: 600; - border: 3px solid var(--border-color); - transition: all 0.3s ease; - position: relative; -} - -.tree-node.visited { - background: var(--primary-color); - border-color: var(--primary-color); -} - -.tree-node.inserting { - background: var(--success-color); - border-color: var(--success-color); - animation: pulse 0.5s ease; -} - -@keyframes pulse { - 0%, 100% { transform: scale(1); } - 50% { transform: scale(1.2); } -} - -/* 控制区域 */ -.controls { - display: flex; - justify-content: space-between; - align-items: center; - flex-wrap: wrap; - gap: 20px; - padding: 20px; - background: var(--bg-dark); - border-radius: 12px; - margin-bottom: 20px; -} - -.control-buttons { - display: flex; - gap: 10px; - flex-wrap: wrap; -} - -.speed-control { - display: flex; - align-items: center; - gap: 10px; -} - -.speed-control label { - color: var(--text-secondary); -} - -.speed-control input[type="range"] { - width: 150px; - height: 6px; - -webkit-appearance: none; - background: var(--bg-light); - border-radius: 3px; - outline: none; -} - -.speed-control input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - width: 18px; - height: 18px; - background: var(--primary-color); - border-radius: 50%; - cursor: pointer; -} - -/* 游戏任务 */ -.game-task { - padding: 20px; - background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(236, 72, 153, 0.1)); - border-radius: 12px; - border: 1px solid var(--border-color); -} - -.game-task h4 { - color: var(--primary-color); - margin-bottom: 10px; -} - -.game-task p { - color: var(--text-secondary); -} - -/* 帮助界面 */ -#help-screen { - padding: 40px 20px; - max-width: 900px; - margin: 0 auto; -} - -#help-screen h2 { - text-align: center; - font-size: 2.5rem; - margin-bottom: 40px; - background: linear-gradient(135deg, var(--primary-color), var(--accent-color)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.help-content { - margin-bottom: 40px; -} - -.help-section { - background: var(--bg-card); - border-radius: 16px; - padding: 30px; - margin-bottom: 25px; - border: 1px solid var(--border-color); -} - -.help-section h3 { - color: var(--primary-color); - margin-bottom: 15px; - font-size: 1.3rem; -} - -.help-section p { - color: var(--text-secondary); - line-height: 1.7; -} - -.help-section ul { - list-style: none; - padding-left: 0; -} - -.help-section li { - color: var(--text-secondary); - padding: 10px 0; - padding-left: 25px; - position: relative; - border-bottom: 1px solid var(--bg-light); -} - -.help-section li:last-child { - border-bottom: none; -} - -.help-section li::before { - content: '▸'; - position: absolute; - left: 0; - color: var(--primary-color); -} - -.algorithm-list { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 20px; -} - -.algo-group { - background: var(--bg-dark); - padding: 20px; - border-radius: 12px; -} - -.algo-group h4 { - color: var(--accent-color); - margin-bottom: 10px; - font-size: 1rem; -} - -.algo-group span { - color: var(--text-secondary); - font-size: 0.9rem; -} - -/* 完成界面 */ -#complete-screen { - text-align: center; - padding: 60px 20px; -} - -.complete-message { - margin-bottom: 40px; -} - -.complete-message h2 { - font-size: 3rem; - margin-bottom: 20px; - background: linear-gradient(135deg, var(--success-color), var(--primary-color)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.complete-message p { - font-size: 1.2rem; - color: var(--text-secondary); - margin-bottom: 30px; -} - -.complete-stats { - display: flex; - justify-content: center; - gap: 60px; - margin-bottom: 40px; -} - -.stat { - display: flex; - flex-direction: column; - align-items: center; -} - -.stat-label { - color: var(--text-secondary); - font-size: 1rem; - margin-bottom: 10px; -} - -.stat-value { - font-size: 2.5rem; - font-weight: 700; - color: var(--primary-color); -} - -.complete-buttons { - display: flex; - gap: 20px; - justify-content: center; - flex-wrap: wrap; -} - -/* 响应式设计 */ -@media (max-width: 768px) { - .game-title { - font-size: 2.5rem; - } - - .level-grid { - grid-template-columns: 1fr; - } - - .game-header { - flex-direction: column; - gap: 15px; - text-align: center; - } - - .controls { - flex-direction: column; - align-items: stretch; - } - - .control-buttons { - justify-content: center; - } - - .visualization-area { - min-height: 300px; - padding: 15px; - } - - .sort-bar { - width: 25px; - } - - .search-element { - width: 45px; - height: 45px; - font-size: 1rem; - } - - .complete-stats { - flex-direction: column; - gap: 30px; - } -} - -/* 动画效果 */ -@keyframes slideIn { - from { - opacity: 0; - transform: translateX(-20px); - } - to { - opacity: 1; - transform: translateX(0); - } -} - -@keyframes bounce { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-10px); } -} - -.animate-bounce { - animation: bounce 0.5s ease; -}