Last active
January 23, 2022 17:29
-
-
Save indyone/3211267ebacdbe5e48228592b81b05ba to your computer and use it in GitHub Desktop.
Wordle Solver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Net.Http; | |
using System.Threading.Tasks; | |
using Microsoft.Playwright; | |
public class Program | |
{ | |
public static async Task Main(string[] args) | |
{ | |
if (!File.Exists("words")) | |
{ | |
var httpClient = new HttpClient(); | |
var content = await httpClient.GetStringAsync("https://github.com/dwyl/english-words/raw/master/words_alpha.txt"); | |
File.WriteAllText("words", content); | |
} | |
var possibleWords = File.ReadAllLines("words").Where(w => w.Length == 5).Select(word => word.ToLowerInvariant().Trim()).ToArray(); | |
var startWords = new[] { "aargh", "aback", "abaft", "aboon", "about", "above", "abuse", "accel", "acute", "adieu", "adios", "admit", "adopt", "adown", "adult", "afoot", "afore", "afoul", "after", "again", "agape", "agent", "agogo", "agone", "agree", "ahead", "ahull", "alack", "alcon", "alife", "alike", "aline", "alive", "allow", "aloft", "aloha", "alone", "along", "aloof", "aloud", "alter", "amiss", "among", "amply", "amuck", "anger", "angry", "apace", "apart", "apple", "apply", "aptly", "arear", "argue", "arise", "aside", "askew", "aught", "avast", "avoid", "award", "aware", "awful", "badly", "bakaw", "bally", "basic", "basis", "basta", "beach", "begad", "begin", "below", "birth", "black", "blame", "bless", "blige", "blind", "block", "blood", "board", "bothe", "brain", "brava", "brave", "bravo", "bread", "break", "brief", "bring", "broad", "brown", "build", "burst", "buyer", "canny", "carry", "catch", "cause", "chain", "chair", "cheap", "check", "chest", "chief", "child", "china", "chook", "circa", "civil", "claim", "class", "clean", "clear", "climb", "clock", "close", "coach", "coast", "count", "court", "cover", "coyly", "crazy", "cream", "crime", "cross", "crowd", "crown", "cycle", "daily", "damme", "dance", "death", "depth", "dildo", "dimly", "dirty", "ditto", "doubt", "draft", "drama", "dream", "dress", "drily", "drink", "drive", "dryly", "dully", "early", "earth", "empty", "enemy", "enjoy", "enter", "entry", "equal", "error", "event", "exact", "exist", "extra", "faint", "faith", "false", "fatly", "fault", "feyly", "field", "fifth", "fight", "final", "first", "fitly", "floor", "focus", "force", "forte", "forth", "frame", "frank", "fresh", "frick", "front", "fruit", "fudge", "fully", "funny", "furth", "gaily", "gayly", "giant", "glass", "godly", "golly", "grand", "grant", "grass", "gratz", "great", "green", "gross", "group", "guess", "guide", "hallo", "haply", "happy", "harsh", "hasta", "havoc", "heart", "heavy", "hella", "hello", "hence", "henry", "horse", "hotel", "hotly", "house", "howay", "howdy", "hullo", "human", "huzza", "icily", "ideal", "image", "imply", "index", "infra", "inner", "input", "intl.", "issue", "japan", "jesus", "jildi", "joint", "jolly", "jones", "judge", "kapow", "knife", "large", "laugh", "laura", "laxly", "layer", "learn", "leave", "legal", "lento", "let’s", "level", "lewis", "light", "limit", "local", "loose", "lordy", "lowly", "lucky", "lunch", "madly", "magic", "major", "march", "marry", "match", "maybe", "mercy", "metal", "minor", "minus", "model", "money", "month", "moral", "motor", "mouth", "music", "naked", "nasty", "naval", "neath", "never", "newly", "night", "nobly", "noise", "north", "novel", "nurse", "occur", "oddly", "offer", "often", "one’s", "order", "other", "ought", "outer", "owner", "panel", "paper", "party", "peace", "peter", "phase", "phone", "piano", "piece", "pilot", "pitch", "place", "plain", "plane", "plant", "plate", "plonk", "plumb", "point", "pound", "power", "press", "price", "pride", "prime", "prior", "prize", "proof", "proud", "prove", "psych", "queen", "queer", "quick", "quiet", "quite", "radio", "raise", "ramen", "range", "rapid", "ratio", "reach", "ready", "redly", "refer", "relax", "reply", "right", "river", "roman", "rough", "round", "route", "royal", "rugby", "rural", "sadly", "salve", "scale", "scene", "scope", "score", "secus", "selly", "sense", "serve", "shall", "shape", "share", "sharp", "sheep", "sheer", "sheet", "shift", "shily", "shirt", "shock", "shoot", "short", "shyly", "sight", "silly", "simon", "since", "sixth", "skill", "skoal", "slash", "sleek", "sleep", "slyly", "small", "smart", "smile", "smith", "smoke", "sniff", "so-so", "solid", "solve", "sooey", "sorry", "sound", "south", "space", "spang", "spare", "speak", "speed", "spend", "spite", "split", "sport", "squad", "srsly", "staff", "stage", "stand", "stark", "start", "state", "steam", "steel", "steep", "stick", "still", "stock", "stone", "store", "stour", "study", "stuff", "style", "sugar", "super", "sweet", "table", "tally", "tanto", "taste", "teach", "terry", "thame", "thank", "theme", "there", "thiam", "thick", "thine", "thing", "think", "third", "throw", "thwap", "tight", "title", "today", "tomoz", "total", "touch", "tough", "tower", "track", "trade", "train", "treat", "trend", "trial", "truly", "trust", "truth", "twice", "twirp", "uncle", "under", "union", "unity", "until", "upper", "upset", "urban", "usual", "utter", "vague", "valid", "value", "verry", "video", "viola", "visit", "vital", "vivat", "voice", "wacko", "wahey", "wanly", "waste", "watch", "water", "wetly", "where", "which", "while", "whist", "white", "whole", "whose", "whoso", "wilma", "wirra", "woman", "woops", "world", "worry", "would", "wowie", "write", "wrong", "wryly", "yecch", "yeeha", "yeesh", "young", "yours", "youth", "yowch", "zowie" }; | |
var playwright = await Playwright.CreateAsync(); | |
var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = false }); | |
var context = await browser.NewContextAsync(new BrowserNewContextOptions { RecordVideoDir = "video" }); | |
var page = await context.NewPageAsync(); | |
await page.GotoAsync("https://www.powerlanguage.co.uk/wordle/"); | |
await page.ClickAsync("div.instructions:visible"); | |
var tries = 1; | |
var absent = new HashSet<char>(); | |
var present = new HashSet<(char Letter, int Index)>(); | |
var correct = new char?[] { null, null, null, null, null }; | |
var thisWord = startWords.PickRandomWord(); | |
while (tries <= 6) | |
{ | |
Console.WriteLine($"--- {tries} ---\n" + | |
$"Absent: {absent.Concat()}\n" + | |
$"Correct: {correct.ConcatCorrect()}\n" + | |
$"PossibleWords: {possibleWords.Length}\n" + | |
$"Word: {thisWord}"); | |
var accepted = await EnterWordAsync(thisWord, tries); | |
if (!accepted) | |
{ | |
await DeleteWordAsync(); | |
tries--; | |
} | |
else if (correct.All(c => c.HasValue)) | |
{ | |
var correctWord = correct.ConcatCorrect(); | |
Console.WriteLine($"Found it! The word is {correctWord}!"); | |
await page.ScreenshotAsync(new PageScreenshotOptions { Path = $"{DateTime.Now:yyyyMMdd}_{correctWord}.png" }); | |
Console.ReadLine(); | |
return; | |
} | |
possibleWords = possibleWords.Where(w => w != thisWord).Where(FilterPossibleWords).ToArray(); | |
if (possibleWords.Length == 0) | |
{ | |
Console.WriteLine($"Could not solve it this time :("); | |
return; | |
} | |
thisWord = possibleWords.PickRandomWord(); | |
present.Clear(); | |
tries++; | |
} | |
await page.CloseAsync(); | |
async Task<bool> EnterWordAsync(string word, int row) | |
{ | |
foreach (var letter in word) | |
{ | |
await page.ClickAsync($"#keyboard button[data-key='{letter}']"); | |
} | |
await page.PressAsync("#keyboard", "Enter"); | |
await Task.Delay(2000); | |
var rows = page.Locator("#board div.row").Nth(row - 1); | |
var tiles = await rows.Locator("div.tile").ElementHandlesAsync(); | |
var index = 0; | |
foreach (var tile in tiles) | |
{ | |
var letter = (await tile.InnerTextAsync()).Trim().ToLowerInvariant().FirstOrDefault(); | |
var state = await tile.GetAttributeAsync("data-state"); | |
switch (state) | |
{ | |
case "absent": | |
absent.Add(letter); | |
break; | |
case "present": | |
present.Add((letter, index)); | |
break; | |
case "correct": | |
correct[index] = letter; | |
break; | |
case"tbd": | |
return false; | |
} | |
index++; | |
} | |
return true; | |
} | |
async Task DeleteWordAsync() | |
{ | |
for (int i = 0; i <= 5; i++) await page.PressAsync("#keyboard", "Backspace"); | |
} | |
bool FilterPossibleWords(string word) | |
{ | |
var i = 0; | |
foreach (var w in word) | |
{ | |
if (absent.Contains(w)) return false; // if absent, skip | |
if (present.Contains((w, i))) return false; // if present in the same place, skip | |
if (correct[i] != null && correct[i] != w) return false; // if not corrent in the same place, skip | |
i++; | |
} | |
if (present.Count > 0 && !present.All(p => word.Contains(p.Letter))) // word should contain all present letters | |
{ | |
return false; | |
} | |
return true; | |
} | |
} | |
} | |
public static class Extensions | |
{ | |
private static readonly Random Random = new Random(); | |
public static string PickRandomWord(this string[] words) | |
{ | |
return words[Random.Next(0, words.Length - 1)]; | |
} | |
public static string Concat(this IEnumerable<char> characters) | |
{ | |
return string.Join(", ", characters); | |
} | |
public static string ConcatCorrect(this IEnumerable<char?> characters) | |
{ | |
return string.Join("", characters.Select(c => c ?? ' ')); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>net5.0</TargetFramework> | |
<Nullable>enable</Nullable> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="Microsoft.Playwright" Version="1.18.0" /> | |
</ItemGroup> | |
</Project> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment