Zombie noises

So... the important things in life include zombies, obviously. Therefore, a program that mangles words into something a zombie might have said must be pretty damn important as well.

That's what it does. It takes a bunch of text and applies some basic transformations to it at random. The transformation multiplies some letters, removes some letters or replaces some letters with entire bits of (short) mangled text. And when there's an empty line somewhere, a generic answer might appear. And sometimes nothing happens... that's zombies for you.

It's actually a re-write of an earlier program I did in the Ocaml programming language; however I could not stop myself from writing it. Comes with the added benefit that it's a script now and does not need recompilation every time you want to add a noise.

It has several modes, so you get to put files and pipes through it or converse with it. The former is good to produce, i.e., a zombie translation of De Bello Gallico by Mr Dog.

The latter is far more interesting, and perhaps dangerous. Some people spend hours on end conversing with the zombie... and I swear, that thing gets intelligent at you, when you're not expecting it!

Right. And it comes with a simple way for people to tinker with it. To add a letter that gets multiplied, include it at lines 37 - 39; and the number of times it might get multiplied is defined in line 43. The removed letters are defined at lines 58 - 61. Generic sounds are defined at lines 29 - 31.

Right, and there are two other number to adjust - the time the zombie thinks of a response in conversation mode (line ) and the odds defining when a the zombie mangles text. It has two numbers there (in which we would call a tuple... if only we knew how to pronounce that) - 3,4 at the time, which means that the odds are 3 in 4 of the zombie doing some mangling.

The substitutions are defined at lines 49 - 52. Defining these is more tricky, since you have to put in two things... it's a bit taxing, I know, but I believe in you.

Oh, and it's GPL'd, so zombie noises is free software. That's free as in '...-range chicken'. Yeah, so feel free to modify it and stuff, if you want to. It's even nicely commented for that purpose.

Here's how to run it in conversation mode (two separate ways):

./zombie_noises.py -i
python zombie_noises.py -i

and here's how to run it with a pipe (two ways as well):

cat de_bello_gallico.txt | ./zombie_noises.py
cat de_bello_gallico.txt | python zombie_noises.py

and here's how to run it with a file (two ways):

./zombie_noises.py -f de_bello_gallico.txt
python zombie_noises.py -f de_bello_gallico.txt

and here's the Spanish Inquisition hiding behind a shed.

Right, enough banter, here's the code. You need Python to run it.
1  #!/usr/bin/python
2   
3  # Copyright 2008 Konrad Siek.
4  
5  # This program is free software: you can redistribute it and/
6  # or modify it under the terms of the GNU General Public 
7  # License as published by the Free Software Foundation, either 
8  # version 3 of the License, or (at your option) any later 
9  # version.
10 
11 # This program is distributed in the hope that it will be 
12 # useful, but WITHOUT ANY WARRANTY; without even the implied 
13 # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14 # PURPOSE. See the GNU General Public License for more 
15 # details.
16 
17 # You should have received a copy of the GNU General Public 
18 # License along with this program. If not, see 
19 # <http://www.gnu.org/licenses/>. 
20 
21 import sys
22 import time
23 import getopt
24 import random
25 
26 # A list of generic noises for the zombie to use when nothing
27 # else is available, i.e., when there was no input.
28 GENERIC_NOISES = [
29     'braaaains''coooffeee'
30     ':grunt:'':groan:',  
31     ':gurgle:'':burp:'':moan:'
32 ]
33 
34 # Characters that are easy for the zombie to elongate when 
35 # speaking, as 'a' in 'braaaains'.
36 ELONGATABLE = [
37     'a''e''i''o''u''y''r''s'
38     'A''E''I''O''U''Y''R''S',
39     '!'
40 ]
41 
42 # Maximum number of allowed repeated characters.
43 MAX_ELONGATION = 6
44 
45 # Characters which zombies make an effort to reproduce but 
46 # sometimes fail. Or maybe they do it for the slurrin effect.
47 # It's sometimes hard to tell with zombies.
48 SUBSTITUTABLE = {
49     'n': 'ngh',   'N': 'NGH',
50     'k': 'kh',   'K': 'KH',
51     'g': 'gh',   'G': 'GH',
52     '?': '!'
53 }
54 
55 # Characters which zombies have trouble pronuning, so they 
56 # tend to drop them altogether. This is mostly punctuation.
57 REMOVABLE = [ 
58     '.'','';''-',   '@''#''$''%',
59     '^''&''*''(',   ')''_''+''=',
60     '{''}''['']',   ':''"''\'''', 
61     '|''<''>''/',   '`''~'      
62 ]
63 
64 # The odds deciding the chance of a character being mangled
65 # by a zombie. The higher the value of the second part, the 
66 # *less* likely the zombie is to touch a given character. The
67 # higher the value of the first part, the *more* likely the 
68 # zombie is to touch a given character. The value of one to 
69 # one will cause all opportunities to mangle to be utilized.
70 # The suggestion here, is to use values generally close to 
71 # one, especially in conversation mode.
72 ODD_FACTOR = (34)
73 
74 # Prompts used for interactive mode to represent the user's 
75 # input to the conversation and the zombie's reponses.
76 USER_PROMPT = 'You: '
77 ZOMBIE_PROMPT = 'Zombie: '
78 
79 # Message used for interactive mode to indicate the time when
80 # the zombie is cogitating.
81 ZOMBIE_THINKS = "(zombie thinks)"
82 
83 # The maximum amount of time for the zombie to conjure a
84 # response, mesaured in seconds. Should be greater or equal to
85 # one.
86 THINK_TIME = 6
87 
88 # A dictionary to all the characters with manglers appropriate
89 # for their class. Intentionally left empty. This will fill up 
90 # later automatically. 
91 MANGLERS = {}
92 
93 def zombify(string):
94     """ Throughputs a string through a zombie producing a 
95         mangled and more interesting alternative to the
96         original input. 
97  
98         A certain class of characters can be removed, some 
99         characters can be multiplied and some can be 
100        substituted for other characters or phrases. And when 
101        the input is empty, a random noise can be made.
102 
103        @param string before a zombie mangles it.
104 
105        @return string after a zombie mangles it.
106    """
107    # If there's nothing in the line, then there's an
108    # opportunity to insert a generic word here. This is a
109    # high-probability event, because we like zombies to say
110    # 'braaaains' and ':grunt:' a lot.
111    if len(string.strip()) == 0:
112        if lottery():
113            return random.choice(GENERIC_NOISES) + "\n"
114        else:
115            return string
116
117    # Check out each character now, and try to apply some 
118    # gruesome mangling to them, if odds allow. This is a 
119    # typical probability event and uses odds. Also, if 
120    # there is no mangler available for use, just ignore the 
121    # character - opportunity wasted.
122    result = ""
123    for character in string:
124        if lottery() and character in MANGLERS:
125            # Select the appropriate class for the character
126            # and use the function appropriate for that class.
127            mangler = MANGLERS[character]
128            result += mangler(character)
129        else:
130            result += character
131    return result
132
133def elongate(character):
134    """ Elongate a character or string a random number of
135        times.
136        
137        @param character to elongate.
138        
139        @return elongated string of characters.
140    """
141    return random.randint(2, MAX_ELONGATION) * character
142
143def remove(character):
144    """ Ignore a character.
145        
146        @param character to ignore.
147        
148        @return empty string.
149    """
150    return ''
151
152def substitute(character):
153    """ Replace a character with the defined substitution. 
154        
155        @throw in case the substitution is not present throw 
156        a KeyError exception.
157        
158        @param character to replace with a string.
159        
160        @return replacement string.
161    """
162    return SUBSTITUTABLE[character]
163
164def lottery():
165    """ A simple binary lottery, with odds of success equal 
166        to ODD_FACTORY[0] in ODD_FACTOR[1].
167        
168        @return either True or False, in a random fashion.
169    """
170    return random.randint(ODD_FACTOR[0], ODD_FACTOR[1]) \
171            in range(1, ODD_FACTOR[0] + 1)
172
173def handle_pipe():
174    """ Zombify individual lines, one by one, so a file or
175        on-the-fly input can be processed. A method to work
176        with large input.
177 
178        @return Generally, True if the processing should be 
179        stopped afterwards and False if it should go on. Here,
180        always True.
181    """
182    for line in sys.stdin:
183        line = zombify(line)
184        sys.stdout.write(line)
185    sys.stdout.write("\n") 
186
187    return True
188
189def handle_interactive():
190    """ Zombify input in a form of conversation with the
191        user, with an additional effect of simulating a zombie
192        in the process of conceptualizing. That process could 
193        take a bit of time, so there is a delay introduced.
194 
195        @return Generally, True if the processing should be 
196        stopped afterwards and False if it should go on. Here,
197        always True.
198    """
199    # Secure in case amodifying user does not understand the 
200    # concept of 'greater or equal'.
201    if THINK_TIME < 1:
202        sys.stderr.write("THINK_TIME, must be at least 1")
203        return True
204    
205    # Continue conversation endlessly!
206    while True:
207        try:
208            line = raw_input(USER_PROMPT)
209            print(ZOMBIE_THINKS)
210            think_time = random.randint(1, THINK_TIME)
211            time.sleep(think_time) 
212            response = zombify(line)
213            print(ZOMBIE_PROMPT + response)
214        except:
215            print
216            break
217
218    return True
219
220def handle_file(path):
221    """ Zombify input taken directly from a named file. The
222        file is processed one line after another and the 
223        output is directed to stdout. It's a sort of batch-
224        -processed zombie then.
225 
226        @return Generally, True if the processing should be 
227        stopped afterwards and False if it should go on. Here,
228        always False, unless an error appears, then True.
229    """
230    try:
231        input_file = open(path)
232        for line in input_file:
233            line = zombify(line)
234            sys.stdout.write(line)
235        sys.stdout.write("\n")
236    except:
237        sys.stderr.write("Cannot open file: " + path + "\n"); 
238        return True
239    
240    return False
241
242def handle_word(word):
243    """ Zombify a single word and continue processing. This 
244        can be used in conjunction with other command, 
245        although I can't imagine what for. 
246 
247        @return Generally, True if the processing should be 
248        stopped afterwards and False if it should go on. Here,
249        always False.
250    """
251    word = zombify(word)
252    sys.stdout.write(word)
253    sys.stdout.write("\n") 
254
255    return False
256
257def handle_params(params):
258    """ Zombify all the parameters as individual lines. It's 
259        the zombie's way of making fun of you typing in 
260        incorrect parameters. This is also a way to work with
261        the program arguments vector as input, if you want to
262        do it that way.
263 
264        @return Generally, True if the processing should be 
265        stopped afterwards and False if it should go on. Here,
266        always True.
267    """
268    for param in params:
269        param = zombify(param)
270        sys.stdout.write(param)
271        sys.stdout.write("\n") 
272
273    return True
274
275def print_usage():
276    """ Prints usage information for the program.
277 
278        @return Generally, True if the processing should be 
279        stopped afterwards and False if it should go on. Here,
280        always False.
281    """
282    print(\
283 """Usage:
284    zombie_noises.py [parameters]
285    
286 Parameters:
287    -p  process standard input (default for no parameters)
288    -i  converse interactively
289    -f  {filename}  process file (and continue)
290    -w  {word}      process words (and continue)
291    -h  show usage screen (and continue)
292        
293 Author:
294    Konrad Siek <konrad.siek@gmail.com>
295 
296 License: 
297    GNU General Public License
298 """\
299    )
300
301    return False
302
303def resolve_opts(opt_handlers, def_handler, arg_handler):
304    """ Handles all the options and parameters for the script
305        with the provided functions. 
306    
307        @param opt_handlers: a dictionary, translating an 
308        option string to a function. Depending on whether the 
309        function is parameterless or has one parameter the 
310        option string will be just a letter or a letter ending 
311        in a colon.
312 
313        @param def_handler: a function used to handle the 
314        program when no parameters or arguments are present.
315        This is a parameterless function.
316    
317        @param arg_handler: a function used to handle all 
318        the arguments - it takes one parameter.
319    """ 
320    string = "".join(["%s" % (i) \
321                            for i in opt_handlers.keys()])
322    options, arguments = getopt.getopt(sys.argv[1:], string)
323
324    # Handle options.
325    for key, value in options:        
326        if value != '':
327            stop = opt_handlers[key[1:]+":"](value)
328        else:
329            stop = opt_handlers[key[1:]]()
330        if stop:
331            return
332          
333    # Handle arguments.     
334    if len(arguments) > 0:
335        arg_handler(arguments)
336    
337    # Handle when no arguments or params are present.
338    elif len(options) == 0:
339        def_handler()
340
341# Execution starts here. Try to make out the arguments and
342# run the appropriate function.
343if __name__ == "__main__":
344    # Join all the classes into one giant dictionary. This 
345    # eliminates inconsistencies and makes manging functions
346    # easy to grab in the code for individual characters.
347    for character in ELONGATABLE:
348        MANGLERS[character] = elongate
349    for character in REMOVABLE:
350        MANGLERS[character] = remove
351    for character in SUBSTITUTABLE.keys():
352        MANGLERS[character] = substitute
353
354    # Define how to react to the various arguments.
355    options = {
356        "p" : handle_pipe,
357        "i" : handle_interactive,
358        "w:" : handle_word,
359        "f:" : handle_file,
360        "h" : print_usage
361    }
362    
363    # Run the functions appropriate to the options.
364    resolve_opts(options, options["p"], handle_params)


The code is also available at GitHub as python/zombie_noises.py.

lala moulati ana9a maghribia

seo

 

Blogroll

Site Info

Text

telechargementz Copyright © 2009 WoodMag is Designed by Ipietoon for Free Blogger Template