Dictionary sorting problem

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
Yc3k
Newbie
Posts: 24
Joined: Tue Feb 27, 2018 8:27 pm
Contact:

Dictionary sorting problem

#1 Post by Yc3k » Thu May 03, 2018 5:28 pm

Hi everyone.

I am currently using a dictionary as a inventory. I know there are better ways to do it, but this one is easy, it does the job and my need for inventory is simple.

So, this is the inventory:

Code: Select all

$ items_food = {"Chocolate": 3, "Juice": 0, "Chips": 2, "Soda": 2, "Coffee": 2, "HotDog": 2, "eDrink": 2, "PizzaCut": 2, "McMenu": 2}
And this is the part of the code I use to display the inventory on screen (minus the screens, alignments and everything else):

Code: Select all

for item in items_food:
	textbutton "[item]" action Jump(item +"OpenScreen")

for item in items_food:
	$ amount_food = items_food[item]
	textbutton "[amount_food]"
Now, this work like a charm with only one problem. The items are displayed at random instead in the order I've put them into the dict. If I change the amount of a certain item it shuffles all the inventory again at random.

Is there any way to sort a dictionary so the item would be displayed in an order that put into the inventory?

Like this:

1. Chocolate
2. Juice
3. Chips
...
...

Thank you all for the help. I apologize if this is already covered somewhere, but I couldn't find it.

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Dictionary sorting problem

#2 Post by kivik » Thu May 03, 2018 7:00 pm

Unfortunately dictionaries aren't sorted at all, so there's no way to bring them back in the order you added them. For this functionality you're going to need a list.

So one way you can do this is:

Code: Select all

default items_food = [["Chocolate", 3], ["Juice", 0], ["Chips", 2]]

screen inventory:
    window:
        vbox:
            for item in items_food:
                textbutton "[item[0]] x[item[1]]" action Jump(item[0]+"OpenScreen")
A better way may be to make your items and inventory objects:

Code: Select all

init python:
    class item(object):
        def __init__(self, name, qty):
            self.name = name
            self.qty = qty

    class inventory(object):
        def __init__(self, items):
            self.items = items

        def add(self, item):
            self.items.append(item)

        def get(self, name):
            return next((x for x in self.items if x.name == name), None)

default inv_food = inventory([item("Chocolate", 3), item("Juice", 0), item("Chips", 2)])

screen inventory:
    window:
        vbox:
            for item in inv_food.items:
                textbutton "[item.name] x[item.qty]" action Jump(item.name+"OpenScreen")
You can use add() to add a new item, and get() to find an item by name.

DannX
Regular
Posts: 99
Joined: Mon Mar 12, 2018 11:15 am
Contact:

Re: Dictionary sorting problem

#3 Post by DannX » Thu May 03, 2018 10:10 pm

Not to take away from kivik's suggestion of using objects, wich is what I would recommend for this case, but in Python there's also OrderedDict, a special dictionary class that can be sorted and remember indexed order, from what I remember. Can't offer an example right now but you can google it if you're interested.

Yc3k
Newbie
Posts: 24
Joined: Tue Feb 27, 2018 8:27 pm
Contact:

Re: Dictionary sorting problem

#4 Post by Yc3k » Sun May 06, 2018 5:42 pm

Thank you all for the help.

Unfortunately my Python knowledge is somewhat limited so I'll just switch to using lists.

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Dictionary sorting problem

#5 Post by kivik » Sun May 06, 2018 6:28 pm

Something like this, granted I'm still using an object to store the OrderedDict :P

Code: Select all

init python:
    from collections import OrderedDict

    class item(object):
        def __init__(self, name, qty):
            self.name = name
            self.qty = qty

    class inventory(object):
        def __init__(self):
            self.items = OrderedDict()

        def add(self, name, item):
            self.items[name] = item

        def get(self, name):
            return self.items[name]

define init_food = [("Chocolate", 3), ("Juice", 0), ("Chips", 2)]
default inv_food = inventory()

screen inventory:
    window:
        align (0.5, 0.5)
        vbox:
            align (0.5, 0.5)
            for k, item in inv_food.items.items():
                textbutton "[item.name] x[item.qty]" action Jump(item.name+"OpenScreen")

label start:
    python:
        for food in init_food:
            inv_food.add(food[0], item(food[0], food[1]))

    show screen inventory

Yc3k
Newbie
Posts: 24
Joined: Tue Feb 27, 2018 8:27 pm
Contact:

Re: Dictionary sorting problem

#6 Post by Yc3k » Sun May 06, 2018 7:12 pm

Your first solution worked like a charm, but I faced another problem. (Like I said, I suck at programming and I'm learning the curves)

When I've used the old dict I used a code to check the amount of that item in the dict and then act accordingly. Here's an example:

Code: Select all

label EatChocolate:
    if energy == 100:
        char "{i}*My energy is already at maximum.*{/i}"
        jump SomeLabel
    else:
        if items_food["Chocolate"] >= 1:
            $ energy += 10
            $ items_food["Chocolate"] -= 1
            jump SomeLabel
        else:
            ben "{i}*I don't have any more chocolate, I should buy more.*{/i}"
            jump SomeLabel
The problem is that I don't know how to test the amount of a certain item and remove from that item when using your solution.

My list will always be the same. It will never change. I just want to add or remove from it. I know it's probably a noob question but I could really use help. Dict was the perfect solution, if only I could get the OrderedDict to work. :)

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Dictionary sorting problem

#7 Post by kivik » Sun May 06, 2018 8:58 pm

Objects are basically just containers to give your structured data a home, so OrderedDict inside inventory would be how I'd approach it. The advantage with object orientation is you can add function calls to your object for when things are added - without having to write the code yourself each time.

So I'm sticking to the OrderedDict in object in my second example, I'd add this function:

Code: Select all

def consume(self, name, qty = 1):
    if name not in self.items or qty > self.items[name].qty:
        return False
    self.items[name].qty -= qty
    return True
The function checks whether you have the item and if so whether you have enough of it to consume. The qty = 1 means it defaults to consuming 1 qty, but you can set it to anything by calling inv_food.consume("Chocolate", 3) for instance. Failing to consume returns False, so you can check for it.

If you have enough, it subtracts it from the correct item, and returns True to indicate that you were successful. Then you can just call the function with a condition statement:

Code: Select all

if inv_food.consume("Chocolate"):
    $ energy += 10
else:
    "{i}*I don't have any more chocolate, I should buy more.*{/i}"
jump SomeLabel
This means in the first line, you've both checked whether you can consume AND consumed the item, and you can immediately determine what to do next.

If you're willing to learn object orientation, you can actually store the stats change property in your item class, so you won't even have to write the condition statement and simply do an if consume and throw error message if failed.

Yc3k
Newbie
Posts: 24
Joined: Tue Feb 27, 2018 8:27 pm
Contact:

Re: Dictionary sorting problem

#8 Post by Yc3k » Mon May 07, 2018 5:52 pm

Thank you so much for your elaborate explanation. I must say I'm not accustomed on using classes but I've tinkered your script a little and I think I'm getting the hang of it.

All in all, look like this will work great. Thank you again.

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Dictionary sorting problem

#9 Post by kivik » Tue May 08, 2018 5:54 am

It's hard for me to know how easy / difficult object orientations are since I've known it for years, but I generally just visualise classes / objects as containers with properties, but containers can contain containers as well. So a person can have a name, dob, favourite colour, but they can also contain a wallet, a backpack, and a sword in one hand. The wallet and backpack in turn can contain more stuff.

In reality it's more complicated, since objects actually contain pointers to other objects, so I visualise every object having a portal to a pocket dimension that contains the physical objects with tickets assigned to them - and so the object hold these tickets when they contain another object. If they need to access an object they're carrying, they just open the pocket dimension and grab that item using their ticket. Tickets can duplicated so two objects can hold the same ticket and manipulate the same object in the pocket dimension.

But ignoring pointers, it's a lot easier to manage and visualise your game items and properties by using object orientation, so it's really worth investing. You kind of already use an bit of object orientation in the form of the Characters in the game. I read in another thread that apparently the Characters aren't exactly objects, but I think as far as you need to know at this stage, they are objects.

Without objects, you'll end up with lists and lists and dictionary after dictionary of stuff, you need to remember what each of these lists and dictionaries mean, and give them names that make sense. Create some classes and quickly everything is contained. Anything to do with the player is inside the player object for instance.

Good luck with your game, and if you have any questions any time, there're plenty of help here :)

Yc3k
Newbie
Posts: 24
Joined: Tue Feb 27, 2018 8:27 pm
Contact:

Re: Dictionary sorting problem

#10 Post by Yc3k » Wed May 09, 2018 5:38 pm

This has really been insightful and I will definitely use more of my time to learn object orientation.

For now, what you've shown me with a little of my tinkering is working like a charm and it makes me really happy.

All in all, thank you for your help and thanks to the whole community here. You guys are the best!

Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot], span4ev