I've recently been learning on how to write Python. I'm still a beginner. I've read multiple times that creating a text based adventure game in Python is a good exercise to learn the in's and out's.

I've finished the basic structure of the script. I've already run the script and so far everything is working great. I haven't implemented thought out descriptions and rooms, but I've got this down first to get the structure ready for detail.

The shop in the game works fine and I can buy/sell items. Right now all of the items are free and you don't receive anything for selling. I'm having trouble on implementing a money system.

My code is here:

North = 'north'
South = 'south'
East = 'east'
West = 'west'
DESC = 'desc'
Ground = 'ground'
GroundDesc = 'grounddesc'
ShortDesc = 'shortdesc'
LongDesc = 'longdesc'
DESCWORDS = 'descwords'
Takeable = 'takeable'
SHOP = 'shop'

SCREEN_WIDTH = 80

room_list = {
    'Prison Cell' : {
        DESC: 'You are in a prison cell. The cell door is unlocked and there is a hallway to the North.',
        North: 'Prison Hallway',
        Ground: ['Prison Sentence']},
    'Prison Hallway' : {
        DESC: 'You step out to the Prison Hallway. There is an unlocked cell to the East. A locked cell is close by to the West. Travelling North will take you to the Center of the Dungeon.',
        North: 'Dungeon Center',
        East: 'Unlocked Cell',
        West: 'Locked Cell',
        South: 'Prison Cell',
        Ground: []},
    'Unlocked Cell' : {
        DESC: 'You open the door to the unlocked cell. You do not see anyone here. The floor is littered with hay.',
        South: 'Prison Hallway',
        Ground: ['Bedroll']},
    'Locked Cell' : {
        DESC: 'The cell is locked. There is a prisoner in the cell, but you cannt tell if he is alive. Its best not to bother him.',
        South: 'Prison Hallway',
        Ground: []},
    'Dungeon Center' : {
        DESC: 'You have entered the heart of the dungeon. From this point on, there is no going back.',
        North: 'North Wing',
        East: 'East Wing',
        South: 'South Wing',
        West: 'West Wing',
        Ground: []},
    'North Wing' : {
        DESC: 'You are now in the North Wing.',
        North : '$hop',
        South: 'Dungeon Center',
        Ground: []},
    '$hop' : {
        DESC: 'The shop owner gives you a friendly wave as you enter.',
        South: 'North Wing',
        SHOP: ['LongBow', 'Iron Arrow', 'Fidget Spinner'],
        Ground: []},
    'East Wing' : {
        DESC: 'You are now in the East Wing.',
        North: 'Treasure Room',
        West: 'Dungeon Center',
        South: 'South Wing',
        Ground: []},
    'West Wing' : {
        DESC: 'You are now in the West Wing.',
        East: 'Dungeon Center',
        Ground: []},
    'South Wing' : {
        DESC: 'You are now in the South Wing.',
        North: 'Dungeon Center',
        Ground: []},
}

Dungeon_Items = {
    'Prison Sentence' : {
        GroundDesc: 'Your Prison Sentence is in your inventory.',
        ShortDesc: 'your Prison Sentence',
        LongDesc: 'You pull your Prison Sentence out of your inventory and unfold the first page. It reads: PRISONER 69, You have been locked away in this dreadful dungeon despite being innocent of any crimes. The only method of escape is death. Enjoy rotting away for no reason. --- Warden.''The first page angers you and instead of reading on, you fold the document and stow it away into back into your pocket.',
        DESCWORDS: ['Prison Sentence', 'document', 'prison sentence', 'unfold']},
    'Bedroll' : {
        GroundDesc: 'You see a bedroll in the corner of the cell. You will need to enter the cell in order to examine the bedroll further.',
        ShortDesc: 'the bedroll',
        LongDesc: 'Looks comfy.',
        Takeable: True,
        DESCWORDS: ['bedroll', 'bed']},
    'LongBow' : {
        GroundDesc: 'A LongBow lies on the ground.',
        ShortDesc: 'a LongBow',
        LongDesc: 'The LongBow is made with oak wood. Your hands run smoothly over the wood as you draw it back. Worth 25 gold.',
        DESCWORDS: ['bow', 'longbow']},
    'Iron Arrow' : {
        GroundDesc: 'An iron arrow lies on the ground.',
        ShortDesc: 'an iron arrow.',
        LongDesc: 'This iron arrow looks brand new. Nothing special, but gets the job done. Worth 1 gold.',
        DESCWORDS: ['arrow', 'iron arrow', 'iron']},
    'Fidget Spinner' : {
        GroundDesc: 'On the back of the fidget spinner, you see some strange writing. As you look closer it reads: "Cant believe you bought this PoS... -- Pete".',
        ShortDesc: 'a fidget spinner',
        LongDesc: 'Gay',
        DESCWORDS: ['fidget spinner', 'spinner']},
    'Gold' : {
        GroundDesc: 'Hey look, free money!',
        ShortDesc: 'Gold.',
        LongDesc: 'Not a fake.',
        DESC: ['gold', 'money', 'gold pieces']},

    }

location = 'Prison Cell'
inventory = ['Prison Sentence']
showFullExits = True

import cmd, textwrap

def displayLocation(loc):
    print(loc)
    print('=' * len(loc))

    print('\n'.join(textwrap.wrap(room_list[loc][DESC], SCREEN_WIDTH)))

    if len(room_list[loc][Ground]) > 0:
        print()
        for item in room_list[loc][Ground]:
            print(Dungeon_Items[item][GroundDesc])

    exits = []
    for direction in (North, South, East, West):
        if direction in room_list[loc].keys():
            exits.append(direction.title())
    print()
    if showFullExits:
        for direction in (North, South, East, West):
            if direction in room_list[location]:
                print('%s: %s' % (direction.title(), room_list [location][direction]))
    else:
        print('Exits: %s' % ' '.join(exits))

def moveDirection(direction):
    global location

    if direction in room_list[location]:
        print('You move to the %s.' % direction)
        location = room_list[location][direction]
        displayLocation(location)
    else:
        print('You cannot move in that direction')

def getAllDescWords(itemList):
    itemList = list(set(itemList))
    descWords = []
    for item in itemList:
        descWords.extend(Dungeon_Items[item][DESCWORDS])
    return list(set(descWords))

def getAllFirstDescWords(itemList):
    itemList = list(set(itemList))
    descWords = []
    for item in itemList:
        descWords.append(Dungeon_Items[item][DESCWORDS][0])
    return list(set(DescWords))

def getFirstItemMatchingDesc(desc, itemList):
    itemList = list(set(itemList))
    DescWords = []
    for item in itemList:
        if desc in Dungeon_Items[item][DESCWORDS]:
            return item
    return None

def getAllItemsMatchingDesc(desc, itemList):
    itemList = list(set(itemList))
    matchingItems = []
    for item in itemList:
        if desc in Dungeon_Items[item][DESCWORDS]:
            matchingItems.append(item)
    return matchingItems

class TextAdventureCmd(cmd.Cmd):
    prompt = '\n> '

    def default(self, arg):
        print('Invalid command. Type "help" for a list of commands.')
    def do_quit(self,arg):
        return True
    def help_combat(self):
        print('Combat is not implemented in this program.')
    def do_north(self, arg):
        moveDirection('north')
    def do_south(self, arg):
        moveDirection('south')
    def do_west(self, arg):
        moveDirection('west')
    def do_east(self, arg):
        moveDirection('east')
    def do_exits(self,arg):
        global showFullExits
        showFullExits = not showFullExits
        if showFullExits:
            print('Showing full exit descriptions.')
        else: 
            print('Showing brief exit descriptions.')

    def do_inventory(self, arg):
        if len(inventory) == 0:
            print('Inventory:\n (nothing)')
            return
        itemCount = {}
        for item in inventory:
            if item in itemCount.keys():
                itemCount[item] += 1
            else:
                itemCount[item] = 1
        print('Inventory:')
        for item in set(inventory):
            if itemCount[item] > 1:
                print(' %s (%s)' % (item, itemCount[item]))
            else:
                print(' ' + item)

    do_inv = do_inventory

    def do_take(self, arg):
        itemToTake = arg.lower()
        if itemToTake == '':
            print('Take what? type "look" the items on the ground here.')
            return
        cantTake = False

        for item in getAllItemsMatchingDesc(itemToTake, room_list[location][Ground]):
            if Dungeon_Items[item].get(Takeable, True) == False:
                cantTake= True
                continue
            print('You take %s.' % (Dungeon_Items[item][ShortDesc]))
            room_list[location][Ground].remove(item)
            inventory.append(item)
            return
        if cantTake:
            print('You cannot take "%s".' % (itemToTake))
        else:
            print('That is not on the ground.')

    def do_drop(self,arg):
        itemToDrop = arg.lower()
        invDescWords = getAllDescWords(inventory)
        if itemToDrop not in invDescWords:
            print('You do not have "%s" in your intentory' % (itemToDrop))
            return

        item = getFirstItemMatchingDesc(itemToDrop, inventory)
        if item != None:
            print('You drop %s.' % (Dungeon_Items[item][ShortDesc]))
            inventory.remove(item)
            room_list[location][Ground].append(item)

    def complete_take(self, text, line, begidx, endidx):
        possibleItems = []
        text = text.lower()

        if not text:
            return getAllFirstDescWords(room_list[location][Ground])

        for item in list(set(room_list[location][Ground])):
            for descWord in Dungeon_items[item][DESCWORDS]:
                if descWord.startswith(text) and Dungeon_Items[item].get(Takeable, True):
                    possibleItems.append(descWord)

        return list(set(possibleItems))

    def do_look(self,arg):
        lookingAt = arg.lower()
        if lookingAt == '':
            displayLocation(location)
            return
        if lookingAt == 'exits':
            for direction in (North, South, East, West):
                if direction in room_list[location]:
                    print('%s: %s' % (direction.title(), room_list[location][direction]))
            return

        if lookingAt in ('north', 'west', 'east', 'south', 'n', 'w', 'e', 's'):
            if lookingAt.startswith('n') and North in room_list[location]:
                print(room_list[location][North])
            elif lookingAt.startswith('w') and West in room_list[location]:
                print(room_list[location][West])
            elif lookingAt.startswith('e') and East in room_list[location]:
                print(room_list[location][East])
            elif lookingAt.startswith('s') and South in room_list[location]:
                print(room_list[location][South])
            else: 
                print('There is nothing in that direction.')
            return

        item = getFirstItemMatchingDesc(lookingAt, room_list[location][Ground])
        if item != None:
            print('\n'.join(textwrap.wrap(Dungeon_Items[item][LongDesc], SCREEN_WIDTH)))
            return

        item = getFirstItemMatchingDesc(lookingAt, inventory)
        if item != None:
            print('\n'.join(textwrap.wrap(Dungeon_Items[item][LongDesc], SCREEN_WIDTH)))
            return
        print('You do not see that nearby.')

    def complete_look(self, text, line, begidx, endidx):
        possibleItems = []
        lookingAt = text.lower()

        invDescWords = getAllDescWords(inventory)
        groundDescWords = getAllDescWords(room_list[location][Ground])
        shopDescWords = getAllDescWords(room_list[location].get(SHOP, []))

        for descWord in invDescWords + groundDescWords + shopDescWords + [North, South, East, West]:
            if line.startswith('look %s' % (descWord)):
                return []
        if lookingAt == '':
            possibleItems.extend(getAllFirstDescWords(room_list[location][Ground]))
            possibleItems.extend(getAllFirstDescWords(room_list[location].get(SHOP, [])))
            for direction in (North, South, East, West):
                if direction in room_list[location]:
                    possibleItems.append(direction)
            return list(set(possibleItems))

        for descWord in groundDescWords:
            if descWord.startswith(lookingAt):
                possibleItems.append(descWord)

        for direction in (North, South, East, West):
            if direction.startswith(lookingAt):
                possibleItems.append(direction)

        for descWord in invDescWords:
            if descWord.startswith(lookingAt):
                possibleItems.append(descWord)

        return list(set(possibleItems))

    def do_list(self,arg):
        if SHOP not in room_list[location]:
            print('This is not a shop.')
            return
        arg = arg.lower()

        print('For sale:')
        for item in room_list[location][SHOP]:
            print(' - %s' % (item))
            if arg == 'full':
                print('\n'.join(textwrap.wrap(Dungeon_Items[item][LongDesc], SCREEN_WIDTH)))

    def do_buy(self, arg):
        """buy <item>" - buy an item at the current location's shop."""
        if SHOP not in room_list[location]:
            print('This is not a shop.')
            return

        itemToBuy = arg.lower()

        if itemToBuy == '':
            print('Buy what? Type "list" or "list full" to see a list of items for sale.')

        item = getFirstItemMatchingDesc(itemToBuy, room_list[location][SHOP])
        if item != None:
            print('You have purchased %s' % (Dungeon_Items[item][ShortDesc]))
            inventory.append(item)
            return

        print('"%s" is not sold here. Type "list or "list full" to see a list of items for sale.' % (itemToBuy))

    def complete_buy(self, text, line, begidx, endidx):
        if SHOP not in room_list[location]:
            return []

        itemToBuy = text.lower()
        possibleItems = []

        if not itemToBuy:
            return getAllFirstDescWords(room_list[location][SHOP])

        for item in list(set(room_list[location][SHOP])):
            for DescWord in room_list[item][DESCWORDS]:
                if descWord.startswith(text):
                    possibleItems.append(descWord)

        return list(set(possibleItems))

    def do_sell(self, arg):
        if SHOP not in room_list[location]:
            print('This is not a shop.')
            return
        itemToSell = arg.lower()

        if itemToSell == '':
            print('Sell what? Type "inventory" or "inv" to see your inventory.')
            return

        for item in inventory:
            if itemToSell in Dungeon_Items[item][DESCWORDS]:
                print('You have sold %s' % (Dungeon_Items[item][ShortDesc]))
                inventory.remove(item)
                return

        print('You do not ave "%s". Type "inventory" or "inv" to see your inventory.' % (itemToSell))

    def complete_sell(self, text, line, begidx, endidx):
        if SHOP not in room_list[location]:
            return []

        itemToSell = text.lower()
        possibleItems = []

        if not itemToSell:
            return getAllFirstDescWords(inventory)

        for item in list(set(inventory)):
            for descWords in Dungeon_Items[item][DESCWORDS]:
                if descWord.startswith(text):
                    possibleItems.append(descWord)

        return list(set(possibleItems))

if __name__ == '__main__':
    print('Text Adventure Demo!')
    print('====================')
    print
    print('(Type "help" for commands.)')
    print
    displayLocation(location)
    TextAdventureCmd().cmdloop()
    print('Thanks for playing!')

I know so far that I need to insert a money function under the "def do_buy" loop. (Lines 350-365). But I just can't understand how.

Do I need to create the money variable under my Dungeon_Items dictionary? Or does this variable need to be specfic to that loop? How would I go about coding in each item's set price that will only let you buy it if you have enough money in your inventory?

I'm also assuming this can be implemented in a similar way that these TextAdventureCmd Classes.

If hints can be provided so that I can figure it out on my own, that would be best. I want to make sure I'm learning and not just copying and pasting.

It looks quite simple. You need to add an attribute to dungeon items, such as GoldValue: 25,. From the character's point of view, you can invent a new variable similar to location or inventory, such as purse = 18 which means that you have 18 gold coins. In do_buy(), you can add a test such as

if item[GoldValue] > purse:
    print("You don't have enough gold for this.")
    return
else:
    purse -= item[GoldValue]
    ...

An alternative would be to transform the inventory into a dictionary item -> quantity, for example

inventory = {'Prison Sentence': 1, 'Gold': 18}

You wouldn't need a specific variable for gold, but you would need to change the code everywhere the inventory is used.

Edit: sorry, I mistakenly marked the thread as solved :) I don't have to do this.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.