0%

第一届TQLCTF高校赛

第一届TQLCTF记录

1. 队伍信息

队伍名称:摸鱼即胜利
个人名称:hakkar0597
队友名称:lines
队伍方向分布: Crypto + Misc

2. 解题情况

签到两日游

3. 个人反思

客观上,题目有绝对难度,对应密码方向没出题可以理解。
实际上,策略还是有些失当。

  • 看到密码不知所云就过早放弃了(?结果上看好像也没错
  • 太上头了,除了时间分配问题外🤔,对现成代码的读取、应用能力差
  • 菜是原罪 😑

Wordle

What

img

规则

一个 5 位英语单词谜底,玩家可以随意提交一个5字母组成英语单词,但必须是字典里有的。

每一位字母会给一个颜色反馈。

  • 绿色 :说明答案里有这个字母、所在位置也正确;
  • 黄色 :说明答案里有这个字母、但不在这个位置;
  • 灰色 :说明答案里没有这个字母。

Why

做题,看到TQLCTF·Misc·Wordle

看的我色盲犯了😵‍💫

题目

image-20220222032744911

成分分析

  • allowed_guesses.txt

    如题,内容为所有允许猜测的单词

  • main.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    import os
    import random
    from flag import award

    random.seed(os.urandom(64))

    with open('allowed_guesses.txt', 'r') as f:
    allowed_guesses = set([x.strip() for x in f.readlines()])

    with open('valid_words.txt', 'r') as f:
    valid_words = [x.strip() for x in f.readlines()]


    MAX_LEVEL = 512
    GREEN = '\033[42m \033[0m'
    YELLOW = '\033[43m \033[0m'
    WHITE = '\033[47m \033[0m'

    def get_challenge():
    # id = random.getrandbits(32)
    # answer = valid_words[id % len(valid_words)]
    # return hex(id)[2:].zfill(8), answer

    # To prevent the disclosure of answer
    id = random.randrange(len(valid_words) * (2 ** 20))
    answer = valid_words[id % len(valid_words)]
    id = (id // len(valid_words)) ^ (id % len(valid_words))
    return hex(id)[2:].zfill(5), answer

    def check(answer, guess):
    answer_chars = []
    for i in range(5):
    if guess[i] != answer[i]:
    answer_chars.append(answer[i])
    result = []
    for i in range(5):
    if guess[i] == answer[i]:
    result.append(GREEN)
    elif guess[i] in answer_chars:
    result.append(YELLOW)
    answer_chars.remove(guess[i])
    else:
    result.append(WHITE)
    return ' '.join(result)

    def game(limit):
    round = 0
    while round < MAX_LEVEL:
    round += 1
    id, answer = get_challenge()
    print(f'Round {round}: #{id}')
    correct = False
    for _ in range(limit):
    while True:
    guess = input('> ')
    if len(guess) == 5 and guess in allowed_guesses:
    break
    print('Invalid guess')
    result = check(answer, guess)
    if result == ' '.join([GREEN] * 5):
    print(f'Correct! {result}')
    correct = True
    break
    else:
    print(f'Wrong! {result}')
    if not correct:
    print('You failed...')
    return round - 1

    return MAX_LEVEL


    def choose_mode():
    print('Choose gamemode:')
    print('0: Easy mode')
    print('1: Normal mode')
    print('2: Hard mode')
    print('3: Insane mode')
    # print('4: Expert mode')
    # print('-1: Osu! mode')
    mode = int(input('> '))
    assert 0 <= mode <= 3
    return mode

    if __name__ == '__main__':
    print('Guess the WORDLE in a few tries.')
    print('Each guess must be a valid 5 letter word.')
    print('After each guess, the color of the tiles will change to show how close your guess was to the word.')

    while True:
    mode = choose_mode()
    if mode == 0:
    limit = 999999999
    else:
    limit = 7 - mode
    final_level = game(limit)
    if final_level < MAX_LEVEL:
    pass
    else:
    print('You are the Master of WORDLE!')
    flag = award(mode, final_level)
    print(f'Here is you award: {flag}')
  • valid_words.txt

    有效的单词,即:谜底单词在这里面(没错,允许猜的有很多不可能是答案

服务器

nc 47.106.102.129 21480

靶机挂了,需要意会。

查找的脚本

跟服务器交互,本能的写出了,如下朴素的人工辅助脚本。

具体实现为:

  • 输入一个字母,在valid_words.txt中剔除没有这个字母的单词
  • 输入一个字母,删除含有这个字母的单词
  • 制定某个字母的位置,剔除在指定位置没有该字母的单词
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
data = open('./valid_words.txt', 'r')
data = data.read().split('\n')
tmp = 1
while tmp != '0':
tmp = input("请输入搜索的单词:")
if tmp == '0':
print("程序已关闭")
elif '-' in tmp: # -o
del_word = tmp.split('-')[-1]
# print(del_word, len(del_word))
# print(data)
data2 = []
for word in data:
if del_word in word:
pass
else:
data2.append(word)
data = data2
# print(data)
for i in data:
print(i)
print("共有{0}个".format(len(data)))
elif '[' in tmp: # d[1]
tmp = tmp.split('[')
word = tmp[0] # d
print(word)
print(tmp)
site = tmp[1][0] # 1
data2 = []
for i in data:
if i[int(site) - 1] == word:
data2.append(i)
data = data2
for i in data:
print(i)
print("共有{0}个".format(len(data)))
else:
if len(data) == 0:
data = open('./valid_words.txt', 'r')
data = data.read().split('\n')
data1 = data
data = []
for i in data1:
if tmp in i:
data.append(i)
for i in data:
print(i)
print("共有{0}个".format(len(data)))

统计

后来仔细思考,想知道什么单词开头能最有效率,于是想到了统计制定位字母出现的频率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
data = open('./valid_words.txt', 'r')
data = data.read().split('\n')
tmp = 1
while tmp != '0':
tmp = input("请输入搜索的单词:")
if tmp == '0':
print("程序已关闭")
elif '-' in tmp: # -o[3]
tmp = ''.join(tmp.split('-')).split("[")
# ['o', '3]']
del_word = tmp[0]
site = int(tmp[1][0])
# print(del_word, len(del_word))
# print(data)
data2 = []
for word in data:
if word[site-1] != del_word:
data2.append(word)
data = data2
# print(data)
for i in data:
print(i)
print("共有{0}个".format(len(data)))
elif '[' in tmp: # d[1]
tmp = tmp.split('[')
word = tmp[0] # d
print(word)
print(tmp)
site = tmp[1][0] # 1
data2 = []
for i in data:
if i[int(site) - 1] == word:
data2.append(i)
data = data2
for i in data:
print(i)
print("共有{0}个".format(len(data)))
elif tmp.isdigit():
# 1 -> 统计所有单词第一位的数据
site = int(tmp)
dict_letter = {}
for word in data:
if word[site -1] in dict_letter:
dict_letter[word[site -1]] += 1
else:
dict_letter[word[site -1]] = 1
dict_letter.items() # 得到: dict_items([('a', 1), ('c', 3), ('b', 2)])

L = list(dict_letter.items()) # 得到列表: L=[('a', 1), ('c', 3), ('b', 2)]
L.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
# x代表从L中遍历出的一个元组
# 得到: [('a', 1), ('b', 2), ('c', 3)]
for i in L:
print("字母{0} {1}次".format(i[0], i[1]))
print("已统计第 {0} 位字母的数据".format(site))

else:
# 存在 s
if len(data) == 0:
data = open('./valid_words.txt', 'r')
data = data.read().split('\n')
data1 = data
data = []
for i in data1:
if tmp in i:
data.append(i)
for i in data:
print(i)
print("共有{0}个".format(len(data)))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
请输入搜索的单词:1
字母z 4
字母y 18
字母q 32
字母j 38
字母u 42
字母k 45
字母i 48
字母n 67
字母o 67
字母v 89
字母e 94
字母h 144
字母w 159
字母l 184
字母r 198
字母g 199
字母m 212
字母d 219
字母a 221
字母f 252
字母t 260
字母p 280
字母b 318
字母c 337
字母s 563
已统计第 1 位字母的数据
请输入搜索的单词:2
字母j 2
字母z 2
字母q 6
字母f 9
字母g 14
字母x 16
字母k 17
字母v 23
字母b 23
字母s 31
字母y 32
字母d 33
字母m 49
字母c 54
字母w 56
字母p 80
字母t 107
字母n 120
字母h 195
字母l 290
字母u 316
字母r 377
字母i 441
字母e 493
字母o 615
字母a 689
已统计第 2 位字母的数据
请输入搜索的单词:3
字母q 3
字母j 5
字母h 19
字母z 28
字母x 30
字母y 37
字母f 39
字母k 43
字母w 57
字母b 80
字母v 94
字母p 97
字母g 106
字母d 115
字母c 123
字母m 125
字母s 177
字母t 193
字母u 241
字母l 266
字母e 306
字母n 307
字母r 336
字母o 359
字母i 418
字母a 486
已统计第 3 位字母的数据
请输入搜索的单词:4
字母x 3
字母j 3
字母y 20
字母z 27
字母b 48
字母w 50
字母f 51
字母h 55
字母v 57
字母u 120
字母p 125
字母m 129
字母g 131
字母k 136
字母d 162
字母o 165
字母c 179
字母i 207
字母a 217
字母s 223
字母r 268
字母l 286
字母n 311
字母t 324
字母e 793
已统计第 4 位字母的数据
请输入搜索的单词:5
字母z 5
字母x 12
字母u 12
字母b 14
字母w 22
字母i 28
字母f 31
字母c 34
字母g 47
字母m 51
字母p 60
字母o 96
字母k 119
字母a 124
字母h 158
字母n 167
字母l 178
字母r 265
字母d 291
字母t 322
字母y 403
字母e 618
字母s 1033
已统计第 5 位字母的数据

最后想了想,干脆一鼓作气,把所有的数据统计出来然后实时推荐。

思路如下:

  1. 易得:三个颜色中,绿色、黄色出现后,数据会剔除的特别快
  2. 意识到:白色最为让人无奈
  3. 朴素地想到:实时统计valid_words.txt中第一位到哪个字母出现的最多,然后是第二位哪个字母最多…直到第五位。
  4. valid_words.txt中尝试找到一个尽可能包含以上五个字母的单词
  5. 如此一来,就算是最不期望的白色,同样也可以最大化剔除、净化数据

用以上思路,借用上面的、还未有过任何输入的实验数据可得:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
字母s         563次
已统计第 1 位字母的数据

字母a 689次
已统计第 2 位字母的数据

字母a 486次
已统计第 3 位字母的数据

字母e 793次
已统计第 4 位字母的数据

字母s 1033次
已统计第 5 位字母的数据

valid_words.txt中,最有效用的开场单词可以是saaes,显然没有这个单词,但有sabes代替(事后发现sages也可

sabes

花了些时间,改了下辅助脚本

事后看,问题很大,逻辑不够明晰,其中对“在valid_words.txt中尝试找到一个尽可能包含以上五个字母的单词”实现不够完美

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# 统计第X位哪个字母出现最多次
def sum_l(site):
dict_letter = {}
for word in data:
if word[site - 1] in dict_letter:
dict_letter[word[site - 1]] += 1
else:
dict_letter[word[site - 1]] = 1
dict_letter.items() # 得到: dict_items([('a', 1), ('c', 3), ('b', 2)])
L = list(dict_letter.items()) # 得到列表: L=[('a', 1), ('c', 3), ('b', 2)]
L.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
return L
# x代表从L中遍历出的一个元组
# 得到: [('a', 1), ('b', 2), ('c', 3)]



data = open('./valid_words.txt', 'r')
data = data.read().split('\n')
tmp = 1
while tmp != '0':
tmp = input("请输入搜索的单词:")
if tmp == '0':
print("程序已关闭")
elif '-' in tmp: # -o[3]
tmp = ''.join(tmp.split('-')).split("[")
# ['o', '3]']
del_word = tmp[0]
site = int(tmp[1][0])
# print(del_word, len(del_word))
# print(data)
data2 = []
for word in data:
if word[site-1] != del_word:
data2.append(word)
data = data2
# print(data)
for i in data:
print(i)
print("共有{0}个".format(len(data)))
elif '[' in tmp: # d[1]
tmp = tmp.split('[')
word = tmp[0] # d
print(word)
print(tmp)
site = tmp[1][0] # 1
data2 = []
for i in data:
if i[int(site) - 1] == word:
data2.append(i)
data = data2
for i in data:
print(i)
print("共有{0}个".format(len(data)))
elif tmp.isdigit():
# 1 -> 统计所有单词第一位的数据
site = int(tmp)
dict_letter = {}
for word in data:
if word[site -1] in dict_letter:
dict_letter[word[site -1]] += 1
else:
dict_letter[word[site -1]] = 1
dict_letter.items() # 得到: dict_items([('a', 1), ('c', 3), ('b', 2)])

L = list(dict_letter.items()) # 得到列表: L=[('a', 1), ('c', 3), ('b', 2)]
L.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
# x代表从L中遍历出的一个元组
# 得到: [('a', 1), ('b', 2), ('c', 3)]
for i in L:
print("字母{0} {1}次".format(i[0], i[1]))
print("已统计第 {0} 位字母的数据".format(site))

# 用魔法来击败魔法
# 统计,自动推荐!
# L = [('a', 1), ('b', 2), ('c', 3)]
elif tmp == "get":
def get():
L1 = sum_l(1)
L2 = sum_l(2)
L3 = sum_l(3)
L4 = sum_l(4)
L5 = sum_l(5)
L_list = [L1, L2, L3, L4, L5]
quanzhong = {}
site = 1
for L in L_list:
if len(L) == 1: # 此位已确定,不予排序
pass
else:
quanzhong[L[-1][0]+str(site)] = L[-1][-1] # 把每一位最大权重的字母加到列表中like: {"c1": 3} ; "1" 指代第一位
site += 1
Q = list(quanzhong.items())
Q.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
print(Q)
# 得到列表: Q=[('a2', 1), ('c3', 4), ('b1', 4)]
data3 = []

# 找data有最高权重字母的
site = int(Q[-1][0][-1])
letter = Q[-1][0][0]
for word in data:
if word[site-1] == letter:
data3.append(word)
print(data3)

if len(Q) > 1:
# 找data3有第二高权重字母的
site = int(Q[-2][0][-1])
letter = Q[-2][0][0]
data4 = []
for word in data3:
if word[site-1] == letter:
data4.append(word)
if len(data4) == 0: # 没有满足的,返回第一权重的词群
print(data3)
elif len(Q) > 2: # 找data4有第三高权重字母的
site = int(Q[-3][0][-1])
letter = Q[-3][0][0]
data5 = []
for word in data4:
if word[site-1] == letter:
data5.append(word)
if len(data5) == 0: # 没有满足的,返回第二权重的词群
print(data4)
else:
print(data5) # 返回第三权重词群
else:
print(data3) # 就只有一个权重,返回之

get()





else:
# 存在 s
if len(data) == 0:
data = open('./valid_words.txt', 'r')
data = data.read().split('\n')
data1 = data
data = []
for i in data1:
if tmp in i:
data.append(i)
for i in data:
print(i)
print("共有{0}个".format(len(data)))



# sabes !!!

辅助脚本最终版

加了些注释,改了点小问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# 统计第X位哪个字母出现最多次
def sum_l(site):
dict_letter = {}
for word in data:
if word[site - 1] in dict_letter:
dict_letter[word[site - 1]] += 1
else:
dict_letter[word[site - 1]] = 1
dict_letter.items() # 得到: dict_items([('a', 1), ('c', 3), ('b', 2)])
L = list(dict_letter.items()) # 得到列表: L=[('a', 1), ('c', 3), ('b', 2)]
L.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
return L
# x代表从L中遍历出的一个元组
# 得到: [('a', 1), ('b', 2), ('c', 3)]



data = open('./valid_words.txt', 'r')
data = data.read().split('\n')
tmp = 1
while tmp != '0':
tmp = input("请输入搜索的单词:")
if tmp == '0':
print("程序已关闭")
elif '-' in tmp: # -o[3]
tmp = ''.join(tmp.split('-')).split("[")
# ['o', '3]']
del_word = tmp[0]
site = int(tmp[1][0])
# print(del_word, len(del_word))
# print(data)
data2 = []
for word in data:
if word[site-1] != del_word:
data2.append(word)
data = data2
# print(data)
for i in data:
print(i)
print("共有{0}个".format(len(data)))
elif '[' in tmp: # d[1]
tmp = tmp.split('[')
word = tmp[0] # d
print(word)
print(tmp)
site = tmp[1][0] # 1
data2 = []
for i in data:
if i[int(site) - 1] == word:
data2.append(i)
data = data2
for i in data:
print(i)
print("共有{0}个".format(len(data)))
elif tmp.isdigit():
# 1 -> 统计所有单词第一位的数据
site = int(tmp)
dict_letter = {}
for word in data:
if word[site -1] in dict_letter:
dict_letter[word[site -1]] += 1
else:
dict_letter[word[site -1]] = 1
dict_letter.items() # 得到: dict_items([('a', 1), ('c', 3), ('b', 2)])

L = list(dict_letter.items()) # 得到列表: L=[('a', 1), ('c', 3), ('b', 2)]
L.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
# x代表从L中遍历出的一个元组
# 得到: [('a', 1), ('b', 2), ('c', 3)]
for i in L:
print("字母{0} {1}次".format(i[0], i[1]))
print("已统计第 {0} 位字母的数据".format(site))

# 用魔法来击败魔法
# 统计,自动推荐!
# L = [('a', 1), ('b', 2), ('c', 3)]
elif tmp == "get":
def get():
L1 = sum_l(1)
L2 = sum_l(2)
L3 = sum_l(3)
L4 = sum_l(4)
L5 = sum_l(5)
L_list = [L1, L2, L3, L4, L5]
quanzhong = {}
site = 1
for L in L_list:
if len(L) == 1: # 此位已确定,不予排序
pass
else:
quanzhong[L[-1][0]+str(site)] = L[-1][-1] # 把每一位最大权重的字母加到列表中like: {"c1": 3} ; "1" 指代第一位
site += 1
Q = list(quanzhong.items())
Q.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
# 得到列表: Q=[('a2', 1), ('c3', 4), ('b1', 4)]
data3 = []

# 找data有最高权重字母的
site = int(Q[-1][0][-1])
letter = Q[-1][0][0]
for word in data:
if word[site-1] == letter:
data3.append(word)

if len(Q) > 1:
# 找data3有第二高权重字母的
site = int(Q[-2][0][-1])
letter = Q[-2][0][0]
data4 = []
for word in data3:
if word[site-1] == letter:
data4.append(word)
if len(data4) == 0: # 没有满足的,返回第一权重的词群
print(data3)
elif len(Q) > 2: # 找data4有第三高权重字母的
site = int(Q[-3][0][-1])
letter = Q[-3][0][0]
data5 = []
for word in data4:
if word[site-1] == letter:
data5.append(word)
if len(data5) == 0: # 没有满足的,返回第二权重的词群
print(data4)
elif len(Q) > 3:
site = int(Q[-4][0][-1])
letter = Q[-4][0][0]
data6 = []
for word in data5:
if word[site - 1] == letter:
data6.append(word)
if len(data6) == 0:
print(data5)
elif len(Q) > 4:
site = int(Q[-5][0][-1])
letter = Q[-5][0][0]
data7 = []
for word in data6:
if word[site - 1] == letter:
data7.append(word)
if len(data7) == 0:
print(data6)
else:
print(data7)
else:
print(data3) # 就只有一个权重,返回之
get()





else:
# 存在 s
if len(data) == 0:
data = open('./valid_words.txt', 'r')
data = data.read().split('\n')
data1 = data
data = []
for i in data1:
if tmp in i:
data.append(i)
for i in data:
print(i)
print("共有{0}个".format(len(data)))



# sabes !!!

🤔实话说,在我看错判定条件(以为完成个位数的关卡就可以得到flag)的情况下,一个色弱用其完成了八次(第九次手动取消了

回去审题,得知:

  • 模式选择

    • 模式 0

      每一关可以猜9999次

    • 模式 1

      每一关可以猜6(7-1)次

    • 模式 2

      每一关可以猜5(7-2)次

    • 模式 3

      每一关可以猜4(7-3)次

  • 完成次数

    • 猜测次数用完后,自动结束,返回当前模式下当前次数所能获得的奖励
    • 完成512次后,自动结束,并输出对应模式的奖励

很明显,正常人不能手动玩游戏玩出flag

但我当初写人工辅助脚本也是无奈之举,因为在模式选择里我向服务器发送“1”,死活没反应。

emo住了,过了三四个小时,实验了无数次后,发现该发送“1\n”

绝!

失败

在知道如何与靶机交互后,慌忙改了改原代码,开冲

慌忙的代价是,写的很差,调试、改了几小时,勉强能跑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import socket


# 求出现总次数、排序
def sum_l(site):
global data
dict_letter = {}
for word in data:
if word[site - 1] in dict_letter:
dict_letter[word[site - 1]] += 1
else:
dict_letter[word[site - 1]] = 1
dict_letter.items() # 得到: dict_items([('a', 1), ('c', 3), ('b', 2)])
L = list(dict_letter.items()) # 得到列表: L=[('a', 1), ('c', 3), ('b', 2)]
L.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
return L
# x代表从L中遍历出的一个元组
# 得到: [('a', 1), ('b', 2), ('c', 3)]


# 统计推荐
def get():
L1 = sum_l(1)
L2 = sum_l(2)
L3 = sum_l(3)
L4 = sum_l(4)
L5 = sum_l(5)
L_list = [L1, L2, L3, L4, L5]
quanzhong = {}
site1 = 1
for L in L_list:
if len(L) == 1: # 此位已确定,不予排序
pass
else:
quanzhong[L[-1][0] + str(site1)] = L[-1][-1] # 把每一位最大权重的字母加到列表中like: {"c1": 3} ; "1" 指代第一位
site1 += 1
Q = list(quanzhong.items())
Q.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
# 得到列表: Q=[('a2', 1), ('c3', 4), ('b1', 4)]
data3 = []

# 找data有最高权重字母的
print(Q)
site0 = int(Q[-1][0][-1])
letter = Q[-1][0][0]
for X in data:
if X[site0 - 1] == letter:
data3.append(X)

if len(Q) == 1:
return data3
elif len(Q) > 1:
# 找data3中有第二高权重字母的
site0 = int(Q[-2][0][-1])
letter = Q[-2][0][0]
data4 = []
for word1 in data3:
if word1[site0 - 1] == letter:
data4.append(word1)
if len(data4) == 0: # 没有满足的,返回第一权重的词群
return data3
elif len(Q) == 2:
return data4
elif len(Q) > 2: # 找data4有第三高权重字母的
site0 = int(Q[-3][0][-1])
letter = Q[-3][0][0]
data5 = []
for word2 in data4:
if word2[site0 - 1] == letter:
data5.append(word2)
if len(data5) == 0: # 没有满足的,返回第二权重的词群
return data4
elif len(Q) == 3:
return data5
elif len(Q) > 3:
site0 = int(Q[-4][0][-1])
letter = Q[-4][0][0]
data6 = []
for word3 in data5:
if word3[site0 - 1] == letter:
data6.append(word3)
if len(data6) == 0:
return data5
elif len(Q) == 4:
return data6
elif len(Q) > 4:
site0 = int(Q[-5][0][-1])
letter = Q[-5][0][0]
data7 = []
for word4 in data6:
if word4[site0 - 1] == letter:
data7.append(word4)
if len(data7) == 0:
return data6
else:
return data7
else:
return data3 # 就只有一个权重,返回之


HOST = '47.106.102.129'
PORT = 26389

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
print(s.recv(1024))

# 选择模式
s.send('1\n'.encode())
s_ = str(s.recv(1024))
print(s_)
for each in range(515):
state = 0
# 初始化数据
data = open('/Users/wenhui/Downloads/daf733a35279428eac1b7fcc43328fe8/valid_words.txt', 'r')
data = data.read().split('\n')
while state == 0:
# 获取推荐并发送
GET = get()
if GET:
print(GET)
tmp = GET[-1]
else:
tmp = data[-1]
print("get居然失效了!")
print(data)
s.send('{0}\n'.format(tmp).encode())

# 接受反馈
s_ = str(s.recv(1024))
print(s_)

if 'Correct!' in s_:
state = 1

# 针对错误过程
s_ = ''.join(s_.split("b'Wrong! "))
s_ = s_.split(r' \x1b[0m')
s_.pop()

# 人类的一小步
site = 1

for color in s_:
if '47m' in color: # 白色 : 在这个位置,这个字母不存在!
# tmp = saves
# 不在这个位置
del_word = tmp[site - 1] # "s"
data2 = []
for word in data:
if word[site - 1] != del_word:
data2.append(word)
data = data2
print("白色", len(data))

elif '43m' in color: # 黄色 : 字母存在,但不是这个位置
# 存在
data1 = data
data = []
for i in data1:
if tmp[site - 1] in i:
data.append(i)

# 不在这个位置
del_word = tmp[site - 1] # "s"
data2 = []
for word in data:
if word[site - 1] != del_word:
data2.append(word)
data = data2
print("黄色", len(data))

elif '42m' in color: # 绿色 : 字母存在 且 是在这个位置
# 存在且位置正确
word = tmp[site - 1] # d
data2 = []
for i in data:
if i[int(site) - 1] == word:
data2.append(i)
data = data2
print("绿色", len(data))
else:
print('啥也不是', color)
site += 1

结局是:选最简单但不无脑的模式1(6次机会),不能稳定完成 : (

改进后

忘记了改了什么,大概是逻辑细节修补一下?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
import socket


# 求出现总次数、排序
def sum_l(site):
global data
dict_letter = {}
for word in data:
if word[site - 1] in dict_letter:
dict_letter[word[site - 1]] += 1
else:
dict_letter[word[site - 1]] = 1
dict_letter.items() # 得到: dict_items([('a', 1), ('c', 3), ('b', 2)])
L = list(dict_letter.items()) # 得到列表: L=[('a', 1), ('c', 3), ('b', 2)]
L.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
return L
# x代表从L中遍历出的一个元组
# 得到: [('a', 1), ('b', 2), ('c', 3)]


# 统计推荐
def get():
L1 = sum_l(1)
L2 = sum_l(2)
L3 = sum_l(3)
L4 = sum_l(4)
L5 = sum_l(5)


L_list = [L1, L2, L3, L4, L5]
quanzhong = {}
site1 = 1
for L in L_list:
if len(L) == 1: # 此位已确定,不予排序
pass
else:
quanzhong[L[-1][0] + str(site1)] = L[-1][-1] # 把每一位最大权重的字母加到列表中like: {"c1": 3} ; "1" 指代第一位
site1 += 1
Q = list(quanzhong.items())
Q.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
print("Q", Q)
# 得到列表: Q=[('a2', 1), ('c3', 4), ('b1', 4)]

# 位权最高
data_01 = []
for each_word in data:
if each_word[int(Q[-1][0][1]) - 1] == Q[-1][0][0]:
data_01.append(each_word)
print(data_01)
if len(Q) == 1:
# [('b1', 4)]
return data_01[-1]
elif len(Q) == 2:
# [('c3', 4), ('b1', 4)]]
data_02 = []
for each_word in data_01:
if each_word[int(Q[-2][0][1]) - 1] == Q[-2][0][0]:
data_02.append(each_word)
else:
pass
if len(data_02) != 0:
return data_02[-1]
else:
return data_01[-1]
elif len(Q) == 3:
# [('a2', 1), ('c3', 4), ('b1', 4)]
data_02 = []
for each_word in data_01:
if each_word[int(Q[-2][0][1]) - 1] == Q[-2][0][0]:
data_02.append(each_word)
else:
pass

if len(data_02) == 0:
for each_word in data_01:
if each_word[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_02.append(each_word)
else:
pass
if len(data_02) != 0:
return data_02[-1]
else:
return data_01[-1]
else:
data_03 = []
for each_word in data_02:
if each_word[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_03.append(each_word)
else:
pass
if len(data_03) == 0:
return data_02[-1]
else:
return data_03[-1]
elif len(Q) == 4:
data_02 = []
for each_word in data_01:
if each_word[int(Q[-2][0][1]) - 1] == Q[-2][0][0]:
data_02.append(each_word)
else:
pass
if len(data_02) == 0:
data_03 = []
for each in data_01:
if each[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_03.append(each)
else:
pass
if len(data_03) == 0:
data_04 = []
for each_word in data_01:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
return data_01[-1]
else:
return data_04[-1]
else:
data_04 = []
for each_word in data_03:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
return data_03[-1]
else:
return data_04[-1]
else:
data_03 = []
for each_word in data_02:
if each_word[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_03.append(each_word)
else:
pass
if len(data_03) == 0:
data_04 = []
for each_word in data_02:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
return data_02[-1]
else:
return data_04[-1]
else:
data_04 = []
for each_word in data_03:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
return data_03[-1]
else:
return data_04[-1]
elif len(Q) == 5:
# [('a2', 1), ('c3', 4), ('b1', 4), ('z4', 5), (w4", 8)]
data_02 = []
for each_word in data_02:
if each_word[int(Q[-2][0][1]) - 1] == Q[-2][0][0]:
data_02.append(each_word)
else:
pass
if len(data_02) == 0:
data_03 = []
for each_word in data_01:
if each_word[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_03.append(each_word)
else:
pass
if len(data_03) == 0:
data_04 = []
for each_word in data_01:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
data_05 = []
for each_word in data_01:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_01[-1]
else:
return data_05[-1]
else:
data_05 = []
for each_word in data_04:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_04[-1]
else:
return data_05[-1]
else:
data_04 = []
for each_word in data_03:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
data_05 = []
for each_word in data_03:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_03[-1]
else:
return data_05[-1]
else:
data_05 = []
for each_word in data_04:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_04[-1]
else:
return data_05[-1]
else: # data2 != 0
data_03 = []
for each_word in data_02:
if each_word[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_03.append(each_word)
else:
pass
if len(data_03) == 0:
data_04 = []
for each_word in data_02:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
data_05 = []
for each_word in data_02:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_02[-1]
else:
return data_05[-1]
else:
data_05 = []
for each_word in data_04:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_04[-1]
else:
return data_05[-1]
else: # data3 != 0
data_04 = []
for each_word in data_03:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
data_05 = []
for each_word in data_03:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_03[-1]
else:
return data_05[-1]
else: # data4 != 0
data_05 = []
for each_word in data_04:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_04[-1]
else:
return data_05[-1]

















HOST = '47.106.102.129'
PORT = 26389

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
print(s.recv(1024))

# 选择模式
s.send('1\n'.encode())
s_ = str(s.recv(1024))
print(s_)
for each in range(515):
state = 0
# 初始化数据
data = open('/Users/wenhui/Downloads/daf733a35279428eac1b7fcc43328fe8/valid_words.txt', 'r')
data = data.read().split('\n')
while state == 0:
# 获取推荐并发送
GET = get()
if GET:
print(GET)
tmp = GET
else:
tmp = data[-1]
print("get居然失效了!")
print(data)
s.send('{0}\n'.format(tmp).encode())

# 接受反馈
s_ = str(s.recv(1024))
print(s_)

if 'Correct!' in s_:
state = 1

# 针对错误过程
s_ = ''.join(s_.split("b'Wrong! "))
s_ = s_.split(r' \x1b[0m')
s_.pop()

# 人类的一小步
site = 1

for color in s_:
if '47m' in color: # 白色 : 在这个位置,这个字母不存在!
# tmp = saves
# 不在这个位置
del_word = tmp[site - 1] # "s"
data2 = []
for word in data:
if word[site - 1] != del_word:
data2.append(word)
data = data2
print("白色", len(data))

elif '43m' in color: # 黄色 : 字母存在,但不是这个位置
# 存在
data1 = data
data = []
for i in data1:
if tmp[site - 1] in i:
data.append(i)

# 不在这个位置
del_word = tmp[site - 1] # "s"
data2 = []
for word in data:
if word[site - 1] != del_word:
data2.append(word)
data = data2
print("黄色", len(data))

elif '42m' in color: # 绿色 : 字母存在 且 是在这个位置
# 存在且位置正确
word = tmp[site - 1] # d
data2 = []
for i in data:
if i[int(site) - 1] == word:
data2.append(i)
data = data2
print("绿色", len(data))
else:
print('啥也不是', color)
site += 1

结局是,还是过不去模式1

元音选择

想到,对“在valid_words.txt中尝试找到一个尽可能包含以上五个字母的单词”的实现中,往往是获得一个列表,其中的单词还可以在进一步筛选

  • 盲猜答案单词相对常见不生僻
  • 统计列表中每一个单词含有的元音字母、排序、选择含元音最多的

期间还重写了 get() 函数(即:实现统计并推荐单词的函数。很粗暴的条件判定罗列,当时没心思想是否有更巧妙的编程方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
import socket


# 求出现总次数、排序
def sum_l(site):
global data
dict_letter = {}
for word in data:
if word[site - 1] in dict_letter:
dict_letter[word[site - 1]] += 1
else:
dict_letter[word[site - 1]] = 1
dict_letter.items() # 得到: dict_items([('a', 1), ('c', 3), ('b', 2)])
L = list(dict_letter.items()) # 得到列表: L=[('a', 1), ('c', 3), ('b', 2)]
L.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
return L
# x代表从L中遍历出的一个元组
# 得到: [('a', 1), ('b', 2), ('c', 3)]


# 统计推荐
def get():
if len(data) == 1:
return data
L1 = sum_l(1)
L2 = sum_l(2)
L3 = sum_l(3)
L4 = sum_l(4)
L5 = sum_l(5)

L_list = [L1, L2, L3, L4, L5]
quanzhong = {}
site1 = 1
for L in L_list:
if len(L) == 1: # 此位已确定,不予排序
pass
else:
quanzhong[L[-1][0] + str(site1)] = L[-1][-1] # 把每一位最大权重的字母加到列表中like: {"c1": 3} ; "1" 指代第一位
site1 += 1
Q = list(quanzhong.items())
Q.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
print("Q", Q)
# 得到列表: Q=[('a2', 1), ('c3', 4), ('b1', 4)]

# 位权最高
data_01 = []
for each_word in data:
if each_word[int(Q[-1][0][1]) - 1] == Q[-1][0][0]:
data_01.append(each_word)
print(data_01)
if len(Q) == 1:
# [('b1', 4)]
return data_01
elif len(Q) == 2:
# [('c3', 4), ('b1', 4)]]
data_02 = []
for each_word in data_01:
if each_word[int(Q[-2][0][1]) - 1] == Q[-2][0][0]:
data_02.append(each_word)
else:
pass
if len(data_02) != 0:
return data_02
else:
return data_01
elif len(Q) == 3:
# [('a2', 1), ('c3', 4), ('b1', 4)]
data_02 = []
for each_word in data_01:
if each_word[int(Q[-2][0][1]) - 1] == Q[-2][0][0]:
data_02.append(each_word)
else:
pass

if len(data_02) == 0:
for each_word in data_01:
if each_word[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_02.append(each_word)
else:
pass
if len(data_02) != 0:
return data_02
else:
return data_01
else:
data_03 = []
for each_word in data_02:
if each_word[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_03.append(each_word)
else:
pass
if len(data_03) == 0:
return data_02
else:
return data_03
elif len(Q) == 4:
data_02 = []
for each_word in data_01:
if each_word[int(Q[-2][0][1]) - 1] == Q[-2][0][0]:
data_02.append(each_word)
else:
pass
if len(data_02) == 0:
data_03 = []
for each in data_01:
if each[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_03.append(each)
else:
pass
if len(data_03) == 0:
data_04 = []
for each_word in data_01:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
return data_01
else:
return data_04
else:
data_04 = []
for each_word in data_03:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
return data_03
else:
return data_04
else:
data_03 = []
for each_word in data_02:
if each_word[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_03.append(each_word)
else:
pass
if len(data_03) == 0:
data_04 = []
for each_word in data_02:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
return data_02
else:
return data_04
else:
data_04 = []
for each_word in data_03:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
return data_03
else:
return data_04
elif len(Q) == 5:
# [('a2', 1), ('c3', 4), ('b1', 4), ('z4', 5), (w4", 8)]
data_02 = []
for each_word in data_02:
if each_word[int(Q[-2][0][1]) - 1] == Q[-2][0][0]:
data_02.append(each_word)
else:
pass
if len(data_02) == 0:
data_03 = []
for each_word in data_01:
if each_word[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_03.append(each_word)
else:
pass
if len(data_03) == 0:
data_04 = []
for each_word in data_01:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
data_05 = []
for each_word in data_01:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_01
else:
return data_05
else:
data_05 = []
for each_word in data_04:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_04
else:
return data_05
else:
data_04 = []
for each_word in data_03:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
data_05 = []
for each_word in data_03:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_03
else:
return data_05
else:
data_05 = []
for each_word in data_04:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_04
else:
return data_05
else: # data2 != 0
data_03 = []
for each_word in data_02:
if each_word[int(Q[-3][0][1]) - 1] == Q[-3][0][0]:
data_03.append(each_word)
else:
pass
if len(data_03) == 0:
data_04 = []
for each_word in data_02:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
data_05 = []
for each_word in data_02:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_02
else:
return data_05
else:
data_05 = []
for each_word in data_04:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_04
else:
return data_05
else: # data3 != 0
data_04 = []
for each_word in data_03:
if each_word[int(Q[-4][0][1]) - 1] == Q[-4][0][0]:
data_04.append(each_word)
else:
pass
if len(data_04) == 0:
data_05 = []
for each_word in data_03:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_03
else:
return data_05
else: # data4 != 0
data_05 = []
for each_word in data_04:
if each_word[int(Q[-5][0][1]) - 1] == Q[-5][0][0]:
data_05.append(each_word)
else:
pass
if len(data_05) == 0:
return data_04
else:
return data_05


HOST = '47.106.102.129'
PORT = 49472

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
print(s.recv(1024))

# 选择模式
s.send('1\n'.encode())
s_ = str(s.recv(1024))
print(s_)

for each in range(515):
state = 0
# 初始化数据
data = open('/Users/wenhui/Downloads/daf733a35279428eac1b7fcc43328fe8/valid_words.txt', 'r')
data = data.read().split('\n')
while state == 0:
# 获取推荐并发送
GET = get()
if GET:
# GET is a list of words
# 进行元音字母筛选
YuanYin = "aeiou" # 定义元音字母
dict_data = {} # 记录元音权重
if len(GET) == 1:
tmp = GET[-1]
else:
for word in GET:
for letter in word:
if letter in YuanYin:
if word in dict_data:
dict_data[word] += 1
else:
dict_data[word] = 1
Y = list(dict_data.items())
Y.sort(key=lambda x: x[1], reverse=False) # 按列表中,每一个元组的第二个元素从小到大排序。
# [('axxxx', 1), ('bxxxx', 2), ('cxxxx', 3)]
tmp = Y[-1][0]
print(tmp)
else:
tmp = data[-1]
print("get居然失效了!")
print(data)
s.send('{0}\n'.format(tmp).encode())

# 接受反馈
s_ = str(s.recv(1024))
print(s_)

if 'Correct!' in s_:
state = 1
else:
pass

# 针对错误过程
s_ = ''.join(s_.split("b'Wrong! "))
s_ = s_.split(r' \x1b[0m')
s_.pop()

# 人类的一小步
site = 1

for color in s_:
if '47m' in color: # 白色 : 在这个位置, 这个字母不存在!
# tmp = saves
# 不在这个位置
del_word = tmp[site - 1] # "s"
data2 = []
for word in data:
if word[site - 1] != del_word:
data2.append(word)
else:
pass
data = data2
print("白色", len(data))

elif '43m' in color: # 黄色 : 字母存在,但不是这个位置
# 存在
data1 = data
data = []
for i in data1:
if tmp[site - 1] in i:
data.append(i)

# 不在这个位置
del_word = tmp[site - 1] # "s"
data2 = []
for word in data:
if word[site - 1] != del_word:
data2.append(word)
data = data2
print("黄色", len(data))

elif '42m' in color: # 绿色 : 字母存在 且 是在这个位置
# 存在且位置正确
word = tmp[site - 1] # d
data2 = []
for i in data:
if i[int(site) - 1] == word:
data2.append(i)
data = data2
print("绿色", len(data))
else:
print('啥也不是', color)
site += 1

测试数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Q [('a3', 486), ('s1', 563), ('a2', 689), ('e4', 793), ('s5', 1033)]
['floss', 'crass', 'abyss', 'rebus', 'truss', 'focus', 'fetus', 'glass', 'class', 'chaos', 'dross', 'cress', 'bless', 'bliss', 'brass', 'cross', 'amass', 'bonus', 'locus', 'grass', 'ethos', 'humus', 'basis', 'guess', 'lupus', 'torus', 'minus', 'dress', 'amiss', 'mucus', 'gross', 'gloss', 'virus', 'chess', 'ficus', 'press', 'years', 'words', 'hands', 'works', 'means', 'times', 'terms', 'seems', 'miles', 'comes', 'hours', 'makes', 'books', 'knows', 'trees', 'parts', 'tears', 'lines', 'takes', 'girls', 'gives', 'lives', 'looks', 'walls', 'steps', 'cases', 'names', 'forms', 'heads', 'ideas', 'ships', 'weeks', 'sides', 'facts', 'hills', 'faces', 'birds', 'tells', 'rules', 'wants', 'hopes', 'woods', 'minds', 'yours', 'shows', 'rocks', 'notes', 'needs', 'lands', 'stars', 'rooms', 'knees', 'doors', 'goods', 'yards', 'temps', 'souls', 'calls', 'plans', 'pages', 'views', 'signs', 'kinds', 'kings', 'links', 'files', 'banks', 'loves', 'wings', 'turns', 'waves', 'towns', 'corps', 'finds', 'costs', 'boats', 'cries', 'sorts', 'falls', 'gates', 'bones', 'trois', 'winds', 'fears', 'wives', 'holds', 'roads', 'gifts', 'marks', 'pains', 'walks', 'folks', 'poets', 'shoes', 'deeds', 'bears', 'feels', 'poems', 'plays', 'keeps', 'songs', 'leads', 'limbs', 'tones', 'grows', 'ranks', 'tales', 'boots', 'seats', 'fires', 'jours', 'cents', 'roses', 'roots', 'pious', 'wages', 'blows', 'cares', 'rises', 'ruins', 'types', 'lords', 'dates', 'homes', 'drops', 'likes', 'cards', 'races', 'codes', 'taxes', 'ashes', 'bells', 'heels', 'evils', 'bands', 'acres', 'mains', 'flies', 'seeds', 'sites', 'bills', 'holes', 'sails', 'rings', 'boxes', 'fools', 'veins', 'opens', 'sends', 'mines', 'paths', 'moves', 'shops', 'tents', 'backs', 'bonds', 'games', 'debts', 'spots', 'balls', 'crops', 'monks', 'lamps', 'hears', 'robes', 'skies', 'draws', 'votes', 'rests', 'brows', 'reads', 'talks', 'horns', 'apres', 'texts', 'genus', 'locks', 'posts', 'funds', 'tools', 'paces', 'fails', 'ports', 'rates', 'vices', 'wears', 'skins', 'items', 'seeks', 'lakes', 'sales', 'meets', 'meals', 'suits', 'flows', 'reeds', 'roofs', 'beams', 'cells', 'pipes', 'folds', 'maids', 'mules', 'reins', 'edges', 'nails', 'tries', 'cakes', 'rites', 'sings', 'hosts', 'hangs', 'coats', 'goals', 'modes', 'loses', 'pines', 'heaps', 'fills', 'forts', 'lions', 'lungs', 'sands', 'halls', 'farms', 'rains', 'hints', 'poles', 'ropes', 'rolls', 'males', 'shots', 'stops', 'clubs', 'lists', 'flags', 'curls', 'weeds', 'tends', 'palms', 'sexes', 'users', 'oaths', 'beads', 'herds', 'vines', 'sighs', 'helps', 'peaks', 'coins', 'hoofs', 'pairs', 'beans', 'coups', 'goats', 'spurs', 'gains', 'moods', 'spies', 'hymns', 'fowls', 'burns', 'mills', 'tails', 'mists', 'ducks', 'waits', 'caves', 'tasks', 'claws', 'twins', 'idols', 'wills', 'dares', 'sizes', 'risks', 'stems', 'tests', 'seals', 'sinks', 'carts', 'deals', 'noses', 'knots', 'areas', 'fists', 'plots', 'drugs', 'wines', 'pools', 'cords', 'rails', 'stays', 'kills', 'lifts', 'worms', 'masts', 'decks', 'pangs', 'toils', 'loads', 'peers', 'longs', 'baths', 'tides', 'tints', 'atoms', 'wares', 'slips', 'rents', 'feats', 'twigs', 'lasts', 'casts', 'snows', 'sects', 'cours', 'lanes', 'wells', 'joins', 'bases', 'vases', 'chaps', 'bolts', 'irons', 'lambs', 'leaps', 'gowns', 'sages', 'bends', 'hurts', 'silks', 'crews', 'bulls', 'lacks', 'verbs', 'traps', 'mates', 'meats', 'feeds', 'darts', 'flats', 'tubes', 'units', 'pours', 'trips', 'antes', 'yells', 'hooks', 'nouns', 'louis', 'ferns', 'fumes', 'sheds', 'foods', 'isles', 'saves', 'forks', 'dites', 'teams', 'cooks', 'deres', 'sacks', 'frogs', 'wakes', 'reefs', 'asses', 'loans', 'binds', 'germs', 'fines', 'crows', 'salts', 'bowls', 'jests', 'sells', 'downs', 'babes', 'dents', 'panes', 'wilds', 'yolks', 'loins', 'stirs', 'veils', 'tunes', 'lumps', 'repos', 'sakes', 'pulls', 'tiles', 'barns', 'aunts', 'crags', 'casks', 'cures', 'alias', 'noirs', 'scars', 'morts', 'ponds', 'bales', 'gales', 'lends', 'foxes', 'picks', 'urges', 'shuts', 'socks', 'parks', 'odors', 'gases', 'lawns', 'tufts', 'fixes', 'soles', 'gusts', 'coils', 'masks', 'packs', 'doves', 'dolls', 'wards', 'puffs', 'dukes', 'shews', 'myths', 'fangs', 'belts', 'idees', 'slabs', 'fates', 'chefs', 'moons', 'prays', 'leans', 'eaves', 'whims', 'whips', 'manos', 'chips', 'domes', 'wraps', 'pumps', 'dregs', 'jumps', 'wiles', 'roars', 'soils', 'raids', 'acids', 'tiers', 'tanks', 'canes', 'bombs', 'stets', 'spars', 'pears', 'swans', 'tours', 'omens', 'cocks', 'pesos', 'clans', 'melts', 'bards', 'moths', 'deeps', 'dears', 'plums', 'hawks', 'moors', 'bites', 'docks', 'serfs', 'oasis', 'laces', 'fades', 'weeps', 'lusts', 'glows', 'pikes', 'chums', 'lotus', 'cuffs', 'barks', 'tires', 'teils', 'doses', 'cages', 'fours', 'feuds', 'gangs', 'pills', 'pants', 'hares', 'riots', 'kicks', 'looms', 'piers', 'seams', 'mails', 'moans', 'drags', 'tusks', 'cones', 'boils', 'crabs', 'warns', 'aches', 'gazes', 'heats', 'howls', 'memes', 'peals', 'bords', 'firms', 'fares', 'bulbs', 'pints', 'popes', 'quits', 'chops', 'pores', 'rares', 'zones', 'liars', 'mares', 'omits', 'cites', 'earls', 'tongs', 'vales', 'nooks', 'busts', 'fetes', 'venus', 'larks', 'gulls', 'duels', 'hoops', 'warms', 'obeys', 'harps', 'tapis', 'fairs', 'rafts', 'cotes', 'plats', 'rages', 'hunts', 'loops', 'manes', 'pails', 'desks', 'horas', 'deems', 'sores', 'sofas', 'trays', 'lurks', 'quays', 'rooks', 'bores', 'reels', 'vents', 'slums', 'mazes', 'blues', 'sires', 'yarns', 'swims', 'husks', 'combs', 'dupes', 'dunes', 'rangs', 'cafes', 'gills', 'halts', 'fonds', 'sechs', 'soups', 'glens', 'jeers', 'pleas', 'earns', 'camps', 'coals', 'rills', 'gasps', 'capes', 'calms', 'fleas', 'polls', 'beets', 'gulfs', 'rends', 'thans', 'soars', 'writs', 'mocks', 'elves', 'disks', 'dries', 'beaks', 'toads', 'grips', 'vives', 'films', 'jerks', 'fasts', 'dawns', 'voces', 'sways', 'spits', 'dykes', 'tolls', 'kites', 'props', 'flaps', 'bucks', 'aides', 'racks', 'necks', 'colds', 'casas', 'winks', 'boars', 'dines', 'wails', 'aloes', 'bancs', 'rears', 'epics', 'colts', 'drays', 'clods', 'gents', 'chins', 'knobs', 'butts', 'wasps', 'limes', 'slays', 'dikes', 'peeps', 'studs', 'bouts', 'jokes', 'heros', 'hoods', 'flaws', 'moles', 'slits', 'muses', 'meads', 'poses', 'gnats', 'stags', 'clams', 'satis', 'tetes', 'bunks', 'seers', 'corks', 'tarts', 'floes', 'siens', 'blots', 'cubes', 'stabs', 'pinks', 'spans', 'liens', 'reals', 'wipes', 'fords', 'claps', 'amies', 'vexes', 'roues', 'tacks', 'bogus', 'rives', 'lobes', 'teens', 'mixes', 'dales', 'heirs', 'wisps', 'penis', 'tombs', 'tress', 'wires', 'heals', 'atlas', 'rakes', 'shins', 'vials', 'fiefs', 'spins', 'auras', 'pomps', 'jails', 'dells', 'modus', 'shams', 'pests', 'betes', 'shuns', 'nests', 'bergs', 'sucks', 'dives', 'herbs', 'roles', 'chats', 'cools', 'snaps', 'hives', 'ovens', 'toits', 'pales', 'trans', 'clues', 'yawns', 'frets', 'lures', 'trots', 'hairs', 'sleds', 'banns', 'tares', 'flits', 'discs', 'grins', 'flees', 'gibes', 'manus', 'booms', 'grubs', 'fells', 'verts', 'vests', 'hulks', 'rudes', 'menus', 'clogs', 'arras', 'exits', 'hails', 'gilds', 'coves', 'junks', 'draps', 'torts', 'fuels', 'licks', 'bumps', 'hurls', 'harms', 'meses', 'solos', 'glans', 'boons', 'slugs', 'heeds', 'stews', 'cults', 'frees', 'hulls', 'baits', 'marts', 'rifts', 'doers', 'foils', 'leaks', 'paras', 'finis', 'damps', 'molds', 'lapis', 'hacks', 'mises', 'ambos', 'mutes', 'brats', 'wands', 'fuses', 'gants', 'loups', 'curds', 'gongs', 'fides', 'tomes', 'waifs', 'grams', 'ponts', 'drums', 'plies', 'slaps', 'lames', 'mites', 'pawns', 'lulls', 'dumps', 'emits', 'duets', 'avers', 'corns', 'tills', 'boors', 'hells', 'axles', 'laves', 'raves', 'talus', 'clefs', 'fawns', 'yokes', 'prows', 'jupes', 'hides', 'galls', 'fiers', 'skips', 'mores', 'drams', 'knits', 'synes', 'peons', 'waxes', 'roams', 'sabes', 'slats', 'buoys', 'reaps', 'ruses', 'oases', 'plugs', 'ticks', 'dames', 'warts', 'miens', 'reeks', 'motes', 'sixes', 'clays', 'teems', 'casus', 'cores', 'runes', 'lutes', 'meres', 'quips', 'blocs', 'preys', 'slops', 'quais', 'altos', 'leeks', 'dooms', 'hires', 'solus', 'fifes', 'gules', 'maces', 'thews', 'sagas', 'scans', 'devas', 'ovals', 'pures', 'lairs', 'gnaws', 'peres', 'snags', 'keels', 'grays', 'slags', 'pelts', 'plows', 'grabs', 'helms', 'gouts', 'bides', 'jacks', 'piles', 'almas', 'barbs', 'brigs', 'nears', 'flues', 'wafts', 'pecks', 'avows', 'trams', 'varas', 'hinds', 'laths', 'welks', 'snobs', 'dotes', 'taels', 'mends', 'fives', 'rungs', 'rimes', 'aegis', 'routs', 'gages', 'pates', 'ducts', 'ricks', 'diets', 'lavas', 'boles', 'mesas', 'locis', 'aeons', 'reams', 'fanes', 'fauns', 'tapes', 'bangs', 'bodes', 'drips', 'wicks', 'polis', 'dures', 'foams', 'loges', 'seres', 'harts', 'clous', 'whigs', 'brags', 'cribs', 'yelps', 'sulks', 'etats', 'dimes', 'tilts', 'moats', 'sills', 'pedis', 'pokes', 'ruffs', 'braes', 'mumps', 'dices', 'greys', 'duros', 'wanes', 'humps', 'hilts', 'sinds', 'deans', 'hauls', 'mints', 'naves', 'leges', 'mimes', 'opals', 'jeans', 'daubs', 'gears', 'hoots', 'loons', 'rides', 'annas', 'burrs', 'clips', 'vanes', 'goads', 'skims', 'brims', 'bulks', 'oozes', 'tiges', 'volts', 'pelas', 'papas', 'gapes', 'autos', 'eases', 'girds', 'pries', 'vires', 'plebs', 'clews', 'leves', 'gaols', 'minas', 'whens', 'malis']
sagas
b'Wrong! \x1b[47m \x1b[0m \x1b[47m \x1b[0m \x1b[47m \x1b[0m \x1b[47m \x1b[0m \x1b[47m \x1b[0m\n> '
白色 3527
白色 2889
白色 2815
白色 2665
白色 1959
Q [('c1', 193), ('a3', 268), ('o2', 359), ('e4', 367), ('e5', 430)]
['awake', 'evade', 'grade', 'abate', 'abase', 'pride', 'adobe', 'crate', 'bribe', 'flume', 'agree', 'biome', 'forge', 'agate', 'alone', 'erode', 'gouge', 'rouge', 'wrote', 'tilde', 'prove', 'grime', 'trace', 'brake', 'craze', 'gripe', 'acute', 'aside', 'gorge', 'wince', 'those', 'frame', 'dodge', 'trove', 'bloke', 'choke', 'rupee', 'brine', 'tease', 'movie', 'purge', 'trope', 'fibre', 'mince', 'ample', 'oxide', 'olive', 'delve', 'hinge', 'phase', 'goose', 'atone', 'agape', 'voice', 'wedge', 'trite', 'midge', 'elope', 'rhyme', 'twice', 'prize', 'theme', 'booze', 'thyme', 'chute', 'trice', 'alike', 'liege', 'grate', 'leave', 'twine', 'grove', 'ombre', 'unite', 'there', 'louse', 'grave', 'inane', 'crave', 'pique', 'arise', 'genre', 'plume', 'rifle', 'undue', 'guile', 'melee', 'loose', 'apple', 'eerie', 'price', 'chose', 'niece', 'grace', 'diode', 'chase', 'prone', 'evoke', 'elite', 'purse', 'write', 'awoke', 'exile', 'nurse', 'house', 'elude', 'cycle', 'boule', 'place', 'nerve', 'ridge', 'gnome', 'prose', 'budge', 'ozone', 'queue', 'truce', 'verse', 'verve', 'title', 'cutie', 'azure', 'weave', 'genie', 'glove', 'irate', 'amaze', 'globe', 'rouse', 'alive', 'ensue', 'anime', 'dunce', 'bilge', 'grape', 'noose', 'prime', 'nudge', 'brave', 'amble', 'amuse', 'copse', 'knife', 'plane', 'abide', 'where', 'graze', 'utile', 'adage', 'trade', 'clove', 'emcee', 'adore', 'puree', 'venue', 'pixie', 'penne', 'lodge', 'glide', 'usage', 'poise', 'drove', 'while', 'aware', 'three', 'chore', 'fluke', 'dense', 'lunge', 'plate', 'bible', 'agile', 'knave', 'arose', 'glare', 'grope', 'uncle', 'dirge', 'horde', 'quite', 'chafe', 'elide', 'pence', 'blaze', 'posse', 'mouse', 'creme', 'merge', 'tense', 'route', 'issue', 'urine', 'flute', 'obese', 'whale', 'abuse', 'terse', 'drake', 'afire', 'tithe', 'noble', 'bride', 'these', 'erase', 'quake', 'prude', 'femme', 'glade', 'elate', 'whole', 'ovate', 'lease', 'blare', 'probe', 'crepe', 'force', 'abode', 'aisle', 'verge', 'guide', 'revue', 'tulle', 'crude', 'curse', 'opine', 'crane', 'lithe', 'prune', 'chide', 'ankle', 'tribe', 'cease', 'flame', 'broke', 'bulge', 'butte', 'tripe', 'worse', 'phone', 'binge', 'belie', 'above', 'fence', 'ounce', 'flake', 'anode', 'crime', 'imbue', 'ledge', 'drone', 'niche', 'juice', 'brute', 'reuse', 'quote', 'noise', 'flare', 'white', 'etude', 'horse', 'belle', 'ovine', 'heave', 'borne', 'rinse', 'deuce', 'hedge', 'coupe', 'blade', 'geese', 'close', 'clone', 'guise', 'drape', 'glaze', 'tepee', 'brace', 'froze', 'moose', 'image', 'chime', 'curve', 'drive', 'fudge', 'forte', 'whine', 'whose', 'crone', 'pulse', 'hence', 'piece', 'blame', 'peace', 'untie', 'judge', 'homme', 'thine', 'jeune', 'monde', 'fille', 'mille', 'bonne', 'comte', 'donne', 'forme', 'afore', 'foule', 'livre', 'welke', 'douce', 'tinge', 'geste', 'cesse', 'fosse', 'prise', 'monte', 'frere', 'titre', 'outre', 'gwine', 'metre', 'folie', 'bitte', 'quale', 'clime', 'levee', 'heare', 'voile', 'chere', 'feare', 'glace', 'apace', 'vilde', 'conte', 'brise', 'gerne', 'crape', 'toile', 'beare', 'longe', 'ronde', 'meane', 'whore', 'chuse', 'tenue', 'blive', 'corse', 'prate', 'mitre', 'crise', 'lieve', 'morne', 'chile', 'gorse', 'deare', 'breve', 'volte', 'furze', 'coude', 'knowe', 'grise', 'dolce', 'dulce', 'russe', 'youse', 'borde', 'nonce', 'thane', 'pease', 'rente', 'drole', 'agone', 'drave', 'usque', 'brume', 'trone', 'amene', 'moste', 'ochre', 'fiere', 'roule', 'plage', 'quare', 'toque', 'deere', 'allee', 'conge', 'weise', 'quire', 'boite', 'botte', 'kopje', 'plebe', 'clave', 'lemme', 'blase', 'brule', 'gimme', 'chine', 'nieve', 'nitre', 'piste', 'prese', 'glebe', 'tenne', 'poule', 'teste', 'golpe', 'etage', 'eyrie', 'bouge', 'kluge', 'chace', 'brede', 'venge', 'bonie', 'inure', 'litre', 'peece', 'fiche', 'weeke', 'perce', 'powre', 'chyle', 'ukase', 'bowie', 'reeve', 'throe', 'phare', 'dowle']
coude
b'Wrong! \x1b[47m \x1b[0m \x1b[47m \x1b[0m \x1b[47m \x1b[0m \x1b[47m \x1b[0m \x1b[43m \x1b[0m\n> '
白色 1766
白色 1450
白色 1384
白色 1343
黄色 480
Q [('e1', 48), ('e3', 83), ('r5', 97), ('e2', 189), ('e4', 239)]
['quiet', 'unfed', 'linen', 'unmet', 'bleed', 'greet', 'islet', 'hyper', 'tweed', 'fixer', 'finer', 'usher', 'abbey', 'elder', 'ulcer', 'other', 'renew', 'fewer', 'askew', 'asset', 'egret', 'liver', 'upset', 'alien', 'ruder', 'onset', 'inter', 'unset', 'libel', 'piney', 'threw', 'fleet', 'deter', 'rivet', 'udder', 'given', 'octet', 'risen', 'diner', 'embed', 'reset', 'queer', 'freer', 'plier', 'nicer', 'pried', 'tenet', 'index', 'flier', 'fiber', 'kneel', 'flyer', 'beset', 'ruler', 'aider', 'river', 'betel', 'often', 'diver', 'alley', 'vixen', 'outer', 'excel', 'queen', 'enter', 'filet', 'inner', 'otter', 'level', 'tuber', 'grief', 'buyer', 'ashen', 'offer', 'dryer', 'infer', 'ether', 'idler', 'timer', 'wheel', 'rebel', 'ester', 'thief', 'tweet', 'giver', 'preen', 'bevel', 'wider', 'breed', 'brief', 'never', 'duvet', 'after', 'owner', 'ember', 'plied', 'upper', 'defer', 'drier', 'jewel', 'hymen', 'freed', 'alter', 'utter', 'piper', 'riper', 'pixel', 'liner', 'unwed', 'order', 'widen', 'annex', 'under', 'refer', 'olden', 'older', 'miner', 'green', 'abled', 'viper', 'kneed', 'odder', 'tried', 'dicey', 'leper', 'bicep', 'bused', 'fever', 'expel', 'revel', 'video', 'apnea', 'purer', 'greed', 'liken', 'beret', 'lumen', 'amber', 'fried', 'miser', 'bezel', 'filer', 'newer', 'lever', 'repel', 'meter', 'dried', 'bleep', 'rider', 'wiser', 'impel', 'inlet', 'ripen', 'riser', 'asked', 'added', 'lived', 'fixed', 'liked', 'tired', 'ended', 'armed', 'acted', 'mixed', 'fired', 'assez', 'owned', 'dined', 'hired', 'filed', 'ruled', 'vexed', 'lined', 'piled', 'aided', 'wiped', 'aimed', 'mused', 'ached', 'lured', 'dived', 'leben', 'fined', 'aimer', 'erred', 'objet', 'fused', 'piped', 'pined', 'oiled', 'prier', 'wired', 'duped', 'tuned', 'timed', 'hewed', 'ebbed', 'adieu', 'tiled', 'riven', 'appel', 'meted', 'aspen', 'ailed', 'abler', 'alder', 'adder', 'aired', 'ither', 'armer', 'fumed', 'anker', 'keyed', 'mined', 'hiver', 'brier', 'gilet', 'bided', 'oriel', 'heben', 'fumer', 'typed', 'liber', 'osier', 'idled', 'biped', 'viler', 'aster', 'feted', 'riled', 'irked', 'remet', 'ivied', 'muted', 'mewed', 'liker', 'treed', 'diced', 'wexed']
queer
b'Wrong! \x1b[47m \x1b[0m \x1b[47m \x1b[0m \x1b[43m \x1b[0m \x1b[42m \x1b[0m \x1b[43m \x1b[0m\n> '
白色 474
白色 455
黄色 378
绿色 202
黄色 29
Q [('r3', 9), ('r2', 10), ('r1', 11), ('d5', 13)]
['pried', 'tried', 'fried', 'dried', 'tired', 'armed', 'fired', 'hired', 'erred', 'wired', 'aired', 'riled', 'irked']
b'Wrong! \x1b[42m \x1b[0m \x1b[47m \x1b[0m \x1b[43m \x1b[0m \x1b[42m \x1b[0m \x1b[47m \x1b[0m\n> '
绿色 11
白色 6
黄色 3
绿色 3
白色 3
Q [('p3', 1)]
['repel']
b'Correct! \x1b[42m \x1b[0m \x1b[42m \x1b[0m \x1b[42m \x1b[0m \x1b[42m \x1b[0m \x1b[42m \x1b[0m\nRound 2: #be3c1\n> '
绿色 3
绿色 3
绿色 1
绿色 1
绿色 1
Q [('a3', 486), ('s1', 563), ('a2', 689), ('e4', 793), ('s5', 1033)]
['floss', 'crass', 'abyss', 'rebus', 'truss', 'focus', 'fetus', 'glass', 'class', 'chaos', 'dross', 'cress', 'bless', 'bliss', 'brass', 'cross', 'amass', 'bonus', 'locus', 'grass', 'ethos', 'humus', 'basis', 'guess', 'lupus', 'torus', 'minus', 'dress', 'amiss', 'mucus', 'gross', 'gloss', 'virus', 'chess', 'ficus', 'press', 'years', 'words', 'hands', 'works', 'means', 'times', 'terms', 'seems', 'miles', 'comes', 'hours', 'makes', 'books', 'knows', 'trees', 'parts', 'tears', 'lines', 'takes', 'girls', 'gives', 'lives', 'looks', 'walls', 'steps', 'cases', 'names', 'forms', 'heads', 'ideas', 'ships', 'weeks', 'sides', 'facts', 'hills', 'faces', 'birds', 'tells', 'rules', 'wants', 'hopes', 'woods', 'minds', 'yours', 'shows', 'rocks', 'notes', 'needs', 'lands', 'stars', 'rooms', 'knees', 'doors', 'goods', 'yards', 'temps', 'souls', 'calls', 'plans', 'pages', 'views', 'signs', 'kinds', 'kings', 'links', 'files', 'banks', 'loves', 'wings', 'turns', 'waves', 'towns', 'corps', 'finds', 'costs', 'boats', 'cries', 'sorts', 'falls', 'gates', 'bones', 'trois', 'winds', 'fears', 'wives', 'holds', 'roads', 'gifts', 'marks', 'pains', 'walks', 'folks', 'poets', 'shoes', 'deeds', 'bears', 'feels', 'poems', 'plays', 'keeps', 'songs', 'leads', 'limbs', 'tones', 'grows', 'ranks', 'tales', 'boots', 'seats', 'fires', 'jours', 'cents', 'roses', 'roots', 'pious', 'wages', 'blows', 'cares', 'rises', 'ruins', 'types', 'lords', 'dates', 'homes', 'drops', 'likes', 'cards', 'races', 'codes', 'taxes', 'ashes', 'bells', 'heels', 'evils', 'bands', 'acres', 'mains', 'flies', 'seeds', 'sites', 'bills', 'holes', 'sails', 'rings', 'boxes', 'fools', 'veins', 'opens', 'sends', 'mines', 'paths', 'moves', 'shops', 'tents', 'backs', 'bonds', 'games', 'debts', 'spots', 'balls', 'crops', 'monks', 'lamps', 'hears', 'robes', 'skies', 'draws', 'votes', 'rests', 'brows', 'reads', 'talks', 'horns', 'apres', 'texts', 'genus', 'locks', 'posts', 'funds', 'tools', 'paces', 'fails', 'ports', 'rates', 'vices', 'wears', 'skins', 'items', 'seeks', 'lakes', 'sales', 'meets', 'meals', 'suits', 'flows', 'reeds', 'roofs', 'beams', 'cells', 'pipes', 'folds', 'maids', 'mules', 'reins', 'edges', 'nails', 'tries', 'cakes', 'rites', 'sings', 'hosts', 'hangs', 'coats', 'goals', 'modes', 'loses', 'pines', 'heaps', 'fills', 'forts', 'lions', 'lungs', 'sands', 'halls', 'farms', 'rains', 'hints', 'poles', 'ropes', 'rolls', 'males', 'shots', 'stops', 'clubs', 'lists', 'flags', 'curls', 'weeds', 'tends', 'palms', 'sexes', 'users', 'oaths', 'beads', 'herds', 'vines', 'sighs', 'helps', 'peaks', 'coins', 'hoofs', 'pairs', 'beans', 'coups', 'goats', 'spurs', 'gains', 'moods', 'spies', 'hymns', 'fowls', 'burns', 'mills', 'tails', 'mists', 'ducks', 'waits', 'caves', 'tasks', 'claws', 'twins', 'idols', 'wills', 'dares', 'sizes', 'risks', 'stems', 'tests', 'seals', 'sinks', 'carts', 'deals', 'noses', 'knots', 'areas', 'fists', 'plots', 'drugs', 'wines', 'pools', 'cords', 'rails', 'stays', 'kills', 'lifts', 'worms', 'masts', 'decks', 'pangs', 'toils', 'loads', 'peers', 'longs', 'baths', 'tides', 'tints', 'atoms', 'wares', 'slips', 'rents', 'feats', 'twigs', 'lasts', 'casts', 'snows', 'sects', 'cours', 'lanes', 'wells', 'joins', 'bases', 'vases', 'chaps', 'bolts', 'irons', 'lambs', 'leaps', 'gowns', 'sages', 'bends', 'hurts', 'silks', 'crews', 'bulls', 'lacks', 'verbs', 'traps', 'mates', 'meats', 'feeds', 'darts', 'flats', 'tubes', 'units', 'pours', 'trips', 'antes', 'yells', 'hooks', 'nouns', 'louis', 'ferns', 'fumes', 'sheds', 'foods', 'isles', 'saves', 'forks', 'dites', 'teams', 'cooks', 'deres', 'sacks', 'frogs', 'wakes', 'reefs', 'asses', 'loans', 'binds', 'germs', 'fines', 'crows', 'salts', 'bowls', 'jests', 'sells', 'downs', 'babes', 'dents', 'panes', 'wilds', 'yolks', 'loins', 'stirs', 'veils', 'tunes', 'lumps', 'repos', 'sakes', 'pulls', 'tiles', 'barns', 'aunts', 'crags', 'casks', 'cures', 'alias', 'noirs', 'scars', 'morts', 'ponds', 'bales', 'gales', 'lends', 'foxes', 'picks', 'urges', 'shuts', 'socks', 'parks', 'odors', 'gases', 'lawns', 'tufts', 'fixes', 'soles', 'gusts', 'coils', 'masks', 'packs', 'doves', 'dolls', 'wards', 'puffs', 'dukes', 'shews', 'myths', 'fangs', 'belts', 'idees', 'slabs', 'fates', 'chefs', 'moons', 'prays', 'leans', 'eaves', 'whims', 'whips', 'manos', 'chips', 'domes', 'wraps', 'pumps', 'dregs', 'jumps', 'wiles', 'roars', 'soils', 'raids', 'acids', 'tiers', 'tanks', 'canes', 'bombs', 'stets', 'spars', 'pears', 'swans', 'tours', 'omens', 'cocks', 'pesos', 'clans', 'melts', 'bards', 'moths', 'deeps', 'dears', 'plums', 'hawks', 'moors', 'bites', 'docks', 'serfs', 'oasis', 'laces', 'fades', 'weeps', 'lusts', 'glows', 'pikes', 'chums', 'lotus', 'cuffs', 'barks', 'tires', 'teils', 'doses', 'cages', 'fours', 'feuds', 'gangs', 'pills', 'pants', 'hares', 'riots', 'kicks', 'looms', 'piers', 'seams', 'mails', 'moans', 'drags', 'tusks', 'cones', 'boils', 'crabs', 'warns', 'aches', 'gazes', 'heats', 'howls', 'memes', 'peals', 'bords', 'firms', 'fares', 'bulbs', 'pints', 'popes', 'quits', 'chops', 'pores', 'rares', 'zones', 'liars', 'mares', 'omits', 'cites', 'earls', 'tongs', 'vales', 'nooks', 'busts', 'fetes', 'venus', 'larks', 'gulls', 'duels', 'hoops', 'warms', 'obeys', 'harps', 'tapis', 'fairs', 'rafts', 'cotes', 'plats', 'rages', 'hunts', 'loops', 'manes', 'pails', 'desks', 'horas', 'deems', 'sores', 'sofas', 'trays', 'lurks', 'quays', 'rooks', 'bores', 'reels', 'vents', 'slums', 'mazes', 'blues', 'sires', 'yarns', 'swims', 'husks', 'combs', 'dupes', 'dunes', 'rangs', 'cafes', 'gills', 'halts', 'fonds', 'sechs', 'soups', 'glens', 'jeers', 'pleas', 'earns', 'camps', 'coals', 'rills', 'gasps', 'capes', 'calms', 'fleas', 'polls', 'beets', 'gulfs', 'rends', 'thans', 'soars', 'writs', 'mocks', 'elves', 'disks', 'dries', 'beaks', 'toads', 'grips', 'vives', 'films', 'jerks', 'fasts', 'dawns', 'voces', 'sways', 'spits', 'dykes', 'tolls', 'kites', 'props', 'flaps', 'bucks', 'aides', 'racks', 'necks', 'colds', 'casas', 'winks', 'boars', 'dines', 'wails', 'aloes', 'bancs', 'rears', 'epics', 'colts', 'drays', 'clods', 'gents', 'chins', 'knobs', 'butts', 'wasps', 'limes', 'slays', 'dikes', 'peeps', 'studs', 'bouts', 'jokes', 'heros', 'hoods', 'flaws', 'moles', 'slits', 'muses', 'meads', 'poses', 'gnats', 'stags', 'clams', 'satis', 'tetes', 'bunks', 'seers', 'corks', 'tarts', 'floes', 'siens', 'blots', 'cubes', 'stabs', 'pinks', 'spans', 'liens', 'reals', 'wipes', 'fords', 'claps', 'amies', 'vexes', 'roues', 'tacks', 'bogus', 'rives', 'lobes', 'teens', 'mixes', 'dales', 'heirs', 'wisps', 'penis', 'tombs', 'tress', 'wires', 'heals', 'atlas', 'rakes', 'shins', 'vials', 'fiefs', 'spins', 'auras', 'pomps', 'jails', 'dells', 'modus', 'shams', 'pests', 'betes', 'shuns', 'nests', 'bergs', 'sucks', 'dives', 'herbs', 'roles', 'chats', 'cools', 'snaps', 'hives', 'ovens', 'toits', 'pales', 'trans', 'clues', 'yawns', 'frets', 'lures', 'trots', 'hairs', 'sleds', 'banns', 'tares', 'flits', 'discs', 'grins', 'flees', 'gibes', 'manus', 'booms', 'grubs', 'fells', 'verts', 'vests', 'hulks', 'rudes', 'menus', 'clogs', 'arras', 'exits', 'hails', 'gilds', 'coves', 'junks', 'draps', 'torts', 'fuels', 'licks', 'bumps', 'hurls', 'harms', 'meses', 'solos', 'glans', 'boons', 'slugs', 'heeds', 'stews', 'cults', 'frees', 'hulls', 'baits', 'marts', 'rifts', 'doers', 'foils', 'leaks', 'paras', 'finis', 'damps', 'molds', 'lapis', 'hacks', 'mises', 'ambos', 'mutes', 'brats', 'wands', 'fuses', 'gants', 'loups', 'curds', 'gongs', 'fides', 'tomes', 'waifs', 'grams', 'ponts', 'drums', 'plies', 'slaps', 'lames', 'mites', 'pawns', 'lulls', 'dumps', 'emits', 'duets', 'avers', 'corns', 'tills', 'boors', 'hells', 'axles', 'laves', 'raves', 'talus', 'clefs', 'fawns', 'yokes', 'prows', 'jupes', 'hides', 'galls', 'fiers', 'skips', 'mores', 'drams', 'knits', 'synes', 'peons', 'waxes', 'roams', 'sabes', 'slats', 'buoys', 'reaps', 'ruses', 'oases', 'plugs', 'ticks', 'dames', 'warts', 'miens', 'reeks', 'motes', 'sixes', 'clays', 'teems', 'casus', 'cores', 'runes', 'lutes', 'meres', 'quips', 'blocs', 'preys', 'slops', 'quais', 'altos', 'leeks', 'dooms', 'hires', 'solus', 'fifes', 'gules', 'maces', 'thews', 'sagas', 'scans', 'devas', 'ovals', 'pures', 'lairs', 'gnaws', 'peres', 'snags', 'keels', 'grays', 'slags', 'pelts', 'plows', 'grabs', 'helms', 'gouts', 'bides', 'jacks', 'piles', 'almas', 'barbs', 'brigs', 'nears', 'flues', 'wafts', 'pecks', 'avows', 'trams', 'varas', 'hinds', 'laths', 'welks', 'snobs', 'dotes', 'taels', 'mends', 'fives', 'rungs', 'rimes', 'aegis', 'routs', 'gages', 'pates', 'ducts', 'ricks', 'diets', 'lavas', 'boles', 'mesas', 'locis', 'aeons', 'reams', 'fanes', 'fauns', 'tapes', 'bangs', 'bodes', 'drips', 'wicks', 'polis', 'dures', 'foams', 'loges', 'seres', 'harts', 'clous', 'whigs', 'brags', 'cribs', 'yelps', 'sulks', 'etats', 'dimes', 'tilts', 'moats', 'sills', 'pedis', 'pokes', 'ruffs', 'braes', 'mumps', 'dices', 'greys', 'duros', 'wanes', 'humps', 'hilts', 'sinds', 'deans', 'hauls', 'mints', 'naves', 'leges', 'mimes', 'opals', 'jeans', 'daubs', 'gears', 'hoots', 'loons', 'rides', 'annas', 'burrs', 'clips', 'vanes', 'goads', 'skims', 'brims', 'bulks', 'oozes', 'tiges', 'volts', 'pelas', 'papas', 'gapes', 'autos', 'eases', 'girds', 'pries', 'vires', 'plebs', 'clews', 'leves', 'gaols', 'minas', 'whens', 'malis']
sagas
b'Wrong! \x1b[47m \x1b[0m \x1b[42m \x1b[0m \x1b[47m \x1b[0m \x1b[47m \x1b[0m \x1b[47m \x1b[0m\n> '
白色 3527
绿色 638
白色 617
白色 593
白色 405
Q [('c1', 43), ('r3', 53), ('y5', 80), ('e4', 104)]
['paper', 'panel', 'lapel', 'cater', 'gamer', 'payer', 'label', 'parer', 'baker', 'valet', 'laden', 'tamer', 'hater', 'eater', 'paler', 'eaten', 'layer', 'matey', 'later', 'hazel', 'haven', 'gavel', 'harem', 'taper', 'ramen', 'caper', 'oaken', 'racer', 'waxen', 'easel', 'gazer', 'facet', 'navel', 'water', 'cameo', 'maker', 'taken', 'camel', 'cadet', 'rarer', 'waver', 'baler', 'wafer', 'gayer', 'taker', 'payee', 'raven', 'named', 'based', 'dared', 'gazed', 'cared', 'hated', 'naked', 'faced', 'faded', 'waved', 'dated', 'paved', 'fared', 'dazed', 'waked', 'waxed', 'taxed', 'raced', 'laten', 'famed', 'bared', 'fated', 'waken', 'laced', 'waded', 'tamed', 'eased', 'jaded', 'rated', 'paled', 'raked', 'fader', 'baser', 'raved', 'waned', 'gaped', 'mater', 'pater', 'pared', 'cased', 'bated', 'razed', 'mated', 'laver', 'haled', 'babel', 'pawed', 'lamed', 'caked', 'baked', 'payed', 'lader', 'caved', 'laved', 'haver', 'paseo', 'oaten']
b'Wrong! \x1b[47m \x1b[0m \x1b[42m \x1b[0m \x1b[43m \x1b[0m \x1b[47m \x1b[0m \x1b[47m \x1b[0m\n> '
白色 362
绿色 362
黄色 78
白色 69
白色 53
Q [('s3', 10), ('t1', 15), ('t5', 22), ('t4', 23)]
['waste', 'waltz', 'paste', 'earth', 'caste', 'haste', 'cacti', 'taste', 'pasta', 'baste', 'haute', 'faith', 'parti', 'hasta', 'tanto', 'carte', 'canto', 'carta', 'baith', 'basta', 'facta', 'garth', 'tanti']
b'Wrong! \x1b[43m \x1b[0m \x1b[42m \x1b[0m \x1b[47m \x1b[0m \x1b[47m \x1b[0m \x1b[47m \x1b[0m\n> '
黄色 38
绿色 38
白色 30
白色 18
白色 18
Q [('h1', 4), ('u3', 7), ('n4', 8)]
['jaunt', 'gaunt', 'faint', 'haunt', 'paint', 'daunt', 'vaunt', 'haint']
b'Wrong! \x1b[47m \x1b[0m \x1b[42m \x1b[0m \x1b[47m \x1b[0m \x1b[42m \x1b[0m \x1b[42m \x1b[0m\n> '
白色 14
绿色 14
白色 8
绿色 2
绿色 2
Q [('p1', 1)]
['paint']
b'Correct! \x1b[42m \x1b[0m \x1b[42m \x1b[0m \x1b[42m \x1b[0m \x1b[42m \x1b[0m \x1b[42m \x1b[0m\nRound 3: #e896c\n> '

平均所需次数仍然 >6,虽然得到了模式1的第一位奖励 : (

一度怀疑计算机没色弱好使🤔

Here is you award: U**********************************************************

不过呢,从开始写的第一个Python交互版的代码开始,其实就已经可以解决模式0

Here is you award: NULL

给我干沉默了…

最后的想法

看到了一篇介绍 3Blue1Brown 关于给出Wordle理论极限解的文章,受到了启发,但时间不够了。

3Blue1Brown

3Blue1Brown,这是一个由斯坦福大学的数学系学生Grant Sanderson 创建的YouTube 频道。该频道从独特的视觉角度解说高等数学,内容包括线性代数微积分神经网络黎曼猜想傅里叶变换以及四元数等等。

据说名字由来是因为其眼瞳的颜色为三分蓝一分棕

3Blue1Brown

引用

从每一次猜测中获得最多信息

Wordle 的游戏规则很简单,玩家需要猜出程序每天指定的一个 5 位英语单词谜底。玩家可以随意提交一个英语单词,但必须是字典里有的,不能胡乱拼写。如果字母在谜底中出现且位置对了就显示绿色,字母出现了但位置不对就显示黄色,字母在答案的单词中没出现就显示灰色。根据反馈信息再进行下一轮猜测,在 6 次尝试之内猜出就算赢。

img

如何让步数尽量少?

3Blue1Brown 的总体思路是尽量从每一次猜测中获得最多的信息。他先是找来了 26 个字母在英语文本中出现频率的统计数据,尝试在前两次尝试中覆盖最多高频字母。比如 other+nails 的组合,就可以覆盖出现频率最高的 11 个字母中的 10 个,如果运气好就能确定下来一些字母。即使这些字母都没出现依然是一种信息量很大的反馈,10 个常用字母都没出现的单词数量就大大减少了,让下一步猜测更简单。

img

不过在尝试过程中,又出现了新的问题。同样用 nails 这几个字母,也可以拼成 snail ,这两种拼写顺序之间的差异,仅依据字母频率数据是无法衡量的。

下面需要一种新的计算方法。

如何计算信息量?

原版 Wordle 游戏里有一个数量 12972 的总单词列表,都能作为猜测词使用。另外有一个 2315 个单词的列表,只有这些单词会出现在答案里 (据说是游戏作者的女朋友挑选的)。因为游戏是用 Javascript 写的,数据都在客户端,这些数据直接可以从源码里找到。不过 3Blue1Brown 觉得让程序利用答案列表的话有点像作弊了,他果断给自己加大难度,只考虑总单词列表。游戏中,每一次猜测都能从 12972 个单词中排除一些结果。比如猜测 weary,如果 W 位置正确同时 A 出现了,那么剩下的可选单词只剩 58 个。

img

这样对同一个猜测,从 5 个字母全没出现到 5 个字母全对的各种反馈的概率都可以计算出来。

img

这样,问题就变成了如何评估各种反馈情况包含的信息量。

3Blue1Brown 选择的办法,就是利用信息论祖师爷香农提出的信息熵概念。信息熵描述的是事件的不确定性,单位就是大家知道的比特。理解起来也不难,可以用扔硬币来解释。

扔 1 枚硬币只会出现正、反两种结果,而且概率相等。扔 2 枚硬币就有正正、正反、反正、反反这 4 种结果,扔 3 枚有 8 种情况等等,也就是扔 n 次有 2 的 n 次方种结果。

当一个事件有两种结果且概率都是 1/2,其不确定性相当于扔 1 枚硬币,此时信息熵定义为 1 比特。如果一个事件有 8 种结果且概率都是 1/8,就相当于扔 3 枚硬币,此时信息熵就是 3 比特。

信息量和信息熵的数量相等、意义相反,相当于衡量一则信息能消除多少不确定性。设每种结果的概率为 p,信息量为 I,有如下等式。

img

稍作变换,可以得到信息量的计算公式。

img

回到 Wordle 游戏上,一次猜测获得的信息量可以用每种可能情况的概率与对应信息量相乘、再把结果相加来计算,也就是求数学期望。

以猜测 weary 为例,计算出获得的信息量为 4.9 比特。代表这则信息消除的不确定性比扔 5 个硬币的不确定性少一点。

img

算法思路有了,接下来就可以交给程序,计算出所有 12972 个单词的能消除的信息熵。

img

用同样的方法,可以再计算第二步、第三步猜测能消除的信息熵。

img

根据这些计算结果,程序就可以在每一次猜测时,选择所有可能单词里能消除信息熵最多的那个。

比如第一次猜 slate 获得一次反馈,此时还剩下 578 个单词可选,其中选 ramin 能消除最多的信息熵,这样一步一步猜直到猜出正确答案。

img

接下来,拿这个程序在所有 2135 种可能的答案上跑一遍,平均用了 4.124 步猜出正确答案。

img

3Blue1Brown 觉得这个成绩还不够好,至少没有超过普通人类玩家水平,还需要继续优化。

那么借用信息墒概念,通过代码实现就完全够用了(平均用了 4.124 步,大不了多试几次

插一句,3Blue1Brown最后通过对单词进行词频分析以选择常用词使其算法最终成绩到达 3.138,逼近了理论极限。

可惜,现在靶机关闭了,无法实际编写代码

参考资料