算法2026-05-01·12 分钟
算法知识库:游戏算法实现
JavaScript/TypeScript 实现游戏相关算法,如路径寻找、决策树、遗传算法等。
游戏算法实现
1. A* 路径寻找
ts
interface Node {
x: number;
y: number;
g: number; // 从起点到当前节点的代价
h: number; // 从当前节点到终点的启发式估计代价
f: number; // f = g + h
parent?: Node;
}
class AStarPathfinding {
private grid: number[][];
private rows: number;
private cols: number;
constructor(grid: number[][]) {
this.grid = grid;
this.rows = grid.length;
this.cols = grid[0].length;
}
findPath(start: { x: number; y: number }, end: { x: number; y: number }): { x: number; y: number }[] {
const openList: Node[] = [];
const closedList: Set<string> = new Set();
const startNode: Node = {
x: start.x,
y: start.y,
g: 0,
h: this.heuristic(start, end),
f: 0,
};
startNode.f = startNode.g + startNode.h;
openList.push(startNode);
while (openList.length > 0) {
// 找到 f 值最小的节点
openList.sort((a, b) => a.f - b.f);
const currentNode = openList.shift()!;
const key = `${currentNode.x},${currentNode.y}`;
if (closedList.has(key)) continue;
closedList.add(key);
// 到达终点
if (currentNode.x === end.x && currentNode.y === end.y) {
return this.reconstructPath(currentNode);
}
// 检查邻居节点
const neighbors = this.getNeighbors(currentNode);
for (const neighbor of neighbors) {
const neighborKey = `${neighbor.x},${neighbor.y}`;
if (closedList.has(neighborKey) || this.grid[neighbor.y][neighbor.x] === 1) continue;
const gScore = currentNode.g + 1; // 假设每个移动代价为 1
const existingNode = openList.find((node) => node.x === neighbor.x && node.y === neighbor.y);
if (!existingNode || gScore < existingNode.g) {
neighbor.g = gScore;
neighbor.h = this.heuristic(neighbor, end);
neighbor.f = neighbor.g + neighbor.h;
neighbor.parent = currentNode;
if (!existingNode) {
openList.push(neighbor);
}
}
}
}
return []; // 没有找到路径
}
private heuristic(a: { x: number; y: number }, b: { x: number; y: number }): number {
// 曼哈顿距离
return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
}
private getNeighbors(node: Node): Node[] {
const neighbors: Node[] = [];
const directions = [
{ x: 0, y: -1 }, // 上
{ x: 1, y: 0 }, // 右
{ x: 0, y: 1 }, // 下
{ x: -1, y: 0 }, // 左
];
for (const dir of directions) {
const newX = node.x + dir.x;
const newY = node.y + dir.y;
if (newX >= 0 && newX < this.cols && newY >= 0 && newY < this.rows) {
neighbors.push({ x: newX, y: newY, g: 0, h: 0, f: 0 });
}
}
return neighbors;
}
private reconstructPath(node: Node): { x: number; y: number }[] {
const path: { x: number; y: number }[] = [];
let current: Node | undefined = node;
while (current) {
path.unshift({ x: current.x, y: current.y });
current = current.parent;
}
return path;
}
}2. 极大极小算法 (Minimax)
ts
class MinimaxGame {
evaluate(board: number[][]): number {
// 简化版评估函数
// 返回正数表示 AI 优势,负数表示玩家优势
return Math.random() * 10 - 5;
}
isGameOver(board: number[][]): boolean {
// 检查游戏是否结束
return Math.random() > 0.9; // 10% 概率结束
}
getPossibleMoves(board: number[][]): number[][] {
// 返回所有可能的移动
const moves: number[][] = [];
for (let i = 0; i < 3; i += 1) {
for (let j = 0; j < 3; j += 1) {
if (board[i][j] === 0) {
const newBoard = board.map((row) => [...row]);
newBoard[i][j] = 1; // AI 移动
moves.push(newBoard);
}
}
}
return moves;
}
minimax(board: number[][], depth: number, isMaximizing: boolean): number {
if (depth === 0 || this.isGameOver(board)) {
return this.evaluate(board);
}
if (isMaximizing) {
let maxEval = -Infinity;
const moves = this.getPossibleMoves(board);
for (const move of moves) {
const eval = this.minimax(move, depth - 1, false);
maxEval = Math.max(maxEval, eval);
}
return maxEval;
} else {
let minEval = Infinity;
const moves = this.getPossibleMoves(board);
for (const move of moves) {
const eval = this.minimax(move, depth - 1, true);
minEval = Math.min(minEval, eval);
}
return minEval;
}
}
findBestMove(board: number[][]): { row: number; col: number } | null {
let bestVal = -Infinity;
let bestMove: { row: number; col: number } | null = null;
for (let i = 0; i < 3; i += 1) {
for (let j = 0; j < 3; j += 1) {
if (board[i][j] === 0) {
const newBoard = board.map((row) => [...row]);
newBoard[i][j] = 1; // AI 移动
const moveVal = this.minimax(newBoard, 3, false);
if (moveVal > bestVal) {
bestVal = moveVal;
bestMove = { row: i, col: j };
}
}
}
}
return bestMove;
}
}3. 遗传算法
ts
interface Individual {
genes: number[];
fitness: number;
}
class GeneticAlgorithm {
private populationSize: number;
private geneLength: number;
private mutationRate: number;
private crossoverRate: number;
private population: Individual[] = [];
constructor(populationSize: number = 100, geneLength: number = 10, mutationRate: number = 0.01, crossoverRate: number = 0.7) {
this.populationSize = populationSize;
this.geneLength = geneLength;
this.mutationRate = mutationRate;
this.crossoverRate = crossoverRate;
this.initializePopulation();
}
private initializePopulation(): void {
for (let i = 0; i < this.populationSize; i += 1) {
const genes = Array.from({ length: this.geneLength }, () => Math.random());
this.population.push({
genes,
fitness: this.calculateFitness(genes),
});
}
}
private calculateFitness(genes: number[]): number {
// 示例适应度函数:寻找所有基因值为 1 的个体
return genes.reduce((sum, gene) => sum + gene, 0);
}
evolve(generations: number = 100): Individual {
for (let gen = 0; gen < generations; gen += 1) {
this.population.sort((a, b) => b.fitness - a.fitness);
const newPopulation: Individual[] = [];
// 精英选择:保留最好的个体
newPopulation.push(...this.population.slice(0, Math.floor(this.populationSize * 0.1)));
// 生成新个体
while (newPopulation.length < this.populationSize) {
const parent1 = this.selectParent();
const parent2 = this.selectParent();
let child: Individual;
if (Math.random() < this.crossoverRate) {
child = this.crossover(parent1, parent2);
} else {
child = { genes: [...parent1.genes], fitness: 0 };
}
this.mutate(child);
child.fitness = this.calculateFitness(child.genes);
newPopulation.push(child);
}
this.population = newPopulation;
}
return this.population[0];
}
private selectParent(): Individual {
// 轮盘赌选择
const totalFitness = this.population.reduce((sum, ind) => sum + ind.fitness, 0);
let pick = Math.random() * totalFitness;
for (const individual of this.population) {
pick -= individual.fitness;
if (pick <= 0) {
return individual;
}
}
return this.population[0];
}
private crossover(parent1: Individual, parent2: Individual): Individual {
const crossoverPoint = Math.floor(Math.random() * this.geneLength);
const childGenes = [...parent1.genes.slice(0, crossoverPoint), ...parent2.genes.slice(crossoverPoint)];
return { genes: childGenes, fitness: 0 };
}
private mutate(individual: Individual): void {
for (let i = 0; i < this.geneLength; i += 1) {
if (Math.random() < this.mutationRate) {
individual.genes[i] = Math.random();
}
}
}
getBestIndividual(): Individual {
return this.population.reduce((best, current) => (current.fitness > best.fitness ? current : best));
}
}4. 蒙特卡洛树搜索 (MCTS)
ts
interface MCTSNode {
state: any;
parent?: MCTSNode;
children: MCTSNode[];
visits: number;
wins: number;
untriedMoves: any[];
}
class MonteCarloTreeSearch {
private root: MCTSNode;
constructor(initialState: any) {
this.root = {
state: initialState,
children: [],
visits: 0,
wins: 0,
untriedMoves: this.getPossibleMoves(initialState),
};
}
search(iterations: number = 1000): any {
for (let i = 0; i < iterations; i += 1) {
const node = this.selectNode();
const winner = this.simulateGame(node);
this.backpropagate(node, winner);
}
return this.getBestMove();
}
private selectNode(): MCTSNode {
let node = this.root;
while (node.untriedMoves.length === 0 && node.children.length > 0) {
node = this.uctSelect(node);
}
if (node.untriedMoves.length > 0) {
const move = node.untriedMoves.pop()!;
const newState = this.makeMove(node.state, move);
const childNode: MCTSNode = {
state: newState,
parent: node,
children: [],
visits: 0,
wins: 0,
untriedMoves: this.getPossibleMoves(newState),
};
node.children.push(childNode);
return childNode;
}
return node;
}
private uctSelect(node: MCTSNode): MCTSNode {
let bestChild: MCTSNode | null = null;
let bestValue = -Infinity;
for (const child of node.children) {
const uctValue = child.wins / child.visits + Math.sqrt((2 * Math.log(node.visits)) / child.visits);
if (uctValue > bestValue) {
bestValue = uctValue;
bestChild = child;
}
}
return bestChild!;
}
private simulateGame(node: MCTSNode): number {
let state = node.state;
let currentPlayer = 1;
while (!this.isGameOver(state)) {
const moves = this.getPossibleMoves(state);
const randomMove = moves[Math.floor(Math.random() * moves.length)];
state = this.makeMove(state, randomMove);
currentPlayer = 3 - currentPlayer; // 切换玩家
}
return this.getWinner(state);
}
private backpropagate(node: MCTSNode, winner: number): void {
let current: MCTSNode | undefined = node;
while (current) {
current.visits += 1;
if (winner === 1) {
// 假设 AI 是玩家 1
current.wins += 1;
}
current = current.parent;
}
}
private getBestMove(): any {
let bestChild: MCTSNode | null = null;
let bestVisits = -1;
for (const child of this.root.children) {
if (child.visits > bestVisits) {
bestVisits = child.visits;
bestChild = child;
}
}
return bestChild ? this.getMoveFromStates(this.root.state, bestChild.state) : null;
}
// 以下方法需要根据具体游戏实现
private getPossibleMoves(state: any): any[] {
// 返回可能的移动
return [];
}
private makeMove(state: any, move: any): any {
// 执行移动,返回新状态
return state;
}
private isGameOver(state: any): boolean {
// 检查游戏是否结束
return false;
}
private getWinner(state: any): number {
// 返回获胜者 (1 或 2)
return 0;
}
private getMoveFromStates(fromState: any, toState: any): any {
// 从状态变化推断移动
return null;
}
}5. 实现要点
- A* 使用启发式函数优化路径寻找。
- Minimax 探索游戏树找到最优移动。
- 遗传算法模拟进化过程。
- MCTS 通过随机模拟学习策略。
算法游戏JavaScript