AWK 帮助解决 Wordle 谜题

AWK 帮助解决 Wordle 谜题

我见过好几个文章描述基本的 Linux 命令(grep 和 regex)如何解决 Wordle 谜题。如果您不熟悉游戏,请查看本问题末尾的注释。我决定使用 awk 来达到这个目的。这是我的第一次尝试:

awk 'length($0)==5' /usr/share/dict/words | awk '!/\-|\x27|[A-Z]/'  | awk '!/[isbou]/' | awk '/a/&&/l/&&/e/&&/e/&&/t/'  | awk '/...a/' | cat -n

前两个 awk 从标准 Ubuntu 安装中的字典中生成 5 个字母的单词列表(不包括大写单词、连字符、撇号)。

awk '/a/&&/l/&&/e/&&/t/'

(对于黄色字母)过滤那些有字母的单词——在单词中但不在书写位置。在此示例中,字母 a、l、e、t

awk '!/[isbou]/'

(对于灰色字母)过滤掉包含任何这些字母的单词 - 在此示例中为 i、s、b、o、u

awk '/...a/'

(对于绿色字母)表示存在且位于正确位置的字母。

我决定使用 5 个字母的单词列表作为我的字典,以保持代码简单。您可以通过多种方式准备这样的列表。例如:

awk 'length($0)==5' /usr/share/dict/words | awk '!/\-|\x27|[A-Z]/' > fives.txt

或者

curl -s 'https://random-word-api.herokuapp.com/word?number=100000' | awk -v RS=',' '{gsub(/[]["]+/,"")}1' | awk 'length($i)==5' > fives.txt

将此文件( Fives.txt )放在主目录中,命令变得更短:

cat ~/fives.txt | awk '!/[isbou]/' | awk '/a/&&/l/&&/e/&&/e/&&/t/'  | awk '/...a/' | cat -n

这效果很好。但这可以缩短吗?如何使黄色字母的检查更加优雅,并且在编辑下一次猜测的命令时不易出现键入错误?

注意:规则非常简单:您需要在 6 次尝试中猜出隐藏的单词(通常是 5 个)。首先,只需在第一行输入任何单词即可。如果该字母被正确猜测并且位于正确的位置,它将以绿色突出显示,如果该字母在单词中,但在错误的位置 - 以黄色突出显示,如果该字母不在单词中,它将保留灰色的。你能在 6 次尝试中猜出隐藏的单词吗?

答案1

您可以通过组合所有 AWK 过滤器并合并cat功能来缩短此时间:

awk '!/[isbou]/ && /a/&&/l/&&/e/&&/t/ && /^...a.$/ { printf("%6d %s\n", ++i, $0) }' ~/fives.txt

我固定了绿色过滤器来专门检查五个位置。

我不会尝试进一步简化 AWK 部分,而是使用带有三个参数的 shell 脚本:灰色字母列表、黄色字母列表以及正确位置的绿色字母。

#!/bin/bash

awkcmd=""

if [[ ${#1} -gt 0 ]]; then
    awkcmd="${awkcmd}!/[$1]/ &&"
fi

if [[ ${#2} -gt 0 ]]; then
    for (( i=0; i < ${#2}; i++ )); do
    awkcmd="${awkcmd} /${2:$i:1}/ &&"
    done
fi

if [[ ${#3} -gt 0 ]]; then
    awkcmd="${awkcmd} /$3/"
else
    awkcmd="${awkcmd} 1"
fi

awkcmd="${awkcmd} { printf(\"%6d %s\n\", ++i, \$0) }"

awk "$awkcmd" ~/fives.txt

对于更通用的单词列表,请awkcmd="/^[a-z]{5}$/ &&"在第 3 行中使用。

答案2

一个非常粗糙的脚本(更像是一个存根)可以这样开始:

#!/bin/bash
conditions='/^[a-z]{5}$/'

while getopts "c:i:e:" opt; do case "${opt}" in
    c) conditions+=" && /^${OPTARG,,}/" ;;
    i) conditions+=$(sed 's|.| \&\& /&/|g' <<<"${OPTARG,,}") ;;
    e) conditions+=" && !/[${OPTARG,,}]/" ;;
esac; done
shift $((OPTIND-1))

awk "${conditions} { print toupper(\$0) }" /usr/share/dict/words

调用./wordle.sh -c "...a" -i "alet" -e "isbou"会产生:

CLEAT
FETAL
METAL
PETAL
PLEAT

本例中生成的 awk 为:

awk '/^[a-z]{5}$/ && /^...a/ && /a/ && /l/ && /e/ && /t/ && !/[isbou]/ { print toupper($0) }' /usr/share/dict/words

...对脚本的草率调用将是./wordle.sh -c...a -ialet -eisbou

当然,{ print toupper(\$0) }脚本部分完全是装饰性的,可以删除。它是由于 Wordle 选择在 gui 中仅使用大写字母而添加的。 :)

答案3

排除任何内容是没有意义的,因为您已经只有 5 个字母的单词,因此!/[isbou]/如果您随后检查/a/&&/l/&&/e/&&/e/&&/t/.接下来,重复/e/ && /e/是没有意义的,它不会检查两个e,它只检查一个,但会检查同一件事两次。如果您想查找包含两个e的案例,您需要/e.*e/.因此,将所有这些放在一起,这可能就是您想要的:

awk '/...a./ && /l/ &&/e.*e/ && /t/{print ++k,$0}' ~/fives.txt 

答案4

如果你只想写这个:

awk 'length($0)==5' /usr/share/dict/words | awk '!/[A-Z]/' | awk '/[:alpha:]/' | awk '!/[isbou]/' | awk '/a/&&/l/&&/e/&&/e/&&/t/'  | awk '/...a/' | cat -n

更简洁地说,它是:

awk '!/[A-Zisbou]/ && /l/&&/e/&&/t/ && /^...a.$/ {print ++n, $0}' /usr/share/dict/words

但如果你想排除包含非小写字母字符的“单词”,那就是:

awk '/^[[:lower:]]+$/ && /l/&&/e/&&/t/ && /^...a.$/ {print ++n, $0}' /usr/share/dict/words

或者如果您愿意:

awk '/l/&&/e/&&/t/ && /^[[:lower:]]{3}a[[:lower:]]$/ {print ++n, $0}' /usr/share/dict/words

相关内容