Wordle-player - An optimal player for Wordle. Based on a rough understanding of information theory

Overview

Wordle Player

Just for fun, my attempt at making an optimal player for Wordle. Based on a rough understanding of information theory, and the idea that the best guess for a given turn is the one that gives you the most information.

Usage

wordle.py will feed you the guesses for a game of Wordle. If you run python wordle.py, you'll be launched into an interactive session, where the program outputs guesses and you just need to give it the outputs of each guess. Here's an example session where the word was PIANO:

$ python wordle.py
> TARES (15918 words)
? .y...
> ALOIN (999 words)
? y.yyy
> OMINA (5 words)
? y.ygy
> PIANO (1 words)
? ggggg

User input occurs on the lines starting with ?. Each . represents a letter that isn't in the word at all, a y represents a letter that is in the word but in the wrong place, and a g represents a letter in the right place. Along with the guess, the program outputs the number of words remaining that it can choose from.

The default wordlist has some pretty obscure words in it, which might not be valid for your game of Wordle. If so, just enter a blank line to fetch the next-best guess:

$ python wordle.py
> TARES (15918 words)
? .y...
> ALOIN (999 words)
? 
> ANOIL (998 words)
? 
> ANOLI (997 words)
...

You can also play with other word sizes using the -k flag:

$ python wordle.py -k 11
> PERCOLATING (37539 words)
? .yy.y.gggy.
> ENUMERATION (29 words)
...

Background: Entropy

From information theory, the entropy H(X) of a random variable X with n possible events is defined as:

H(X) = -sum{ P(x_i) * log2(P(x_i)) } for 1 <= i <= n

H(X) roughly means the amount of information* it takes to describe the outcome of X. For example, the entropy of a fair (50/50) coin flip is

H(fair coin) = -[1/2*log2(1/2) + 1/2*log2(1/2)] = 1.

But the entropy of flipping a horribly weighted coin is

H(unfair coin) = -[1/10*log2(1/10) + 9/10*log2(9/10)] = 0.47.

The fair coin takes exactly 1 bit to describe one of two outcomes, which makes sense. A flip of the unfair coin takes less information to describe because the same thing happens most of the time, and every now and then you'll need some extra bits to describe the more unlikely event.

*Measured in bits, since we use log2 - you can use any base you want, though.

Modeling a game of Wordle

Let's assume that every "target" word in Wordle is equally likely (drawn from a dictionary of k-letter words). When we play some word w, we get some outcome (in the form of each letter being green, yellow, or gray) - this will be our random variable X_w. By carefully choosing the word we play, we get different expected outcomes for X_w, and thus get different entropies. It's kind of like choosing the weights of our coin toss, but for a much more complex event. Our goal is to find the w that maximizes H(X_w), in order to make sure that when we observe the outcome, we gain as much information as possible.

To calculate H(X_w), we can check each possible target word in the dictionary and see what the outcome of playing w gets. There are 3^5 = 243 possible outcomes (different combinations of green, yellow, and gray), and each of these will get an associated probability depending on how many target words they map to. Calculating H(X_w) is then straightforward, we can use the formula from earlier:

H(X_w) = -sum{ P(r) * log2(P(r)) } for each possible outcome r.

Now we've chosen a word to play. When we play it, we'll observe the outcome of X_w. This will eliminate many words from our dictionary - we can throw out any word that wouldn't have lead to the observed outcome. Doing this iteratively should eventually lead to us either guessing the target word or leaving exactly 1 word in the dictionary.

Speed

This will work to find the optimal word, but it's an expensive calculation: given a dictionary with n words with k letters each, this will take O(k * n^2) time to run. I'm lazy so I wanted to find a fast approximation.

Instead of playing an entire word at a time, we can play a single character c in position i and observe its outcome Y_ci. Then, we can estimate H(X_w) by adding H(Y_ci) for each character of w. Now, this would give us exactly H(X_w) if each of Y_ci were independent random events, but this obviously isn't the case - for instance, there are way more words that start with SH___ than words that start with HS___. (Following this strategy to calculate H(X_w), the optimal starting word I got was SAREE, which isn't a great starter because it has two of the same letter. Playing E anywhere is a high-entropy play, because it's a very common letter.)

So instead, we can use this estimate as a filter, and just calculate the actual value of H(X_w) for the top a% of words. Using this strategy with a = 3, the optimal starting word I got for 5-letter words was TARES. I precomputed all of these for between 4 and 11 letters and saved them in starting_words.pickle. The wordle.py program uses these by default.

Pseudocode

k := number of letters per word
D := dictionary of k-letter words
a := the retry percentage we choose
H := the entropy function, which takes a distribution and returns its entropy

function guess(W) {
    n = size of W

    -- H(Y_ci)
    HY := empty map of (char, number) -> number
    for each c in the alphabet:
        for each i in [0, k):
            Y := map of possible outcomes (green, yellow, or gray) -> 0
            for each t in W:
                r := the outcome of playing c in position i on target word t
                Y[r] += 1/n
            HY[(c, i)] = H(Y)

    -- Estimated H(X_w)
    EHX := empty map of string -> number
    for each w in D:
        EHX[w] = sum of HY[(w[i], i)] for i in [0, k)
    
    -- Eligible words
    D' := a% of words in D with the highest EHX[w]

    -- Actual H(X_w)
    HX := empty map of string -> number
    for each w in D':
        X := map of possible outcomes -> 0
        for each t in W:
            r := the outcome of playing w on target word t
            X[r] += 1/n
        HX[w] = H(X)
    
    return the word in D' with the maximum HX[w]
}

References

Owner
Neill Johnston
Neill Johnston
DouZero_For_HLDDZ_FullAuto: 将DouZero用于欢乐斗地主自动化

DouZero_For_HLDDZ_FullAuto: 将DouZero用于欢乐斗地主自动化 本项目基于DouZero 和 DouZero_For_Happy_DouDiZhu 环境配置请移步项目DouZero 模型默认为ADP,更换模型请修改main.py中的模型路径 运行main.py即可 在原

322 Dec 25, 2022
A sprite ripper and converter for Com2uS' 2007 game Music World.

Music World Sprite Dumper This repository contains a python script reads an UNCOMPRESSED Music World pxo file and attempts to dump sprites from it. Th

Buu342 1 Mar 16, 2022
Console 2D GameEngine {C2DGE} [0.1.0]

Console 2D GameEngine {C2DGE} [0.1.0] By Grosse pastèque#6705 The Project's Goal : This projects was just a challenge so if you have bad reviews, it's

Big watermelon 1 Nov 06, 2021
Utility for generating randomizer datapacks for minecraft.

Minecraft Rando Utility for generating randomizer datapacks for minecraft. At the moment, it randomizes the following: Loot tables (including block dr

2 Dec 02, 2021
Box - a world simulator written in python with pygame

Box is a world simulator written in python with pygame. Features A world generation system A world editor Simulates creatures called boxlanders. You c

1up Community 3 Nov 14, 2022
Chess game for 2 players with UI

2-D Chess for 2 players Overview This is a simple 2D Chess game for 2 players using pygame library. Requirements To be able to run this game, you must

7 Apr 06, 2022
Algorithm to solve Wordle correctly 100% of the time within 6 attempts.

WordleSolver © Zulkarnine, 2022. Algorithm to solve Wordle 100% of the time within 6 attempts. You can go ahead and run main.py to run it for all 2315

Zulkarnine Mahmud 69 Dec 11, 2022
An optimal solution finder for the game Wordle, written in Python

wordle-solver: a nearly-optimal computer player for Wordle Wordle is an interesting word guessing game. This program plays it very well, taking only 3

4 Jun 13, 2022
PyCharge is an open-source computational electrodynamics Python simulator

PyCharge PyCharge is an open-source computational electrodynamics Python simulator that can calculate the electromagnetic fields and potentials genera

Matthew Filipovich 28 Jan 03, 2023
3D online shooter written on Panda3D 1.10.10 and Python 3.10.1

на русском itch.io page Droid Game 3D This is a fresh game that was developed using the Panda3D game engine and Python language in the PyCharm IDE (I

Marcus Kemaul 5 Jun 04, 2022
The main objective of the game is to destroy multiple waves of asteroids with the help of a blaster mounted on the spaceship.

Astronomia: let the exploration begin The main objective of the game is to destroy multiple waves of asteroids with the help of a blaster mounted on t

Aryan Nath 8 Nov 18, 2022
Ultimaze est un jeu en 2.5D, réalisé dans le cadre d'un projet de NSI.

Ultimaze Ultimaze est un jeu en 2.5D, réalisé dans le cadre d'un projet de NSI. La consigne était d'utiliser la librairie pygame pour créer un jeu en

parlabarbedeMerlin 3 Sep 17, 2022
A Neural Network based chess engine and GUI made with Python and Tensorflow/Keras.

Haxaw-Chess Haxaw: Haxaw is the Neural Network based chess engine made with Python and Tensorflow/Keras. Also uses the python-chess library. (WIP: Imp

Sarthak Bharadwaj 8 Dec 10, 2022
Creates a landscape with more accurate river generation in Minecraft version 1.12 using python.

MinecraftLandRiverGen View the following youtube video to set up a world that can interact with the python programs

23 Dec 25, 2022
Chess GUI

Lucas Chess Lucas Chess is a GUI of chess: To learn to play chess. To play chess against engines. Dependencies Python 2.7 PyQt4 PyAudio psutil Python

Lucas 322 Dec 20, 2022
Repository for the DecodED2 Game Project!

DecodED2 Game Project Hello everyone! Welcome to the GitHub Repository for DecodED2, as a start you'll need to clone this repository and make sure you

6 Sep 29, 2021
Minecraft-Bedrock-Modpack-Maker - Simple tool to combine multiple addons into one. Not finished

Minecraft-Bedrock-Modpack-Maker Simple tool to combine multiple addons into one. Not finished! Any contributing is welcome. How to use: Move all .mcpa

MivianCoin 1 Jan 06, 2022
WIP python/pygame 2D zombie shooter

2d-shooter project A single/multiplayer co-op survival small space zombie shooter. If you'd like to contribute, feel free to join the discord! INSTALL

36 Dec 08, 2022
Python module providing simple game networking

nethelper Python module providing simple game networking This module was originally created to facilitate a class on creating multiplayer games in Pyg

Cort 3 Jan 11, 2022
Jogo da velha escrito em python para 1 ou 2 jogadores

O Jogo da Velha Esse jogo da velha foi desenvolvido por mim em python, como um desafio de programar um jogo da velha em menos de 24 horas, no qual o c

Gabriel Castelo Branco 5 Jun 18, 2021