Skip to main content
improve
Source Link
Surculose Sputum
  • 8.4k
  • 1
  • 14
  • 40

Python 3, (1, 149, 840945, 12131118, 112102)

from collections import Counter # history: a list of tuple of (guess, feedback) # feedback: a list of length 5, each element can be MISS, CLOSE, or MATCH def play(history): # Hard coded first guess turn = len(history) + 1 if turn == 1: return 'trace' # When there are few words left remaining_words = [word for word in WORDS if all(get_feedback(guess, word) == feedback for guess, feedback in history)] if len(remaining_words) <= 2: return remaining_words[0]   # Hardcoded hard case if turn == 3 and history == [('trace', [MISS, CLOSE, MISS, MISS, CLOSE]), ('risen', [CLOSE, MISS, MISS, MATCH, MISS])]: return 'howdy' guess_list = WORDS if turn > 2 and len(remaining_words) < 100 else remaining_words return find_best_guest(guess_list, remaining_words)   def find_best_guest(guess_list, secret_list): R = [] secret_set = set(secret_list) for guess in guess_list: c = Counter([tuple(get_feedback(guess, secret)) for secret in secret_list]) R.append([guess, len(c), guess in secret_set, -max(c.values())]) best_guess = max(R, key=lambda t:(t[1],-t[2])t[1:]) return best_guess[0] 

Try it online!Try it online!

ScorerScorer

Each time, I pick the guess from the list of remaining words (words matching all previous guesses), such that the guess splits the words intomaximize the most number of groupspossible outcomes. For example, at the start, we guess "trace". This splits the possible secrets into 150 groups, only one of which is possible based on the feedback. For the second guess, if we guess a word from that group, then there is 1 universe where we guess correctly. Thus in total, we have 150 universes where we guess correctly within the first 2 turns. By maximizing the number of groups each turn, we can make sure that there are more universes where we guess correctly early on.

  • If we have too few remaining words, then we might have to guess a word outside of those, to get the best split. Specifically, I allow selecting from outside if we're at the 3rd guess (or after) and there are less than 100 remaining words.
  • I brute forced search a some hard subtrees (e.g. 'trace' -> 'risen') to get the worst case at most 5 guesses.

Python 3, (1, 149, 840, 1213, 112)

from collections import Counter # history: a list of tuple of (guess, feedback) # feedback: a list of length 5, each element can be MISS, CLOSE, or MATCH def play(history): # Hard coded first guess turn = len(history) + 1 if turn == 1: return 'trace' # When there are few words left remaining_words = [word for word in WORDS if all(get_feedback(guess, word) == feedback for guess, feedback in history)] if len(remaining_words) <= 2: return remaining_words[0]   # Hardcoded hard case if turn == 3 and history == [('trace', [MISS, CLOSE, MISS, MISS, CLOSE]), ('risen', [CLOSE, MISS, MISS, MATCH, MISS])]: return 'howdy' guess_list = WORDS if turn > 2 and len(remaining_words) < 100 else remaining_words return find_best_guest(guess_list, remaining_words)   def find_best_guest(guess_list, secret_list): R = [] for guess in guess_list: c = Counter([tuple(get_feedback(guess, secret)) for secret in secret_list]) R.append([guess, len(c), max(c.values())]) best_guess = max(R, key=lambda t:(t[1],-t[2])) return best_guess[0] 

Try it online!

Scorer

Each time, I pick the guess from the list of remaining words (words matching all previous guesses), such that the guess splits the words into the most number of groups. For example, at the start, we guess "trace". This splits the possible secrets into 150 groups, only one of which is possible based on the feedback. For the second guess, if we guess a word from that group, then there is 1 universe where we guess correctly. Thus in total, we have 150 universes where we guess correctly within the first 2 turns. By maximizing the number of groups each turn, we can make sure that there are more universes where we guess correctly early on.

  • If we have too few remaining words, then we might have to guess a word outside of those, to get the best split. Specifically, I allow selecting from outside if we're at the 3rd guess (or after) and there are less than 100 remaining words.

Python 3, (1, 149, 945, 1118, 102)

from collections import Counter # history: a list of tuple of (guess, feedback) # feedback: a list of length 5, each element can be MISS, CLOSE, or MATCH def play(history): # Hard coded first guess turn = len(history) + 1 if turn == 1: return 'trace' # When there are few words left remaining_words = [word for word in WORDS if all(get_feedback(guess, word) == feedback for guess, feedback in history)] if len(remaining_words) <= 2: return remaining_words[0]   # Hardcoded hard case if turn == 3 and history == [('trace', [MISS, CLOSE, MISS, MISS, CLOSE]), ('risen', [CLOSE, MISS, MISS, MATCH, MISS])]: return 'howdy' guess_list = WORDS if turn > 2 and len(remaining_words) < 100 else remaining_words return find_best_guest(guess_list, remaining_words)   def find_best_guest(guess_list, secret_list): R = [] secret_set = set(secret_list) for guess in guess_list: c = Counter([tuple(get_feedback(guess, secret)) for secret in secret_list]) R.append([guess, len(c), guess in secret_set, -max(c.values())]) best_guess = max(R, key=lambda t:t[1:]) return best_guess[0] 

Try it online!

Scorer

Each time, I pick the guess from the list of remaining words (words matching all previous guesses), such that the guess maximize the number of possible outcomes. For example, at the start, we guess "trace". This splits the possible secrets into 150 groups, only one of which is possible based on the feedback. For the second guess, if we guess a word from that group, then there is 1 universe where we guess correctly. Thus in total, we have 150 universes where we guess correctly within the first 2 turns. By maximizing the number of groups each turn, we can make sure that there are more universes where we guess correctly early on.

  • If we have too few remaining words, then we might have to guess a word outside of those, to get the best split. Specifically, I allow selecting from outside if we're at the 3rd guess (or after) and there are less than 100 remaining words.
  • I brute forced search a some hard subtrees (e.g. 'trace' -> 'risen') to get the worst case at most 5 guesses.
add readable function
Source Link
Surculose Sputum
  • 8.4k
  • 1
  • 14
  • 40
from collections import Counter, defaultdict from # itertoolshistory: importa zip_longest deflist find_best_guestof tuple of (guess_listguess, secret_listfeedback): # feedback: Ra =list [] of length for5, guesseach inelement guess_list: can be MISS, CLOSE, cor =MATCH def Counter([tuple(get_feedbackplay(guess, secret)history):  for secret# inHard secret_list]) coded first guess  R.append([guess,turn = len(chistory), max(c.values())]) + 1  best_guess =if max(R,turn key=lambda== t1:(t[1],-t[2]))   return best_guess[0]'trace' def search( # When there are few words,forced_guess=None,depth=1,history=tuple()): left  remaining_words = [word for word in WORDS if lenall(wordsget_feedback(guess, word) == 1:feedback returnfor [1]guess, feedback in history)] elifif len(wordsremaining_words) ==<= 2:  return [1,remaining_words[0]  1]   # Hardcoded hard case if depthturn == 3 and history == [('trace', (0[MISS, 1CLOSE, 0MISS, 0MISS, 1CLOSE]), ('risen', (1[CLOSE, 0MISS, 0MISS, 2MATCH, 0)MISS])]: # Special case for hard subtree guess =return 'howdy' else:  # Normal case   guess_list = WORDS if depthturn > 2 and len(wordsremaining_words) < 100 else wordsremaining_words   guessreturn =find_best_guest(guess_list, forced_guessremaining_words)  or  def find_best_guest(guess_list, wordssecret_list): dR = defaultdict(list)[] for secretguess in wordsguess_list: fc = tupleCounter([tuple(get_feedback(guess, secret))  d[f].append(secret) recursive_results = [search(words2,depth=depth+1,history=history+(guess,t)) for t, words2secret in d.items() if t != (2,2,2,2,2secret_list])]   correct = 0 + (R.append(2,2,2,2[guess,2) in dlen(c)   result = [correct,*map max(sum,zip_longestc.values(*recursive_results, fillvalue=0))] if len(result) + depth > 6:   print(depth, result,best_guess guess,= lenmax(words)R, history)  if depth >key=lambda 1t: print(" ", "t[1],".join(words-t[2])) return result FIRST_GUESS = "trace" print(search(WORDS, "trace"))best_guess[0] 

Try it online!Try it online!

Scorer

from collections import Counter, defaultdict from itertools import zip_longest def find_best_guest(guess_list, secret_list): R = []  for guess in guess_list:  c = Counter([tuple(get_feedback(guess, secret)) for secret in secret_list])  R.append([guess, len(c), max(c.values())])  best_guess = max(R, key=lambda t:(t[1],-t[2])) return best_guess[0] def search(words,forced_guess=None,depth=1,history=tuple()): if len(words) == 1: return [1] elif len(words) == 2: return [1, 1] if depth == 3 and history == ('trace', (0, 1, 0, 0, 1), 'risen', (1, 0, 0, 2, 0)): # Special case for hard subtree guess = 'howdy' else:  # Normal case   guess_list = WORDS if depth > 2 and len(words) < 100 else words   guess = forced_guess or find_best_guest(guess_list, words) d = defaultdict(list) for secret in words: f = tuple(get_feedback(guess, secret))  d[f].append(secret) recursive_results = [search(words2,depth=depth+1,history=history+(guess,t)) for t, words2 in d.items() if t != (2,2,2,2,2)]   correct = 0 + ((2,2,2,2,2) in d)   result = [correct,*map(sum,zip_longest(*recursive_results, fillvalue=0))] if len(result) + depth > 6:   print(depth, result, guess, len(words), history)  if depth > 1: print(" ", ",".join(words)) return result FIRST_GUESS = "trace" print(search(WORDS, "trace")) 

Try it online!

from collections import Counter  # history: a list of tuple of (guess, feedback) # feedback: a list of length 5, each element can be MISS, CLOSE, or MATCH def play(history):  # Hard coded first guess  turn = len(history) + 1  if turn == 1:   return 'trace'  # When there are few words left  remaining_words = [word for word in WORDS if all(get_feedback(guess, word) == feedback for guess, feedback in history)] if len(remaining_words) <= 2:  return remaining_words[0]     # Hardcoded hard case if turn == 3 and history == [('trace', [MISS, CLOSE, MISS, MISS, CLOSE]), ('risen', [CLOSE, MISS, MISS, MATCH, MISS])]: return 'howdy' guess_list = WORDS if turn > 2 and len(remaining_words) < 100 else remaining_words return find_best_guest(guess_list, remaining_words)    def find_best_guest(guess_list, secret_list): R = [] for guess in guess_list: c = Counter([tuple(get_feedback(guess, secret)) for secret in secret_list]) R.append([guess, len(c), max(c.values())]) best_guess = max(R, key=lambda t:(t[1],-t[2])) return best_guess[0] 

Try it online!

Scorer

added 185 characters in body
Source Link
Surculose Sputum
  • 8.4k
  • 1
  • 14
  • 40

Each time, weI pick the guess from the list of remaining words (words matching all previous guesses), such that the guess splits the words into the most number of groups. For example, at the start, we guess "trace". This splits the possible secrets into 150 groups, only one of which is possible based on the feedback. For the second guess, if we guess a word from that group, then there is 1 universe where we guess correctly. Thus in total, we have 150 universes where we guess correctly within the first 2 turns. By maximizing the number of groups each turn, we can make sure that there are more universes where we guess correctly early on.

Following the naive strategy above, the result is (1, 149, 1044, 904, 178, 31, 7, 1). If we score by lexicographical order from left to right, without caring about the length of the tuple, then this is the largest tuple possible. Heuristically, this is good since if the left entries of the tuple are as large as possible, then the right most entries will be small. However, because the most important criteria is the length of the tuple, I have to tweak this algorithm a bit to get rid of all cases that have >5 turns.

Optimization

  • If we have too few remaining words, then we might have to guess a word outside of those, to get the best split. Specifically, I allow selecting from outside if we're at the 3rd guess (or after) and there are less than 100 remaining words.

Each time, we pick the guess from the list of remaining words (words matching all previous guesses), such that the guess splits the words into the most number of groups.

Each time, I pick the guess from the list of remaining words (words matching all previous guesses), such that the guess splits the words into the most number of groups. For example, at the start, we guess "trace". This splits the possible secrets into 150 groups, only one of which is possible based on the feedback. For the second guess, if we guess a word from that group, then there is 1 universe where we guess correctly. Thus in total, we have 150 universes where we guess correctly within the first 2 turns. By maximizing the number of groups each turn, we can make sure that there are more universes where we guess correctly early on.

Following the naive strategy above, the result is (1, 149, 1044, 904, 178, 31, 7, 1). If we score by lexicographical order from left to right, without caring about the length of the tuple, then this is the largest tuple possible. Heuristically, this is good since if the left entries of the tuple are as large as possible, then the right most entries will be small. However, because the most important criteria is the length of the tuple, I have to tweak this algorithm a bit to get rid of all cases that have >5 turns.

Optimization

  • If we have too few remaining words, then we might have to guess a word outside of those, to get the best split. Specifically, I allow selecting from outside if we're at the 3rd guess (or after) and there are less than 100 remaining words.
added 185 characters in body
Source Link
Surculose Sputum
  • 8.4k
  • 1
  • 14
  • 40
Loading
Source Link
Surculose Sputum
  • 8.4k
  • 1
  • 14
  • 40
Loading