Created
February 6, 2022 19:43
-
-
Save MarcPer/130904256430bacca679c4054cfb3a5c to your computer and use it in GitHub Desktop.
Wordle with segfault
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
def parse_vec file | |
v = {} | |
file.split("\n").each do |s| | |
arr = s.split(":") | |
v[arr[0]] = arr[1].gsub("[", "").gsub("]", "").split(",").map(&:to_i) | |
end | |
v | |
end | |
def parse_inv file | |
v = {} | |
file.split("\n").each do |s| | |
arr = s.split(":") | |
v[arr[0]] = arr[1].gsub("{", "").gsub("}", "").split(", ").map do |st| st.gsub("'", '') end | |
end | |
v | |
end | |
def parse_tweets file | |
d = {} | |
file.split("\r\n").each do |ln| | |
parts = ln.split ";" | |
day = parts[0].to_i | |
id = parts[1] | |
guesses = parts[2] | |
.gsub("[", "").gsub("]", "") | |
.split(", ").map {|st| st.gsub("'", '')} | |
d[day] ||= {} | |
d[day][id] = guesses | |
end | |
d | |
end | |
def cosine_slow(v1, v2) | |
dot_product = 0 | |
v1.zip(v2).each do |v1i, v2i| | |
dot_product += v1i * v2i | |
end | |
a = v1.map { |n| n ** 2 }.reduce(:+) | |
b = v2.map { |n| n ** 2 }.reduce(:+) | |
return dot_product / (Math.sqrt(a) * Math.sqrt(b)) | |
end | |
def cosine_fast(v1, v2) | |
dot_product = 0 | |
a = 0 | |
b = 0 | |
v1.size.times do |i| | |
dot_product += v1[i] * v2[i] | |
a += v1[i]**2 | |
b += v2[i]**2 | |
end | |
return dot_product / (Math.sqrt(a) * Math.sqrt(b)) | |
end | |
def cosine(v1, v2) | |
cosine_fast(v1, v2) | |
end | |
def counter list | |
counts = {} | |
for l in list do | |
counts[l] ||= 0 | |
counts[l] = counts[l] +1 | |
end | |
counts | |
end | |
def evaluate_guess(answer, guess) | |
res = ['','','','',''] | |
matches = {} | |
gue_c = guess.chars | |
ans_c = answer.chars | |
ans_letters = counter(ans_c) | |
gue_c.each {|c| matches[c] = 0} | |
gue_c.each_with_index do |c, i| | |
if answer[i]==c | |
res[i] = 'Y' | |
matches[c] += 1 | |
end | |
end | |
gue_c.each_with_index do |c, i| | |
if res[i] != 'Y' | |
if ans_c.include? c && matches[c] < (ans_letters[c] || 0) | |
res[i] = 'M' | |
mathces[c] += 1 | |
else res[i] = 'N' | |
end | |
end | |
end | |
res | |
end | |
def read_data(args, filename, small=false) | |
folder = small ? "data/small/" : "data/" | |
args.gtk.read_file(File.join(folder, filename)) | |
end | |
def tick args | |
args.state.results ||= {} | |
small = false | |
if args.state.results.empty? | |
letters = ['Y', 'M', 'N'] | |
vec_locs = letters.product(letters).product(letters).product(letters).product(letters) | |
.map {|arr| arr.flatten.join('') }.sort | |
args.state.v_all ||= parse_vec(read_data(args, "vec_all.txt", small)) | |
args.state.v_ratio ||= parse_vec(read_data(args, "vec_ratio.txt", small)) | |
args.state.answers ||= read_data(args, "answers.txt", small).split('\n') | |
args.state.other_words ||= read_data(args, "other_words.txt", small).split('\n') | |
args.state.invalid_results ||= parse_inv(read_data(args, "invalid_results.txt", small)) | |
args.state.tweets ||= parse_tweets(read_data(args, "tweets.txt", small)) | |
# args.state.tweets.each do |day, games| | |
# if day != 210 { next } | |
day = 210 | |
games = args.state.tweets[day] | |
all_counts = counter(games.find_all {|g| g.length > 1 && g[-1] == 'YYYYY'}.flatten ) | |
first_counts = counter(games.find_all {|g| g.length > 1 && g[-1] == 'YYYYY'}.map {|g| g[0]}) | |
penultimate_counts = counter(games.find_all {|g| g.length > 1 && g[-1] == 'YYYYY'}.map {|g| g[-2]}) | |
vec_all = vec_locs.map {|res| all_counts[res] || 0} | |
# puts vec_all.size | |
# puts "Num words: #{args.state.v_all.keys.size}" | |
# puts "Games: #{games.size}" | |
vec_first = vec_locs.map {|res| first_counts[res] || 0} | |
vec_penultimate = vec_locs.map {|res| penultimate_counts[res] || 0} | |
vec_ratio = vec_locs.map {|res| (penultimate_counts[res] || 0)/((all_counts[res] || 0)+1e-6)} | |
# args.state.results = [1] | |
# return | |
dists = {"all" => {}, "ratio" => {}, "invalid" => {}} | |
args.state.v_all.each_key do |word| | |
dists["all"][word] = cosine(vec_all, args.state.v_all[word]) | |
dists["ratio"][word] = cosine(vec_ratio, args.state.v_ratio[word]) | |
invalid_res = args.state.invalid_results[word] | |
dists["invalid"][word] = games.count {|g| invalid_res.any? { |w| g.include?(w) } } | |
# dists["invalid"][word] = games.count {|g| !(g & args.state.invalid_results[word]).empty? } | |
end | |
ranks = {} | |
dists.each do |type, value| | |
s = value.sort_by{|k, v| v} | |
ranks[type] = {} | |
s.length.times {|i| ranks[type][s[i][0]] = i} | |
end | |
overall = {} | |
args.state.v_all.each_key do |key| | |
overall[key] = ranks.map {|k, v| v[key]} | |
end | |
overall_s = overall.sort_by {|k, v| v} | |
my_guess = overall_s[0][0] | |
answer = args.state.answers[day] | |
answer_rank = overall_s.map {|a| a[0]}.index(answer) | |
# results.insert([i, my_guess, answer, answer_rank, overall, dists, ranks]) | |
feedback = evaluate_guess(answer.to_s, my_guess.to_s).join | |
if answer==my_guess | |
feedback.concat(" !!!!!!") | |
else | |
feedback.concat(" :(:( the actual answer was #{answer}, which ranked #{answer_rank} on my guess list") | |
end | |
# puts("For Wordle #{day}, my guess was #{my_guess}. #{feedback}") | |
args.state.results[day] = my_guess | |
end | |
# end | |
args.outputs.labels << [640, 500, args.state.results, 5, 1] | |
end | |
def log_perf(args, name, &bl) | |
now = Time.now.to_i | |
args.gtk.append_file_root("perf.log", "started #{name}\n") | |
bl.call | |
args.gtk.append_file_root("perf.log", "done #{name} in #{Time.now.to_i - now}\n") | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment