返回

Wordle破译利器——遗传算法

人工智能

遗传算法:Wordle破译利器

在智力游戏中,"Wordle"无疑是风靡全球的佼佼者。这款每日文字谜题考验着我们的词汇量和逻辑推理能力,引无数玩家竞折腰。而如果你厌倦了常规猜谜,不妨尝试运用遗传算法,让它成为你的"作弊神器"。

遗传算法简介

遗传算法是一种受生物进化启发的优化算法。它通过模拟自然选择和遗传变异,不断迭代更新候选解,逐步逼近最优解。

遗传算法在Wordle中的应用

将遗传算法应用于Wordle,其基本原理如下:

  1. 初始化种群: 生成随机猜测单词,作为初始候选解种群。

  2. 计算适应度: 评估每个猜测单词与正确单词的相似度,以此作为适应度。

  3. 选择: 根据适应度,选择最相似的单词作为亲代。

  4. 交叉: 通过交换亲代基因(字母),生成新的后代单词。

  5. 变异: 随机改变后代单词的某个字母,引入多样性。

  6. 迭代: 重复上述步骤,直至找到最优解(正确单词)或达到最大迭代次数。

Java实现示例

以下是用Java实现的遗传算法代码示例:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class WordleSolver {

    private static final List<String> WORD_LIST = new ArrayList<>();  // 单词库
    private String targetWord;  // 目标单词
    private int populationSize;  // 种群大小
    private int maxIterations;  // 最大迭代次数
    private double crossoverProbability;  // 交叉概率
    private double mutationProbability;  // 变异概率

    public WordleSolver(String targetWord, int populationSize, int maxIterations, double crossoverProbability, double mutationProbability) {
        this.targetWord = targetWord;
        this.populationSize = populationSize;
        this.maxIterations = maxIterations;
        this.crossoverProbability = crossoverProbability;
        this.mutationProbability = mutationProbability;
    }

    public String solve() {
        // 初始化种群
        List<String> population = generateInitialPopulation();

        // 迭代直到找到目标单词或达到最大迭代次数
        for (int i = 0; i < maxIterations; i++) {
            // 计算每个个体的适应度
            List<Double> fitnesses = calculateFitnesses(population);

            // 根据适应度选择亲代
            List<String> parents = selectParents(population, fitnesses);

            // 交叉和变异生成后代
            List<String> offspring = crossoverAndMutate(parents);

            // 替换旧种群
            population = offspring;

            // 检查是否找到目标单词
            if (population.contains(targetWord)) {
                return targetWord;
            }
        }

        // 如果未找到目标单词,返回最优猜测
        return Collections.max(population, (s1, s2) -> calculateFitness(s1) - calculateFitness(s2));
    }

    // 初始化种群
    private List<String> generateInitialPopulation() {
        List<String> population = new ArrayList<>();
        for (int i = 0; i < populationSize; i++) {
            population.add(generateRandomWord());
        }
        return population;
    }

    // 生成随机单词
    private String generateRandomWord() {
        Random random = new Random();
        int index = random.nextInt(WORD_LIST.size());
        return WORD_LIST.get(index);
    }

    // 计算每个个体的适应度
    private List<Double> calculateFitnesses(List<String> population) {
        List<Double> fitnesses = new ArrayList<>();
        for (String word : population) {
            fitnesses.add(calculateFitness(word));
        }
        return fitnesses;
    }

    // 计算单个个体的适应度
    private double calculateFitness(String word) {
        int numCorrectLetters = 0;
        int numCorrectPositions = 0;
        for (int i = 0; i < word.length(); i++) {
            if (word.charAt(i) == targetWord.charAt(i)) {
                numCorrectPositions++;
            } else if (targetWord.contains(word.charAt(i))) {
                numCorrectLetters++;
            }
        }
        return numCorrectPositions * 10 + numCorrectLetters;
    }

    // 根据适应度选择亲代
    private List<String> selectParents(List<String> population, List<Double> fitnesses) {
        List<String> parents = new ArrayList<>();
        for (int i = 0; i < populationSize; i++) {
            int index1 = rouletteWheelSelection(fitnesses);
            int index2 = rouletteWheelSelection(fitnesses);
            parents.add(population.get(index1));
            parents.add(population.get(index2));
        }
        return parents;
    }

    // 轮盘赌选择
    private int rouletteWheelSelection(List<Double> fitnesses) {
        double totalFitness = 0;
        for (double fitness : fitnesses) {
            totalFitness += fitness;
        }

        Random random = new Random();
        double randomValue = random.nextDouble() * totalFitness;

        double currentFitness = 0;
        int index = 0;
        for (int i = 0; i < fitnesses.size(); i++) {
            currentFitness += fitnesses.get(i);
            if (currentFitness >= randomValue) {
                index = i;
                break;
            }
        }

        return index;
    }

    // 交叉和变异生成后代
    private List<String> crossoverAndMutate(List<String> parents) {
        List<String> offspring = new ArrayList<>();
        for (int i = 0; i < parents.size(); i += 2) {
            String parent1 = parents.get(i);
            String parent2 = parents.get(i + 1);

            // 交叉
            if (Math.random() < crossoverProbability) {
                int crossoverPoint = random