Skip to content

Instantly share code, notes, and snippets.

@cyrillsemenov
Last active February 14, 2022 17:54
Show Gist options
  • Save cyrillsemenov/ffc4e13e219c1fe76eceecf92107ede0 to your computer and use it in GitHub Desktop.
Save cyrillsemenov/ffc4e13e219c1fe76eceecf92107ede0 to your computer and use it in GitHub Desktop.
Three guesses
let regex = /(?<=Ma=\[).+(?=\]\,Oa)/gm,
alphabet = {},
wordsList = [],
weights = {};
// Каждый день у игры новый хэш, его легко достать из объекта window,
// затем в тексте файла нужно найти переменную со списком слов
// и превратить ее из текста в массив
fetch(`main.${window.wordle.hash}.js`)
.then(response => response.text())
.then(data => wordsList = JSON.parse(`[${regex.exec(data)}]`))
.then(_ => getWeights ());
function getWeights () {
// Мы просто проходимся по каждой букве каждого слова
// и добавляем к счетчику в объекте alphabet
wordsList.forEach(w => {
w.split("").forEach(
l => {alphabet[l] = alphabet[l] ? alphabet[l]+1 : 1
})
});
// Было бы неплохо его (объект alphabet) отсортировать
var sortable = [];
for (var letter in alphabet) {
sortable.push([letter, alphabet[letter]]);
}
sortable.sort(function(a, b) {
return a[1] - b[1];
});
// Заполняем "таблицу мер и весов"
sortable.forEach((l, i) => {
weights[l[0]] = i
});
}
// Нам понадобятся само приложение, к которому можно обратиться
// через querySelector и переменные для подсказок
let app = document.querySelector("game-app"),
let firstBest = ["", 0],
secondBest = ["", 0],
thirdBest = ["", 0];
function getFirstGuess () {
// Теперь считаем суммарный вес каждого слова
wordsList.forEach(w => {
weight = 0;
// Причем для этого мы убираем повторяющиеся буквы,
// чтобы например слова с двумя «l» не были слишком тяжелыми -
// они нам не интересны
[...new Set(w.split(""))].forEach(l => {
weight += weights[l];
});
if (weight > firstBest[1]) {
firstBest = [w, weight]
}
});
// Выводим подсказку на табло
print(firstBest[0])
}
function getSecondGuess () {
//  Это я объясню позже
secondBest = ["", 0];
// Здесь нам понадобятся результаты предыдущей попытки
let evaulations = app.letterEvaluations;
// Снова считаем вес
wordsList.forEach(w => {
weight = 0;
[...new Set(w.split(""))].forEach(l => {
weight += weights[l];
});
// Но теперь с условием:
// в самом "тяжелом" слове не должно быть букв
// из первой подсказки и тех, которые как игра нам сказала,
// отсутствуют в правильном решении
unique = !firstBest[0]
.split("").some(el => {return w.includes(el)})
&& [...new Set(w.split(""))].every(el =>
evaulations[el] != "absent"
);
if (weight > secondBest[1] && unique) {
secondBest = [w, weight]
}
});
print(secondBest[0])
}
function getThirdGuess () {
// К этому вернемся позже
thirdBest = ["", 0];
evaulations = app.letterEvaluations;
// Ищем буквы, присутствующие в ответе, на своих и на чужих местах
let correct = [undefined, undefined, undefined, undefined, undefined],
wrongPlace = {};
app.boardState.forEach((w, i) => {
if (app.evaluations[i] != null) {
app.evaluations[i].forEach(
(e,j) => {
if (e == "correct") {
correct[j] = w[j]
} else if (e == "present") {
if (wrongPlace[w[j]]) {
wrongPlace[w[j]].push(j)
} else {
wrongPlace[w[j]] = [j]
}
}
})
}
}) // Ужас, но что поделать
// Тут я соберу все присутствующие и правильные буквы
// Начинается путаница с названиями переменных, прошу простить
let present = Object.entries(evaulations)
.filter(e =>
e[1] == "present" || e[1] == "correct"
).map(e => e[0]);
// Снова считаем массы
wordsList.forEach(w => {
weight = 0;
let letters = [...new Set(w.split(""))];
letters.forEach(l => {
weight += weights[l];
});
// Мама, не выгоняй меня из дома, я проверяю:
// 1. В слове нет отсутствующих в ответе букв
// 2. Каждая присутствующая буква есть в слове
// 3. Каждая правильная буква на правильной позиции
// 4. Все угаданные на не правильном месте буквы стоят
// в других местах
let passing = letters
.every(el => evaulations[el] != "absent")
&& present.every(el => w.includes(el))
&& w.split("")
.every((el, i) => correct[i] == el || correct[i] == undefined)
&& w.split("")
.every((el, i) => ![...wrongPlace[el]||[]].includes(i));
if (weight >= thirdBest[1] && passing) {
thirdBest = [w, weight]
}
});
print(thirdBest[0])
}
// Сперва нужно создать функцию print,
// чтобы выводить рехультат подсказок на табло
function print(w, enter=false) {
// Делается это с помощью KeyboardEvent'ов:
// именно так работает экранная клавиатура в игре
w.split("").forEach(l =>
window.dispatchEvent(
new KeyboardEvent('keydown', {'key': l})
));
if (enter) {
window.dispatchEvent(
new KeyboardEvent('keydown', {'key': 'Enter'})
);
}
}
// Еще одна помогайка, название говорит само за себя
function applyStyle(el, style){
Object.entries(style).forEach(p => {
el.style[p[0]] = p[1];
})
}
// Создадим контейнер для кнопок,
// а так же найдем куда его поместить (для этого придется
// залезть в сумеречную зону)
let suggestions = document.createElement("div"),
header = document.querySelector("game-app").shadowRoot
.querySelector("game-theme-manager > header");
// Накинем стиль на контейнер и кнопки
// Я делаю это здесь, а не в поле CSS потому что он находится
// в Shadow Root и CSS до него не доберется
applyStyle(suggestions, {
display: "grid",
gridTemplateColumns: "repeat(3, 1fr)",
gridGap: "5px",
justifyItems: "center",
padding: "10px",
margin: "auto",
boxSizing: "border-box",
maxWidth: "350px",
width: "100%",
fontSize: "1.5rem",
lineHeight: "2rem",
fontWeight: "bold",
verticalAlign: "middle",
color: "var(--tile-text-color)",
});
let buttonStyle = {
textAlign: "center",
width: "100%",
background: "#a52a2a"
};
// Чтобы не повторяться соорудил вот это
let buttons = [
["First", getFirstGuess],
["Second", getSecondGuess],
["Third", getThirdGuess]
].forEach(b => {
let el = document.createElement("div");
applyStyle(el, buttonStyle);
el.innerText = b[0];
el.onclick = b[1];
suggestions.appendChild(el);
});
// Добавили кнопки в интерфейс
header.after(suggestions);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment