dictionary summing

main_dic= {"slot1": [0, "item", False, 1, True, "item", 4, 0, 0],
"slot2":[0, "none", False, 0, False, "none", 0, 0, 0],
"slot3":[0, "item", False, 1, False, "item", 15, 1, 0],

Im having trouble sorting my code…Id like to get a TOTAL of the any slots wheret he fifth slot where 5 = “item”…in other words id like to come up with a variable that == 19 by adding slots in main_dic where the 5th item does not equal “none”. Im having trouble getting the syntax right. Im using

n = [slot for slot, var in logic.globalDict[“main_dict”].items() if var[5] =! own[“none”]]
and then trying to break down n

but i cant get a running total of all the [6] of each slot of n if that makes sense…i cant get the syntax right. Any help is appreciated if you understand.

the wanted variable should just be 19…by adding the sum of [6]slots that have “item” in the [5] slot within the dictionary “main_dic”…

any help is appreciated…sorry for the jumble…

sum([s[6] for s in main_dic.values() if s[5] == "item"])

sum([s[6] for s in main_dic.values() if s[5] == “item”])

Worked. 100%. Thank you Goran

The design of the data structure looks pretty chaotic. Are you sure this is what you want?

I’m sure it makes perfect sense from the inside :wink: Just gotta learn dict expressions well if you use such system. Very handy: https://docs.python.org/2/tutorial/datastructures.html#dictionaries

Might want to use named tuples for your dictionary values, as they make it easier to work out what is being used, and offer a cleaner access format.

Or more dictionaries or instances of classes to represent each type of item. This method seems a bit awkward to use at the moment.

For all of the above suggestions

Ive been told multiple times that my way of keeping dictionaries is sloppy…Although I am much thankful to goran for solving my problem I am open to suggestions about better syntax…People say my way is sloppy but I dont understand How I would clean it up without making a larger dictionary…The above with variables changes goes like this

inv_dic= {“slot1”: [0(is equipped 0 no, 1 yes), “item_name”,0(is loaded 1 yes 0 no) ,1(is stackable 1 yes 0 no)],
for EX
“slot2”:[0, “none”,0,0,]
“slot3”:[0, “item_swordex”,1,1]}

Although to an outsider my key values might seem as sloppy, I know what they mean. I dont know a way to further streamline the values outside of a 0,1 (True or not)…Theres no way to break it down further…I guess from what your saying I should have a dictionary for each slot rather than a total “inventory” dictionary…I can load my inventory, 6 character classes, stats, treasury, skills, base stats, and quest triggers from a 6KB file, although the dictionary might look like mumble to an outsider who dont know the values…I dont understand a way to make it more clean…Since the backend is clear to me…I dont understand why If its dic.key value = true is worse than breaking it down into further tuples within the dictionary itself…Am I supposed to be making dictionaries within dictionaries just so a python reader can understand?? seems like it would make it longer than me just putting a comment in that says hey
#0=1 is active, “name”, 0or1=blah, 0or1=blah…

Sorry if it sounds sassy but just trying to understand…seems like you want me to break down my dictionaries to more dictionaries just so its more legible to a programmer…

As always I am open to the advice of people who are more experienced than myself

After thinking about it its like this…right now i have a dic that goes

0 streght, 1 dexterity, 2 intellect, 3 luc…blah blah…within the dic my_stats

stats= {“mystats”: 0,0,0,0,0}

seems like you want me to have a dictionary for each stat rather than comment than what each value stands for

and sorry for the typos…my phone keeps trying to correct it

It seems like you’re pushing the dictionary’s keys and values forward one “level” each time you use it, to me.

For example, you have:



inventory = {'slot1':[0, 1, 0, 1], 'slot2':[0, 0, 0, 0], ...}


With each value in the dictionary being just a list. You’re losing the effectiveness of the dictionary in my opinion, as you’re using it essentially as a list (where each key is a string that’s essentially just a number; “slot1”, “slot2”, etc), and the values are contained in lists and aren’t labeled. A simple way to turn that around would be to do this:



inventory = [
{'equipped':False, 'name': 'Iron Sword', 'quantity':5, 'stackable':False}, # This is slot 0 (or 1, depending on how you look at it)
] # List for the inventory


In this example, your inventory is a list. Now you essentially cut out the “slot” part and just use the number rather than a string to grab the item in a numbered slot (inventory[0], for example). A dictionary inside of the list is what is contained in that inventory “slot”, and has the values necessary, properly and easily labeled for a unique item (i.e. its name, quantity, stackable status, and if it’s equipped).

Note that a down-side to this is that you could screw up a string somewhere on creation of a new slot or a new item (i.e. “equiped”:False instead of “equipped”:False), and you’re pushing the creation of the item away from the item itself. So, I might go with a class-based system, since all of these things are properties of an item:



class Item():

    def __init__():

        self.stackable = True  # Most items are stackable
        self.name = "An Item"
        self.quest_item = False  # Most items aren't quest items
        self.description = "No description for this item exists."

class IronSword(Item):

    def __init__():
    
        super().__init__()  # Iron Swords inherit from the base Item class and have their properties
        self.name = "Iron Sword"
        self.description = "The mighty common rusted iron sword."
        self.stackable = False  # Iron swords are now not stackable

inventory = []

inventory.append(IronSword())


This is an approach in which you’re defining essentially item types, and not individual items, and then adding an instance of that item to your inventory. It’s pretty simple to sort your inventory with this, too, by whatever instance you’re sure all items have (since they’re all instances of classes that, at the very least, inherit from the base “Item” class). This way, you’re sure nothing you do will crash or break the game, since the default values exist.

You could also go with other methods to define items over entire classes, like calling item and passing certain variables, or reading an external file with just certain, specified properties that get loaded in over a base Item instance.

actually thats a very clear explanation and I appreciate your response…

the reason i use slot…If I can try to explain…Is because…the Whole dictionary is loaded into globaldict from a file…i will have a tile named “slot1” with the corresponding values…and load fron a dictionary(dataFile) if my mouse is over Slot1(then load Globaldict[“slot1”]…If you will look at the first video in my tag…I load everything from file…I may have a slot(tile,object) named slot1…and it basically tells the blend to load everything fron the data with slot1:yada,yada…slot1 is just used as a pointer…I mean…If youll look…the blend has to know from somewhere where to look…so if mouseover[tile]slot1 then that equals all the stuff for dictionary[inventory][slot1]…to me…its the only way i can relate what im doing on screen…to be a duplicate of the dictionary file…(im trying to do away with more reading whats in blends and on screen …and letting the blend be a representation of the data file)…what I have done in the past has worked…but as saving key.values. onto a blender object and reading those throughout…I can now load only things from the data file and have the blend represent those without properties…and it loads-works just the same…with no properties on the blend object…I use mouseover only as a pointer/directer…naming my slots slot1, slot2…i can mouseover slot1, slot2, etc…== dictionary[inventory] slot1,slot2.

Sorry if thats not coming out clear…but to me its simple loading from a file using a representation…classes scare, confuse me…and I dont really see the relevance in a simple situation like this…beleive me Im all for simpler…It just dont click in my mind yet how its simpler I guess.

see I see no difference in your code tag1(representing what I have) and code 2…to me it seems the same…just diffferent(like you just put equiped first)(hard to explain)but I could do that…

My jest is:
I dont understand the need of making a class “IronSword”…when its already saved in my file as a dict key “Iron sword”…and I just need to load the values…If you understand

Nah, I think I got you, man.

You could tie the tiles to your global dictionary by just giving them a property that you read (named “index”, for example). You could also grab the last characters from their name and converting it to an integer. For example, if the inventory slot’s name is “InventorySlot13”,



from bge import logic

cont = logic.getCurrentController()

obj = cont.owner

slot_number = int(obj.name[13:])  # Grab everything but the first 13 characters ("inventoryslot")


Anyway, you can use what you like since it is your code. I would recommend that you read up on classes and instances so that you at least understand and can use them if you like, though. I’m just recommending different methods to ensure you don’t end up in a situation like:



inventory = [
{"name":"Iron Sword", "equipped":False},
{"Name":"Bronze Sword", "equipt":-1},
]

… Where mis-spelling code, even simply with incorrect capitalization, will cause bugs or problems that may be hard to catch later on.

P.S. Any reason to use …'s in your posting? It kinda makes it difficult to read.

P.S. Any reason to use …'s in your posting? It kinda makes it difficult to read.

sorry…thats why I apologize so much in my post…sounds different in my head than when I type things out…My fingers move faster than my brain I think :smiley:

SolarLune showed you some ways to organize your data structure in a more readable manner (this means a reader does not need to study an awful lot of documentation to get an idea what each little component means).

I understand why you want to use this “condensed” form - because you want to store/save it in global dict.
You want it small, you want it savable - for saving.

You buy that by making other aspects of you inventory harder to use.

I suggest you use one data structure for storing/saving that fits that aspect best and another structure for other aspects. Saving does not happen that often and should not be in conflict with inventory operations. You can convert from one data structure to the other without worrying too much about processing time. Saving gets a really condensed form, while inventory operations can run on a better fitting structure. [Typically the structures are similar but not necessarily the same]

This way you can establish more readable code when performing inventory operations:


def getTheSlotContentType(slot):
   return slot.contentType # Ahh, it is the content type of a slot, forget the docs

rather than:


def getTheSlotContentType(slot):
   return slot[5] # is 5 content type? or something else? Where are the docs?

alternate way:


def getTheSlotContentType(slot):
   return slot[CONTENT_TYPE] # Ahh, it is the content type of a slot, forget  the docs

yar, it be mangling me words it does.

*My squishy thought sack

Why don’t you just make all of your slots dictionaries themselves?


inventory = {
                  "Slot1" : {"Name" : "Sword, "Equipped" : False, "Stackable" : False}
}

Inventory would still be a dictionary (which it sounds like you want) rather than a list and you can grab items by a logical sounding identifier rather than an index number.

So rather than


item_name = inventory["Slot1"][0]

you would have


item_name = inventory["Slot1"]["Name"]

Pretty much the same as what you are doing but reads better.

Classes scared me till I tried to use them. The resource that helped the most was this one:
http://introtopython.org/classes.html

The way I se your problem is that the data is non-heirachical. Things like ‘stackable’ are properties of the weapon not of he slot it’s in. This is where classes come in, but to keep things simple, I’ll use dictionaries.
What I would do is have a collection of datatypes

equipped = [None, None, None, None, None]
Inventory = {}

#And then for each weapon:
sword = {'name':'Sword', description':'A basic weapon easily found', ;stackable':False, 'modelname':'bronze_sword'}
bow = {'name .... ...

Then to assign each item, you can do things like:

inventory['sword'] = sword
equipped[0] = inventory['sword']

With other simple code you could read item properties from text files. Also I find the code fairly understandable, no idea if that’t just me because I wrote it though!

Here comes a wall.

After walking away last night and coming back today. Some of the advice make more sense(i think). And after looking I realise that I am mixing structures and the way that I do things…My problem is that my code gets heavy so I try to shorten things up. We didnt start here but we are here so here we go.

I probably should have said these things when we went here. I had a problem using “names” because when I click and move an item in my inventory from my “bag” to my equipped stuff, it just sticks the tile to the cursor so I can move it, click again to equip it or put it away. I cant use names because I ran accross a situation where my monsters dropped 2 novice_swords after I killed them, I had 2 Novice_swords in my bag. So when I try to manipulate or move a sword based on the name “Novice_Sword”, if I have more than 1 novice sword in my bag, they all stick to the cursor, they all add their values, and everything happens to all of them. The only way I could fix this was to assign an ID, which is one of my variables, to each novice sword item. So one of my variables is a ID.

main_dic= {“slot1”: [0, “Novice_Sword”, False, 1, True, “item”, 4, 0, whatever_the_ID_of_the_object_is],
“slot2”: [0, “Novice_Sword”, False, 1, True, “item”, 4, 0, whatever_the_ID_of_the_object_is],
“slot3”: [0, “empty”, False, 1, True, “item”, 4, 0, 0],
“weapon_slot”: [2, “Novice_Sword”, False, 1, True, “item”, 4, 0, whatever_the_ID_of_the_object_is]}

See I do feel that I have to mix numbers and names because there is a name, and an ID. I cant manipulate Items based on names because I may have more than 1. And If I do that, It happens to all of them.

but youll notice withing my inventory dict I have slot1, slot 2, etc, but I also have slots named, weapon_slot, helmet_slot, whatever…So the way Ive been handing it, is that if an item gets dropped into a slot with “equip” in the name(or as a property of that object), the first value gets changed to a 2, So that I know its equipped. So when I figure my attack power. Ill get my base stats, and add everything from the Dictionary that has a 2 as the 1st value which, means it is equipped. But I still get lines like this:

if own[“moving_item”] !=0 and mouse_over_any.hitObject != None and “equipslot” in mouse_over_any.hitObject and logic.globalDict[“inv_dict”][mouse_over_any.hitObject[“equipslot”]][1] == “none” and mouse_over_any.hitObject[“equipslot”] == logic.globalDict[“item_description_dict”][logic.globalDict[“inv_dict”][n[0]][1]][8] and logic.globalDict[“item_description_dict”][logic.globalDict[“inv_dict”][n[0]][1]][0] == “equipment” and logic.globalDict[“player_dict”][“level”] >= logic.globalDict[“item_description_dict”][logic.globalDict[“inv_dict”][n[0]][1]][9]:

Hows that for a condition check?

The condition breaks down like this, n is looked up earlier as im moving stuff around and just compares the items visual id to the visual id that I stored and gave the item when it was loaded(I do think I can clean that up a bit)…The rest of the condition is like this:

1.Am I moving an item(I dont want it to do anything if im not moving an item. This turns to the items ID if im moving an item and the item sticks to the cursor. If I dont have this and just stick an item to the cursor when I click on it guess what happens if I click more than 1 item, Yes They all stick, they all get manipulated. So it needs to see if Im moving an Item currently…Eg. If Im already moving an Item, I cant pick up another item, If I do something with the item Im moving, do something to the dictionary representation of that item)
2. If Im over something (or I get a Nonetype error if I click in empty space)
3. If “equip_slot” is in what Im clicking(Ill change the 1st value to 2 to know its equipped else im just droppping it in another bag slot.)(And theres more to it…potions to action bar only, and dont put weapons on the action bar, dont put potions in weapon slots…it goes deep)
4. If the slot doesnt equal “None”(If something was in the slot, that items name would be here, when I take an item out we change the old slots value to “None”, so we know what the slot is empty again)
5. if the 8th value is the same(the 8th value looks into another dictionary that has each items attributes and looks into by name only. This dictionary contains what slot an item can go into as its eight entry. So I cant put a shield on my head where a helmet goes EX. Is this slot your over a helmet_slot and is what your moving a helmet)
6. Is what your are moving equipment?(checks the same above dictionary where “equipment” is the [1] value of sword, so that I cant put a potion or key in my hand or on my head because they are “key” or “potion”, not “equipment”:smiley:
7. Check your level against the items required level(Is your level greater then the required level of the item also pulled from the same dictionary, theres a whole other dictionary whats starts with “Novice sword”, its used to check attributes of itemssuch as “novice_sword” )and every item

And If all the conditions are true. Is puts the visual object there, snaps it to its slot, and copies everything in the dictionary from bag_slot[whichever] to helmet_slot, changes the first value to a 2 so I know its equipped. Adds all entries together with a 2 in front(equippeditems), and that have phys_def as its attribute(another long statement) and tell me my physical defense. Else it snaps the object back where it was and changes nothing in the dictionary.

See I have 3 or 4 dictionaries going on at one time. One for slots, one that contains an items attributes, one that contains base stats. and the value positions line up(that my way of making it easier)

My saver has been in my else…if all the conditions arent true…it doesnt move the item. But as you can see it gets deep quick.

My problem with not mixing integers and strings, Is that I cant manipulate an item on screen based on name. If I have more than 1 item with the same name they all do it. and, I cant look up an items attributes by integer, items attributes are looked up from the dictionary by name. This would require me to give each item an integer value which would make even more confusion.

I do appreciate all of the advice and like i said after coming back and looking at some of you alls suggestions, I think I can clean some stuff up and ill have it a try. But as I wrote and certain things happened (Oh my that potion went into a shield slot, Ive alrady got an item Im moving but instead of clicking the empty slot, I accidently clicked the other sword. It picks that up to). I have to check lots of certain conditions to keep bad things from happening. And when your checking to make sure(Im over something, this is an equipment slot not an empty inventory slot, im holding equipment, my levels high enough, theres not already something in that slot, that type of item goes in that type of slot)OK all good, do it and go ahead and save to the file that you just put that item in that slot, so if your game crashes, when you come back, that Item will be in that slot. The stuff becomes a mess.

I see where I can clean up a few things and make it more legible, So Ill start there…(such as referring to values by names instead of numbers). Ill see how far I can get with that. Thanks for your helps guys.

yar, it be mangling me words it does.

yes, yes it does :smiley:

Ahh, now we see there is some more planning that perhaps sho8ld be done to avoid that massive wall of conditionals.

For reference:
This only hit me earlier this year. It is very hard to do major refactoring in the middle of a project. Continue with what you have, but perhaps conside this for future projects.

The only way to get code that is clear, readable and stays that way as a project gets bigger is planning. Lot’s of planning. Not just overal game structure, but down to the actual coding, how you’ll store information, and how things will get passed around the game.

Let’s take the first half of your conditional. It deals with:
What is the mouse pointer over.

Is this something the inventory should deal with?
Probably not.

So how could we do it better? How about an input module that takes all user interaction with the computer, and turns it into game-level commands. For input, I’m a big fan of callbacks. Right at the game start, a script gets run that will run every frame. The first frame it loads up a set of bindings. Keyboard controls, mouse buttons, everything. A nice dictionary gets passed to it mapping Human->Computer (keyboard, mouse, joystick -> python function)
Example bindings are things like:

  • Mouse.bind(left_click, python_function, object_name)
  • Mouse.bind(x_movement, python_function)
  • Mouse.bind([x_movement, left_click], python_function)
  • Keyboard.bind(button_name, python_function)
    And so on
    All function take input parameters of the event that triggered them (ie click, object_name) and a value. In the case of a mouse movement, the value is the position. In the case of buttons, it’s the duration the button has been pressed for.

What does this mean? Your conditional turns into:


def click_on_bag(event, value):
    #Note that because event is a mouse_click, it has the following properties:
    #Object -> What it's clicked on
    #Button -> Which button

    global currently_holding
    global game
    If currently_holding == None or currently_holding['level'] < game['level']:
        return
    If currently_holding['type'] not in event['object']['able_to_hold']:
        #Doesn't fit, display prompt to user, ideally a function taking an error message
    else:
        if event['object']['slot'] != None:
             #Switch Object, ideally a function taking two objects as parameters, in this case event['object'] and currently_holding
        else:
             #Place Object, ideally a function taking two objects as parameters


Yup, it’s a lot longer than your one-line wonder, but, the way to do programming is ‘divide an conquer.’ At the very least, slit your conditional onto multiple lines, and create ‘definitions’ like


HELMET = 8
BREASTPLATE = 7
...
SHIELD = 3
SWORD = 2
KNIFE = 1

...

Then you can get rid of some of the cryptic numbers.

Hows that for a condition check?

It’s nightmarish and you know it.

For such inventory system use classes or at least make inventory.py or something that you can import for neat functions and abbreviations.


#name inventory.py or whatever is relevant
inv = bge.logic.globalDict["inv_dict"] #BTW don't see why there's dict if you only have one type of inv there
itemdescs = bge.logic.globalDict["item_description_dict"] #again redundant dict IMO
pointedOb = mouse_over_any.hitObject #is it item or inventory slot? if so name accordingly

#function examples
def getEquippedItemNames():
    return [s[1] for s in inv.values() if s[0] == 1]

def isEquipped(itemname):
    if itemname in getEquippedItemNames():
        return True
    else:
        return False

#how to use elsewhere
import inventory

if inventory.isEquipped("Sword of Thousand Truths"):
    print("You can pass")
else:
    print("You shall not pass")

Edit:
Also what sdfgeoff says about numbers: if you want to use lists and numbers you can write functions that do the messy work and use clear formatting. I don’t care to dwell too deep in your number jungle but if for example 3 corresponds for weapon equip slot and 5 for head equip slot in some complex array you can write a function called getWeaponSlotItem() that reads from your number jungle myList[2][0][3] or whatever and returns it and getHeadEquipSlotItem() that does the same for [2][0][5].