Welcome, guest | Sign In | My Account | Store | Cart

crackerhacker.py is a script I wrote as a Python learning exercise to help solve Fallout 3's "terminal hacking" minigame. Many of you may already be aware of this annoying mind challenge after playing the popular waste of time from Bethesda Softworks on your favorite pc or console.

more details in the script

Python, 113 lines
  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
#!/usr/bin/python

#
#  Copyright Bill Sharer 2008
#  Distributed under the terms of the GNU General Public License v2 or later
#

#
#  crackerhacker.py is a script I wrote as a Python learning exercise to help
#  solve Fallout 3's "terminal hacking" minigame.  Many of you may already be
#  aware of this annoying mind challenge after playing the popular waste of
#  time from Bethesda Softworks on your favorite pc or console.
#
#  The minigame presents a "green screen" like terminal with what apparently
#  is a dump of some mainframe's password program file.  In amongst the noise
#  are a set of words that are all the same length.  As you hover your mouse
#  over each of these words, that word becomes a guess that you may take on
#  the command line.  The following ascii excerpt of an example screen is
#  taken from DrAgRoS' terminal hacking guide from gamespot.com (I was too
#  lazy to type one on my own)
#
# ---------------------------------------------------------
# ROBCO INDUSTRIES (TM) TERMLINK PROTOCOL                  |
# ENTER PASSWORD NOW                                       |
#                                                          |
# 4 ATTEMPT(S) LEFT : [] [] [] []                          |
#                                                          |
# 0xF92C %*-}'!.-[)#! 0xF9F8 :($-?!!}'%_(                  |
# 0xF938 (>!];-/\[=(, 0xFA04 /?;_;#"]!!:,                  |
# 0xF944 @PARTNERSHIP 0xFA10 %'%{.@@}#?|+                  |
# 0xF950 S=\]%,*?++:] 0xFA1C ="||^<@-|PUR                  |
# 0xF96C #\--(??%=^\? 0xFA28 IFICATION(^S                  |
# 0xF978 ]$/!]'|]=}"| 0xFA34 ECLUSIONIST>                  |
# 0xF984 REPRIMANDING 0xFA40 .,"CONSTRUCT                  |
# 0xF980 :(%CIVILIZAT 0xFA4C ION@'_'=':'>                  |
# 0xF99C ION:(]=%?|{A 0xFA58 =!.;/'+.@'/D                  |
# 0xF908 PPRECIATION' 0xFA64 ISAPPEARING%                  |
# 0xF9A4 :*CONVERSATI 0xFA70 ,]%?<TRANSMI                  |
# 0xF9B0 ON=.:="+$@#< 0xFA7C SSION,}"/'},                  |
# 0xF9BC ['<'%':}!%;+ 0xFA88 \"%\^?<(|APP                  |
# 0xF9C8 '('#'?,.%*!+ 0xFA94 REHENSIVE}<+                  |
# 0xF9D4 =\.\?/(!|#?< 0xFAA0 "<\^+].^^'._                  |
# 0xF9E0 |[)???@?%{CI 0xFAAC ;++}{=/'\ENC                  |
# 0xF9EC RCUMSTANCE_= 0xFAB8 OUNTERING*}; >[]              |
# ---------------------------------------------------------
# 
# 						   ------
# 						   |    |
# 					    POWER  ------
#
#
#  You only have four guesses (although as the guide mentions, there may be ways
#  to reset the challenge).  When you make an incorrect guess, the terminal
#  shows the number of characters that matched the correct guess.  This match
#  count is a character by character comparison of the guess against the correct
#  password.
#
#  You will be permanently locked out of the terminal after four incorrect
#  guesses, but using the script, I have yet to not have the list narrowed down
#  to a single choice by the fourth attempt.
#

words = []
while True :
    line = raw_input("word> ")
    if line != "" :
        words.append(line)
    else :
        break

word_matrix = {}
for word in words :
    word_matrix[word] = {}
    for key in word_matrix.keys() :
        match = 0
        i = 0
        while i < len(key) :
            if key[i] == word[i] :
                match += 1
            i += 1
        word_matches = word_matrix[key]
        word_matches[word] = match
        word_matches = word_matrix[word]
        word_matches[key] = match

for key in word_matrix.keys() :
    word_matches = word_matrix[key]
    nonzero = 0
    sum = 0
    for word in word_matches.keys() :
        if word != key :
            if word_matches[word] > 0 :
                nonzero += 1
                sum += word_matches[word]
    if nonzero > 0 :
        print key, "matches",  nonzero, " avg", sum/nonzero

narrowed = set(words)

while True :
    guesses = []
    guess = raw_input("guess> ")
    if guess == "" :
        break
    matches = input("matches> ")
    word_matches = word_matrix[guess]
    for word in word_matches.keys() :
        if word_matches[word] == matches :
            guesses.append(word)

    narrowed = narrowed & set(guesses)
    for word in narrowed :
        print word

So I probably should have posted this on some "1337" gamer site, but I would rather get spam from a developer site. Besides, the script is a concise example of text processing using dictionaries, lists and sets. I'm an old perl guy learning python, so apologies in advance ;-)

Here is an example of the script in action from an actual minigame. I typed in the list of 18 strings and then made three guesses (companies, disparate and ransacked) leaving the single choice of the correct password monstrous for the fourth attempt

word> distances word> entrances word> primarily word> disparate word> ransacked word> concerned word> monstrous word> companies word> histories word> contained word> converted word> preparing word> disagrees word> commanded word> batteries word> chemicals word> convinced word> possesses word> distances matches 17 avg 2 entrances matches 17 avg 2 disagrees matches 17 avg 2 disparate matches 16 avg 1 ransacked matches 17 avg 2 convinced matches 14 avg 3 concerned matches 17 avg 2 monstrous matches 17 avg 1 companies matches 17 avg 3 histories matches 17 avg 2 contained matches 17 avg 2 converted matches 17 avg 2 preparing matches 16 avg 1 primarily matches 16 avg 1 commanded matches 17 avg 2 batteries matches 17 avg 2 chemicals matches 17 avg 1 possesses matches 17 avg 2 guess> companies matches> 2 disagrees disparate ransacked monstrous chemicals primarily guess> disparate matches> 1 chemicals monstrous ransacked guess> ransacked matches> 2 monstrous guess>

4 comments

Bill Sharer (author) 12 years, 11 months ago  # | flag

As I suspected, the example in the discussion mangled the example minigame in the discussion section. There should be a new line after each word and guess prompt.

J G 12 years, 11 months ago  # | flag

have you encountered any situations where the game reported impossible and incorrect info regarding number of matches? during my playing and solving them manually, every so often it would give me a mathematically impossible result, or so I thought. just curious if the script confirms this, so I know im not crazy :)

nice idea for a recipe though!

Bill Sharer (author) 12 years, 11 months ago  # | flag

I just finished the game last night (pc version) and didn't encounter any inconsistent match counts. However I did finally hit one minigame where I hadn't narrowed the list down to a single word by the fourth try. As my science skill went up to 100 the number of words in each minigame went down. That one anomoly was somewhere in the middle of the leveling where I was probably working on a "hard" terminal. When I was at 100, I'm pretty sure I was hitting the choice on the 2nd guess since just about all of the terms were "average" and I only had four choices initially.

greg p 12 years, 10 months ago  # | flag

I just made my own version here. I borrowed your descriptions.

Created by Bill Sharer on Sat, 20 Dec 2008 (MIT)
Python recipes (4591)
Bill Sharer's recipes (2)

Required Modules

  • (none specified)

Other Information and Tasks