Skip to content

Instantly share code, notes, and snippets.

@matthewd
Forked from tenderlove/fallout.rb
Last active April 4, 2019 00:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewd/28fd2869f88c6f93a5ac to your computer and use it in GitHub Desktop.
Save matthewd/28fd2869f88c6f93a5ac to your computer and use it in GitHub Desktop.
hack fallout terminals
##
# Program to help you hack terminals in Fallout
#
# Usage:
#
# Run this program with a '/' separated list of possible words, and
# (once you've made a guess) another '/' separated list of words and
# scores where the word and score are separated by a ':'
#
# In this example, the words shown in my terminal were:
#
# CASTE
# LINES
# ALTER
# OFFER
# KEEPS
# HAVEN
# SPEED
# BASIC
#
# I hadn't made a guess yet, so I started by running this:
#
# ```
# $ ruby fallout.rb CASTE/LINES/ALTER/OFFER/KEEPS/HAVEN/SPEED/BASIC
# ["CASTE", "LINES", "ALTER", "OFFER", "KEEPS", "HAVEN", "SPEED", "BASIC"]
#
# Next guess: "ALTER" 3 guesses remaining
# ```
#
# As instructed, I chose "ALTER", and the terminal said it scored 0, so
# I ran this:
#
# ```
# $ ruby fallout.rb CASTE/LINES/ALTER/OFFER/KEEPS/HAVEN/SPEED/BASIC ALTER:0
# ["CASTE", "KEEPS", "BASIC"]
#
# Next guess: "BASIC" 1 guesses remaining
# ```
#
# Notice we skipped "2 guesses remaining": the estimate of 3 was in case
# ALTER scored 1.
#
# BASIC scored 2, so I ran this:
#
# ```
# $ ruby fallout.rb CASTE/LINES/ALTER/OFFER/KEEPS/HAVEN/SPEED/BASIC ALTER:0/BASIC:2
# ["CASTE"]
#
# Final answer: CASTE
# ```
#
# The only choice left is "CASTE", and it is the correct answer!
def count w1, w2
w1.chars.zip(w2.chars).count { |a,b| a == b }
end
def hack w, t
t.inject(w - t.map(&:first)) { |c, (w1, s)|
c.find_all { |w2|
s.to_i == count(w1, w2)
}
}
end
def solve w, t, m
dw = hack(w, t)
return 0 unless dw.size > 1
return 1 if dw.size == 2
dw.map {|a|
solve(w, t + [[a, m[a]]], m)
}.max + 1
end
w, t = ARGV[0].split('/'), (ARGV[1] || '').split('/').map { |x| x.split(':') }
dw = hack(w, t)
p dw
if dw.size > 1
hh = Hash.new { |h1, w1| h1[w1] = Hash.new { |h2, w2| h2[w2] = count(w1, w2) } }
(maximum,), guess = dw.map { |w1|
[dw.map { |w2|
m = hh[w2]
solve(w, t + [[w1, m[w1]]], m) + 1
}.sort.reverse, w1]
}.sort.first
puts
puts "Next guess: #{guess.inspect} #{maximum} guesses remaining"
puts
else
puts
puts "Final answer: #{dw.first}"
puts
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment