2

So I wrote a short and simple chat bot in Python, however there's an irritating issue. The program will only call the posResponses() function initially.

In context, if I respond to its initial question with 'sad', 'terrible' or even 'asdfasdfasdf' I will still get a positive response.

What should happen is if I input a negative/ambiguous keyword the negResponses()/ambiguousResponses() function should be called. That is not the case. What did I do wrong, and how do I fix it? Code is as follows:

import random
import time

def opening():
    print('Hello!')

def responseType():
    responseType = str(input('How are you ?'))
    if responseType == 'good' or 'great' or 'fantastic' or 'decent' or 'fine' or 'ok' or 'okay': posResponses()
    elif responseType == 'bad' or 'terrible' or 'sad' or 'grumpy' or 'angry' or 'irritated' or 'tired': negResponses()
    else: ambiguousResponses()

def posResponses():
    number = random.randint(1, 4)
    if number == 1:
        print('That\'s great! So what\'s up?')
        input()
        ambiguousResponses()
    if number == 2:
        print('Really? I\'d like to hear more.')
        input()
        ambiguousResponses()        
    if number == 3:
        print('I\'m glad to hear that. What\'s going on?')
        input()
        ambiguousResponses()        
    if number == 4:
        print('Ah, me too. You should begin a topic discussion.')
        input()
        ambiguousResponses()        

def negResponses():
    number2 = random.randint(5, 8)
    if number2 == 5:
        print('That\'s really too bad. Care to elaborate?')
        input()
        ambiguousResponses()
    if number2 == 6:
        print('Awww. Why?')
        input()
        ambiguousResponses()
    if number2 == 7:
        print('That sucks! How come?')
        input()
        ambiguousResponses()
    if number2 == 8:
        print('What a shame! You should explain why.')
        input()
        ambiguousResponses()

def ambiguousResponses():
    number = random.randint(1, 4)
    if number == 1:
        print('Interesting. Carry on.')
        input()
        ambiguousResponses()
    if number == 2:
        print('Wow, elaborate!')
        input()
        ambiguousResponses()
    if number == 3:
        print('What an astute remark! Continue.')
        input()
        ambiguousResponses()
    if number == 4:
        print('How interesting. Please do explain further.')
        input()
        ambiguousResponses()


if __name__ == "__main__":
    opening()
    responseType()
icktoofay
  • 126,289
  • 21
  • 250
  • 231
Stumbleine75
  • 391
  • 2
  • 7
  • 22
  • 1
    For all the number comparisons, instead of a series of `if`s using `elif`s will be clearer (and more efficient). Also the indentation in your listing is off (but probably due to being posted here) – Levon Aug 13 '12 at 01:33

2 Answers2

6

Python is parsing it like this:

if (responseType == 'good') or 'great' or 'fantastic' or 'decent' or 'fine' or 'ok' or 'okay': posResponses()
elif (responseType == 'bad') or 'terrible' or 'sad' or 'grumpy' or 'angry' or 'irritated' or 'tired': negResponses()
else: ambiguousResponses()

'great' is a truthy value, so that if statement always succeeds. You probably want to rewrite it like:

if responseType == 'good' or responseType == 'great' or responseType == 'fantastic' or responseType == 'decent' or responseType == 'fine' or responseType == 'ok' or responseType == 'okay':
    posResponses()
elif responseType == 'bad' or responseType == 'terrible' or responseType == 'sad' or responseType == 'grumpy' or responseType == 'angry' or responseType == 'irritated' or responseType == 'tired':
    negResponses()
else:
    ambiguousResponses()

Or, preferably:

if responseType in {'good', 'great', 'fantastic', 'decent', 'fine', 'ok', 'okay'}:
    posResponses()
elif responseType in {'bad', 'terrible', 'sad', 'grumpy', 'angry', 'irritated', 'tired'}:
    negResponses()

You could even move those responses into a constant:

# near the top of the file:
GOOD_RESPONSES = {'good', 'great', 'fantastic', 'decent', 'fine', 'ok', 'okay'}
BAD_RESPONSES = {'bad', 'terrible', 'sad', 'grumpy', 'angry', 'irritated', 'tired'}

# when you need to judge a response:
if responseType in GOOD_RESPONSES:
    posResponses()
elif responseType in BAD_RESPONSES:
    negResponses()
else:
    ambiguousResponses()
icktoofay
  • 126,289
  • 21
  • 250
  • 231
  • Nitpick: I don't think this would be a proper use of a tuple. GOOD_RESPONSES is a list of items, not a heterogeneous structure. See [What's the difference between list and tuples in Python?](http://stackoverflow.com/questions/626759/whats-the-difference-between-list-and-tuples-in-python) and [Python Tuples are Not Just Constant Lists](http://jtauber.com/blog/2006/04/15/python_tuples_are_not_just_constant_lists/) – Mark Hildreth Aug 13 '12 at 01:36
  • Your preferred method worked perfectly. Thank you very much! I also applied it to the negResponses function so that the ambiguous function could be called. – Stumbleine75 Aug 13 '12 at 01:38
  • @Mark: That's a good point. I've changed it to use lists rather than tuples. – icktoofay Aug 13 '12 at 01:41
  • I've changed my comment because apparently it is a better idea to use lists instead. The decision is unanimous. – Stumbleine75 Aug 13 '12 at 01:41
  • @ThroatOfWinter57: It's purely a semantic difference. Putting items in a tuple typically means that you're signifying that order matters. Dealing with 2D coordinates, for example: using a tuple like `(5, 3)` makes sense. If you start using tuples for list-purposes, you could confuse readers of your code who are expecting the order of the items in the tuple to have some meaning, when there is none. It probably won't have any change to the running of the code (it won't cause errors or anything like that). – Mark Hildreth Aug 13 '12 at 01:45
  • Ah yes, I totally agree. Making the lists of moods at the top rather than in the body also makes the code look more organized and helps me follow the logic path when skimming the code. – Stumbleine75 Aug 13 '12 at 01:57
  • In this case, you really don't want either a list or a tuple, you want a `set`.... – Danica Aug 13 '12 at 03:33
  • @Dougal: Oh, that's even better. I considered a `set`, but thought that using the `set` function would get in the way of understanding the rest. I forgot Python 3 added a set literal, but your comment made me remember. – icktoofay Aug 13 '12 at 06:25
0

posResponses is only being called once, because in posResponses you call ambiguousResponses, and in ambiguousResponses you call ambiguousResponses. So it will never exit ambiguousResponses, it will just keep calling ambiguousResponses until you run out of stack and the program crashes.

You have tried to make this program recursive. It shouldn't be, there should be a loop centered around the input() call, of which you only need one in the whole program, not 15 or whatever you have now.

But more blatantly wrong than that, your test of responses to see if they are positive or negative is not included in the recursion, hence the program only checks what response to output once.

Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251