如何自动破解 Hardle
weilycoder · · 科技·工程
本做法仅保证在 Hardle.org 上有效。
其实我本来只想看看 Hardle 的单词表的。
断网后测试发现仍能正常判断单词是否合法,因此单词表一定被加载到本地了。
在删除缓存后重启请求网页,发现请求文件如下:
逐个检查后可以发现单词表藏在 TrashIcon.BbFlvf2K.js 文件下。
本来到这里已经结束了,大家不难利用这个词表写出一个自动破解 Hardle 的交互程序。但是紧跟着词表的是一个奇怪的 map:
考虑到 map 的键是日期格式,那么是个人都会猜测这玩意是答案列表。
经测试后的确如此。
并且这个表只列到 6.10.2027,就是 27 年 10 月 6 号,那大家也就只能再玩一年多 hardle 了。
希望作者记得及时更新吧。
附 Deepseek 生成的提取代码,注意代码输出包含当日答案。
:::info[Code]
"""
Hardle Word List Extraction Tool
Extract complete word list and daily answers from https://hardle.org/
"""
import re
import json
from datetime import datetime, date
from urllib.request import urlopen
# Hardle JS chunk URL
CHUNK_URL = "https://hardle.org/_app/immutable/chunks/TrashIcon.BbFlvf2K.js"
def fetch_js(url: str) -> str:
print(f"Downloading: {url}")
with urlopen(url) as resp:
data = resp.read().decode("utf-8")
print(f"Download complete: {len(data):,} bytes")
return data
def extract_word_list(text: str) -> list[str]:
match = re.search(r'ma=\[(?:"[a-z]+"(?:,"[a-z]+")*)\]', text)
if not match:
raise ValueError("Word list array not found!")
words = json.loads("[" + match.group(0).split("=[", 1)[1])
return words
def extract_answer_map(text: str) -> dict[str, str]:
start = text.index("ya=new Map([") + len("ya=new Map([")
depth = 1
i = start
while depth > 0 and i < len(text):
if text[i] == "[":
depth += 1
elif text[i] == "]":
depth -= 1
i += 1
map_str = text[start : i - 1]
entries = re.findall(r'\["(\d{1,2}\.\d{1,2}\.\d{4})","([a-z]+)"\]', map_str)
return {date_str: word for date_str, word in entries}
def get_today_answer(answer_map: dict[str, str]) -> tuple[str, str] | None:
today = date.today()
de_date = f"{today.day}.{today.month}.{today.year}"
word = answer_map.get(de_date)
if word:
return de_date, word
return None
def main():
print("=" * 60)
print(" Hardle Word List Extraction Tool")
print("=" * 60)
js = fetch_js(CHUNK_URL)
print("\nExtracting complete word list...")
word_list = extract_word_list(js)
print(f" Total {len(word_list):,} words")
with open("hardle_words.txt", "w", encoding="utf-8") as f:
f.write("\n".join(word_list))
print(" Saved to hardle_words.txt")
print("\nExtracting daily answers...")
answer_map = extract_answer_map(js)
sorted_dates = sorted(
answer_map.keys(),
key=lambda d: datetime.strptime(d, "%d.%m.%Y"),
)
print(f" Total {len(answer_map):,} answers")
print(f" Date range: {sorted_dates[0]} ~ {sorted_dates[-1]}")
with open("hardle_answers.json", "w", encoding="utf-8") as f:
json.dump(
{d: answer_map[d] for d in sorted_dates},
f,
indent=2,
ensure_ascii=False,
)
print(" Saved to hardle_answers.json")
print("\nToday's answer:")
today_info = get_today_answer(answer_map)
if today_info:
de_date, word = today_info
print(f" {de_date} → {word.upper()}")
else:
print(" Today's answer not found")
print("\nStatistics:")
print(f" Valid guess words: {len(word_list):,}")
print(f" Daily answers: {len(answer_map):,}")
print(f" Answer ratio: {len(answer_map) / len(word_list) * 100:.1f}%")
not_in_list = [w for w in answer_map.values() if w not in word_list]
if not_in_list:
print(f" {len(not_in_list)} answer(s) not in word list: {not_in_list}")
else:
print(" All answers are in the word list")
print("\n" + "=" * 60)
print(" Done!")
print("=" * 60)
if __name__ == "__main__":
main()
:::