6
\$\begingroup\$

Here is a little game modeled after adventure that I have been working on. The code initializes a set of lists. It sets a current location randomly generated. The user is tasked with either incrementing the index or de-incrementing the index (moving up and down the avenue). At each location there is a store which they can enter into. If they choose to, they can buy something if they have enough money. If they buy something, their need is met and they receive pleasure. The goal of the game is to meet all your needs and receive the most pleasure before the time runs out. At this point you have 30 turns to do so, or 30 iterations of the while loop in main().

I'm worried about bugs. Basically, the way I am tracking the decisions of the user to buy stuff is by index. Meaning, if a user is at index 3, then they can enter into the store which is also at index 3, and meet their need which is at index 3. I am tracking streets, stores, and needs in separate lists. But once a person meets their need, lets say they 'eat pizza', I pop the need off the list.

But what happens when I do that? The need which is 'next in line' to the index 3, for instance, goes to index 3. So someone would be able to meet the need of index 4 while going to the location at index 3. So the question in sum is:

What is the proper way to structure the data so that the 'need' of index 3 stays in index 3, even if the need at index 2 is popped off? Can the code be changed, or does the data structure need to be changed?

I'd also like any feedback regarding content.

import sys
from travels import *
import random
import collections

print("Welcome to Cavernous J. You have stumbled upon a quaint commercial strip, and have a couple of hours to satisfy all yours needs before it closes up.")
start()

#the function which initializes the game - the initial arrays, variables
def start():
    #initialize lists and variables
#   global Streets, Need, Locations, money, pleasure, Time, check, street_index, current_street
    global Need
    Streets= ["east 13th", "east 14th", "east 15th", "east 16th"]
    Need= ["food", "impress girlfriend", "clothing", "backache", "community"]
    Locations = ["pizza store", "flower shop", "shoe store", "massage parlor"]
    money = random.randint(200, 500)
    Time= ["1200PM", "100PM", "200pm"]
    pleasure = 0
    check = 0
#generate a starting point
    street_index = random.randint(0, len(Streets)-1)
    current_street = ""

#let the games begin
    main(Streets, Need, Locations, money, pleasure, Time, check, street_index, current_street)

#the main function - takes user input, and interacts with data accordingly
def main(Streets, Need, Locations, money, pleasure, Time, check, street_index, current_street):
#try:
    while len(Need) > 0 and len(Time) > 0:
        current_street= Streets[street_index]
    #   print ("Current Street = " + str(current_street))
    #   print ("Current Street Index = " + str(street_index))   
        check = check + 1
        if check > 10:
            Time.pop(0)
            check = 0
    #before the processessing is done, determine what the user enters
        user_input = raw_input("You are on Avenue J at " + current_street + ". It is " + Time[0] + ". You have $" +str(money) +". \n")
        user_answer = findAnswer(user_input, current_street)

    #print("User Input = " + user_input)
    #print("Numeric Value of User Input = " + str(user_answer))

    #start processesing
        #takes in the user input,  current street index
        #name of current street, list of locations, and current set of needs
        #outputs a string 
        if user_answer == 1:
            print(get_help(user_input, current_street, street_index, Locations, Need))
        #takes in list of streets, numeric value of user answer, current street index, current name of street
        #updates current street index accordingly
        elif user_answer >1 and user_answer <= 5:
            street_index = travel(Streets, user_answer, street_index, current_street)
        #takes in user input, numeric value of user input, name, index, and locations at current street 
        elif user_answer > 5 and user_answer <= 9:
            interaction = enter_store(user_answer, street_index, Locations, money, pleasure)
            if interaction[0] == "yes":
                money = interaction[1]
                pleasure = pleasure + interaction[2]
              #  print(money)
              #  print(pleasure)
            else:
                break
#if the user decides to discuss the finer matters
        elif user_answer ==10:
            discuss(user_input, user_answer, street_index)
        else:
            print("The lox tastes great!")
#except:
#   print ("You were unable to successfully meet all of your needs on Avenue J today. Try again tomorrow")
#takes in a number and outputs a string"""
    print("Total Needs Met = " + str(5-(len(Need))))
    print("Total pleasure = " + str(pleasure))
#find what the user entered
def findAnswer(answer, location):
#traveling answers
    if answer in ("look around", "help", "get help", "look", "jump"):
        return 1
    elif answer in ("walk north", "go north", "travel north", "turn north", "north"):
        return 2
    elif answer in ("walk south", "go south", "travel south", "turn south", "south"):
        return 3
    elif answer in ("walk east", "go east", "travel east", "turn east", "east"):
        return 4
    elif answer in ("walk west", "go west", "travel west", "turn west", "west"):
        return 5
#action answers
    elif answer in ("pizza", "go eat", "eat", "buy pizza", "eat pizza", "get pizza"):
        if location == "east 13th":
            return 6
    elif answer in ("flowers", "buy flowers", "get flowers", "smell flowers"):
        if location == "east 14th":
            return 7    
    elif answer in ("shoes", "go shop", "shop", "buy shoes", "get shoes"):
        if location == "east 15th":
            return 8
    elif answer in ("massage", "get massage"):
        if location == "east 16th":
            return 9
#interactions
        elif answer in ("argue", "debate", "discuss"):
            return 10

#incorrect answer, time goes forward
        else:
            return 11

#generates a list of prices given the users current location
def prices(location, user_answer):
    prices = []
    #user is in pizza shop  
    if user_answer ==6:
        for x in range(1, 5):
            prices.append(x*4)
    #user is in flower shop
    elif user_answer ==7:
        for x in range(1, 5):
            prices.append(x*10)

    #user is in shoe shop
    elif user_answer ==8:
        for x in range(1, 5):
            prices.append(x*100)

    #user is in massage parlor
    elif user_answer ==9:
        for x in range(1, 5):
            prices.append(x*30)

    else:
        return "Nothing"

    return prices

#if the user decides to ask for help
def get_help(user_input, current_street, street_index, Locations, Need):
    word = ""
    if user_input == "look around":
        word = "You looked around and saw a " + Locations[street_index] + "."
    elif user_input == "look":
        word = "You looked around and saw a " + Locations[street_index] + "."
    elif user_input == "help":
        word = "You asked for help and a passerby was kind enough to show you the " + Locations[street_index] + " nearby. He cautioned you to avoid political discussions as they often end in communal relationships."
    elif user_input == "get help":
        word = "You asked for help and a passerby was kind enough to show you the " + Locations[street_index] + " nearby. He cautioned you to avoid political discussions as they often end in communal relationships."
    elif user_input == "jump":
        word = "You went from degree to degree with a side topping of kangaroo boxing."         

    return word

#if the user decides to travel
def travel(Streets, user_answer, street_index, current_street):
# Streets, Need, Locations, money, pleasure, Time, check, street_index, current_street
#   print("User Input = " + user_input)
#    print("Numeric Value of User Input = " + str(user_answer))
#   print("Number of streets = " + str(len(Streets)))
#   print("Current Street = " + str(current_street))
    if user_answer == 2:
        print("you traveled north. You wandered around for a bit. After deciding there was not much of interest, you went back to where you were.")
    elif user_answer == 3:
        print("you traveled south. You wandered around for a bit. After deciding there was not much of interest, you went back to where you were.")
    elif user_answer == 4:
        if street_index + 1 < len(Streets):
#if the user decides to travel east, and are not at the edge of the map, go east
            street_index = street_index + 1
            current_street = Streets[street_index]
       #    print("Updated Street Index = " + str(street_index))
        #   print("Updated Street = " + current_street)
            print("You traveled east")
         #  print("Returning..." + str(street_index))
#if the user decides to travel east, and the are at the edge of the map, return an error
        else:
            print("Can't go further east")
    elif user_answer == 5:
        if street_index - 1 >= 0:
            street_index = street_index - 1
            current_street = Streets[street_index]
#       print("Updated Street Index = " + str(street_index))
#       print("Updated Street = " + current_street)
            print("You traveled west")
      #      print("Returning..." + str(street_index))
        else:
            print("Can't go further west")

    return street_index
#based on the response of the user
#generates a list of prices for goods at that location, queries the user about interacting, how much they wish to spend
#updates the money variable and pleasure variable accordingly
def enter_store(user_answer, street_index, Locations, money, pleasure):
    price_list = prices(Locations, user_answer)
    pLoc = ""
    p=""
    interact = collections.namedtuple('Interact', ['decision', 'money', 'pleasure'])
    for x in price_list:
        p = p + " $" + str(x) + ", "
    if user_answer == 6:
        pLoc = "You entered the pizza shop and see prices of " + p
        print pLoc[:-2]
        if raw_input("The pizza man asks you 'would you like something?' ")=="y" or "yes":
            mon = int(raw_input("How much do you wish to spend? "), base=10)
            if price_list.index(mon) < 10:
                if (money-mon)>0:
                    money = money - mon
                    pleasure = price_list.pop(price_list.index(mon))/2
                    Need.pop(street_index)
                    return(interact('yes', money, pleasure))
                else:
                    print("Sorry, but you ran out of money while shopping on Avenue J. Make some more before returning.")
                    return(interact('no', money, pleasure))
        else:
            print("You do not purchase any items")
            return(interact('no', money, pleasure))
    elif user_answer == 7:
        pLoc = ("you stopped off at the flower stand and see prices of" + p)
        print pLoc[:-2]
        if raw_input("The flower lady asks you 'would you like something?' ")=="y" or "yes":
            mon = int(raw_input("How much do you wish to spend? "), base=10)
            if price_list.index(mon) < 10:
                if (money-mon)>0:
                    money = money - mon
                    pleasure = price_list.pop(price_list.index(mon))/2
                    Need.pop(street_index)
                    return(interact('yes', money, pleasure))
                else:
                    print("Sorry, but you ran out of money while shopping on Avenue J. Make some more before returning.")
                    return(interact('no', money, pleasure))
        else:
            print("You do not purchase any items")
            return(interact('no', money, pleasure))
    elif user_answer == 8:
        pLoc = "You perused the shoe store, and prices of " + p
        print pLoc[:-2]
        if raw_input("The shoe salesman on duty asks you 'would you like something?' ")=="y" or "yes":
            mon = int(raw_input("How much do you wish to spend? "), base=10)
            if price_list.index(mon) < 10:
                if (money-mon)>0:
                    money = money - mon
                    pleasure = price_list.pop(price_list.index(mon))/2
                    Need.pop(street_index)
                    return(interact('yes', money, pleasure))
                else:
                    print("Sorry, but you ran out of money while shopping on Avenue J. Make some more before returning.")
                    return(interact('no', money, pleasure))
        else:
            print("You do not purchase any items")
            return(interact('no', money, pleasure))
    elif user_answer == 9:
        pLoc = "You entered the massage parlor, and see a price list of massages for " + p
        print pLoc[:-2]
        if raw_input("The massage lady ask you 'massage?' ")=="y" or "yes":
            mon = int(raw_input("How much do you wish to spend? "), base=10)
            if price_list.index(mon) < 10:
                if (money-mon)>0:
                    money = money - mon
                    pleasure = price_list.pop(price_list.index(mon))/2
                    Need.pop(street_index)
                    return(interact('yes', money, pleasure))
                else:
                    print("Sorry, but you ran out of money while shopping on Avenue J. Make some more before returning.")
                    return(interact('no', money, pleasure))
        else:
            print("You do not purchase any items")
            return(interact('no', money, pleasure))

#if the user decides to argue with people on the street
def discuss(user_input, user_answer, current_street):
    if len(Need) == 1:
        Need.pop()
        print("There was some person on the street that was holding a pro-Benjamin Netanyahu sign. You proceeded to walk up to him and call him a lunatic. You stood back and reflected on your success.")
\$\endgroup\$
  • 1
    \$\begingroup\$ Providing us the travel method would allow better reviews as it makes the code testable. \$\endgroup\$ – Caridorc Sep 10 '15 at 22:18
5
\$\begingroup\$

Input sanitizing and validation

As it stands, whenever you try to get input from the user, and check it against and if statement, it looks something like this:

user_input = raw_input( ... )

if user_input == ...:
    ...

This is a really bad way to get user input. Not only are you not sanitizing input, or lowering it, but you're also not doing error handling when you deal with integer input.

In order to properly "sanitize" input, I'd recommend that you use the following techniques:

  • Strip any leading and trailing whitespace. For example:

        blah foo bar blah   
    ^^^^                 ^^^
    
  • Remove unnecessary, non alphanumeric characters. For example:

    @$!$blah% foo^& bar-- bl*ah
    ^^^^    ^    ^^    ^^  ^
    
  • Convert all the characters in user input to lowercase characters.

In the case of integer input, you want to setup a try-except block, that will check to make sure that the user enters only valid integers. Here's what that might look like:

try:
    user_input_int = int(raw_input( ... ))
    ...
except ValueError:
    print "Invalid input!"
    ...

Dictionary lookups

Rather than chaining a bunch of if-elif statements, like this:

if blah == 1:
    ...

elif blah == 2:
    ...

...

You can use a dictionary to create a lookup table for user input. For example:

possible_inputs = {
    "input1": some_function,
    ...
}

Then, to check user input, all you have to do is something simple like this:

user_input = raw_input( ... )
if user_input in possible_inputs:
    possible_inputs[user_input]()
else:
    print "Invalid input!"
    ...

Do note, you will still want to validate, and sanitize your input with this method.


Style

Python has on official style guide, and you're violating many of these guidelines. According to this online checker, you have about 50 violations. Since there are too many issues to list here, here's a small list of some of the more important violations.

  • Variable names should be in snake_case, and constant variables should be in UPPER_SNAKE_CASE.
  • Function names should also be in snake_case.
  • Classes should be in PascalCase.
  • You should have spaces between binary, mathematical, comparison, and assignment operators. This adds additional clarity.
  • There should be two blank lines between top-level code block, functions, and classes.
  • Comments above function declarations should be converted into docstrings.
  • Wildcard imports, like from blah import *, should be avoided.
  • Commented lines of code, like these ones here:

    # Streets, Need, Locations, money, pleasure, Time, check, street_index, current_street
    #   print("User Input = " + user_input)
    #    print("Numeric Value of User Input = " + str(user_answer))
    #   print("Number of streets = " + str(len(Streets)))
    #   print("Current Street = " + str(current_street))
    

    Are a bit of a code smell. I'd highly recommend that you remove them, as it makes your code more readable, and easier to understand.

I'd highly recommend that you read PEP8, Python's official style guide.

\$\endgroup\$
2
\$\begingroup\$

You can simplify:

def get_help(user_input, current_street, street_index, Locations, Need):
    word = ""
    if user_input == "look around":
        word = "You looked around and saw a " + Locations[street_index] + "."
    elif user_input == "look":
        word = "You looked around and saw a " + Locations[street_index] + "."
    elif user_input == "help":
        word = "You asked for help and a passerby was kind enough to show you the " + Locations[street_index] + " nearby. He cautioned you to avoid political discussions as they often end in communal relationships."
    elif user_input == "get help":
        word = "You asked for help and a passerby was kind enough to show you the " + Locations[street_index] + " nearby. He cautioned you to avoid political discussions as they often end in communal relationships."
    elif user_input == "jump":
        word = "You went from degree to degree with a side topping of kangaroo boxing."         

    return word

word = "" is not needed and can be removed.

if conditions can be merged with in:

def get_help(user_input, current_street, street_index, Locations, Need):
    if user_input in ("look", "look around"):
        return "You looked around and saw a " + Locations[street_index] + "."
    elif user_input in ("help", "get help"):
        return  "You asked for help and a passerby was kind enough to show you the " + Locations[street_index] + " nearby. He cautioned you to avoid political discussions as they often end in communal relationships."
    elif user_input == "jump":
        return "You went from degree to degree with a side topping of kangaroo boxing."         

    return ""
\$\endgroup\$
  • 1
    \$\begingroup\$ Also, you could do even better, replacing the if-elif chain with a single dictionary lookup followed by a .format invocation on the resulting string to substitute Locations[street_index] in where needed. \$\endgroup\$ – user14393 Sep 11 '15 at 7:21
0
\$\begingroup\$

A much better data structure would be to have a list contain all those lists as dictionaries:

streets = [{"name": "east 13th", "location": "pizza store", "need": "food"},
           {"name": "east 14th", "location": "flower shop", "need": "impress girlfriend"},
           ...
          ]

Then you can have current street constantly be set to an index of that list, and from that you can access all the values together. Whenever you have values related to each other, it's a good idea to actually store them together and not just in equivalent index points.

Instead of popping off elements now, you could set "need" to None and use that as your check, as it wont change the position of the list or affect any other data.

However I'd recommend against that as you can then no longer access that string to perhaps be able to tell the player what needs have been met. Instead I'd add a boolean to each dictionary from the above list, something like "completed": True.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.