Skip to content

Instantly share code, notes, and snippets.

@mstahl
Last active December 21, 2015 16:58
Show Gist options
  • Save mstahl/6336888 to your computer and use it in GitHub Desktop.
Save mstahl/6336888 to your computer and use it in GitHub Desktop.

Fallout 3 terminal hacker

Enter all the words as arguments on the command line,

user$ fallout_3 clustered mentioned stationed convinces eliminate convinced \
      convicted criminals challenge chemicals considers carriages cardinals \
      rearguards hurriedly continued consisted messianic gladiator chemistry
  0:  clustered
  1:  mentioned
  2:  stationed
  3:  convinces
  4:  eliminate
  5:  convinced
  6:  convicted
  7:  criminals
  8:  challenge
  9:  chemicals
  10: considers
  11: carriages
  12: cardinals
  13: rearguard
  14: hurriedly
  15: continued
  16: consisted
  17: messianic
  18: gladiator
  19: chemistry
fallout_3> 

You may then enter in a number (or the word itself) followed by another number, which is the number of matching letters. As you enter in more words, the list of words you can enter diminishes. Once the solver is confident that it has found the right word, it quits.

require 'pp'
class Puzzle
attr_reader :words
def initialize(words = [])
@words = words
end
def add_clue(word, num_matching_chars)
@clues ||= {}
@clues[word] = num_matching_chars
end
def potential_solutions
# Set of potential solutions is the set of words in the original vocabulary
# (@words) which, for each clue, have the same number of letters in common
# with that previous guess as that guess had with the correct password. So,
# if "conductor" had 3 letters in common with the solution, then
# "confluence" could be a solution but "condiment" could not because it has
# too many letters in common with the clue.
return self.words if @clues.nil? or @clues.empty?
self.words.select do |word|
@clues.all?{|k, v| k != word and num_matching(k, word) == v}
end
end
private
def num_matching(a, b)
# a.each_with_index do |c, i|
# matches += 1 if c == b[i]
# end
# Let's make this function as absurd as possible why don't we....
a.split(//).zip(b.split(//)).map{|x, y| x == y ? 1 : 0}.reduce(:+)
end
end
# Main -------------------------------------------------------------------------
def main()
puzzle = Puzzle.new(ARGV)
p puzzle
p puzzle.potential_solutions
until puzzle.potential_solutions.count <= 1
puts "Potential solutions:"
puzzle.potential_solutions.each_with_index do |s, i|
puts(" %2d: #{s}" % i)
end
print "Choose a guess: "
guess = $stdin.gets.chomp
print "What was the response? "
matches = $stdin.gets.to_i
puzzle.add_clue(guess, matches)
end
case puzzle.potential_solutions.count
when 1
puts "Solution found: #{puzzle.potential_solutions.first}"
when 0
puts "No solutions found! Try again."
end
end
if __FILE__ == $0
main
end
# vim: set ft=ruby:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment