Floating point to integer through nested list
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.
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.
Floating point to integer through nested list
Could someone please enlighten me as to how I am suppose to convert a floating point number from a nested list back into some format I can check the value with? I've spent quite a number of hours and have tried 10+ methods of doing this, some straight from standard Python documentation but everything seems to fail for one reason or another or another.
The if statement here is failing as the new variable is still seen as a "revertable list". I can convert the variable to a string type, but trying further to convert to a float or int type always causes errors, and trying to use the eval function to see what the program thinks the variable is causes an error that seems to be thrown by the renpy engine itself. The peculiar spelling of "revertable" rather than "revertible" makes me wonder if at least a couple of the other errors for things I've been trying aren't non-Python interpreter as well. At this place in the program I can pull a second variable and do an exact check, but later on I really do need to work with this as a true number. So, how do I do this in renpy?
I am not an object-oriented programmer, much less a python programmer, and have been frustrated by never knowing for sure whether problems I'm running into are due to my lack of understanding with modern methods, are due to documentation not matching version of Python being used, or because of limitations in the RenPy engine. I've been able to eventually resolve all problems so far, but at least two of the problems I was able to find mention of in the forums as being limitations RenPy implemented because of incompatibilities with the rollback engine. Even by passing code with the $ or python prefixes, code that runs on an interactive basis doesn't always in RenPy. Is there some way of disabling the rollback engine so that I can get results back that match standard python documentation? More effectively than $ config.rollback_enabled = False ? Or are the limitations so low-level that a recompile would be necessary? In lieau of that, is there someway of passing statements to a full-fledged interpreter instead of the limited one?
I have spent the better part of my free time for a couple of months on this personal game project and would hate to port now. There are features in RenPy that I really like, despite the fact that most of the features I don't really have a use for. However, I am starting to wonder if my project isn't really suitable for RenPy due to the limitations I keep facing.
]10 Gosub 100 : REM This a a rant and can be ignored
In the 80s I could work with games similar to Star Trek that used 8x8 matrixes which each contained an 8x8 matrix on a 1 Mhz computer with 64 KBs of memory. In the 90s I could sort mailing lists by zip code containing 5000-7000 addresses on a 60 Mhz computer with 8 MB of memory. Currently, object oriented languages seem to require that I hop up and down on a rail with one foot with a finger up my nose while whistling Yankee Doodle to accomplish what I would normally consider simple, basic tasks on my 1.8 Gigaherz computer with 3GB. I suppose a Computer Science person would think I'm just an eccentric crackpot. But, honestly here, just as an example... Python makes all division operations integer by default. In order to get sane results you have to declare your variable as floating point first. Why is this really necessary? For the 1 Mhz 6502 microprocessor there were four different methods for maintaining integrity of the floating point conversions on the binary level. There were only a handful of discrepencies, most of them known and documented, and in any case, (if my memory serves correct) the discrepencies were always less than a 10th of a decimal off.
]120 Return
I will need a copy of the variable later in the game that I can increment.
$ job_agency1 = ["Agency Assistant"], [1], [5.00], [0.0], [52], [5], [2]
$ open_agency = [None]
$ open_agency.insert(1, job_agency1) ; aj2 = 1
menu:
"Agency Openings" if ((len(open_agency)>1) and aj2) or customers:
$ i = 1 ; j = 0 ; ixtemp = 0
$ j = (len(open_agency))
if (j>1):
while (i<j):
$ ixtemp = open_agency[3][:]
if (ixtemp == 0):
$ temp = str(open_agency[0][:])
$ temp1 = str(open_agency[1][:])
"%(temp)s at level %(temp1)s at %(i)s and %(j)s"
$ i += 1
$ del ixtemp
if customers:
"You have %(customers)s"
The if statement here is failing as the new variable is still seen as a "revertable list". I can convert the variable to a string type, but trying further to convert to a float or int type always causes errors, and trying to use the eval function to see what the program thinks the variable is causes an error that seems to be thrown by the renpy engine itself. The peculiar spelling of "revertable" rather than "revertible" makes me wonder if at least a couple of the other errors for things I've been trying aren't non-Python interpreter as well. At this place in the program I can pull a second variable and do an exact check, but later on I really do need to work with this as a true number. So, how do I do this in renpy?
I am not an object-oriented programmer, much less a python programmer, and have been frustrated by never knowing for sure whether problems I'm running into are due to my lack of understanding with modern methods, are due to documentation not matching version of Python being used, or because of limitations in the RenPy engine. I've been able to eventually resolve all problems so far, but at least two of the problems I was able to find mention of in the forums as being limitations RenPy implemented because of incompatibilities with the rollback engine. Even by passing code with the $ or python prefixes, code that runs on an interactive basis doesn't always in RenPy. Is there some way of disabling the rollback engine so that I can get results back that match standard python documentation? More effectively than $ config.rollback_enabled = False ? Or are the limitations so low-level that a recompile would be necessary? In lieau of that, is there someway of passing statements to a full-fledged interpreter instead of the limited one?
I have spent the better part of my free time for a couple of months on this personal game project and would hate to port now. There are features in RenPy that I really like, despite the fact that most of the features I don't really have a use for. However, I am starting to wonder if my project isn't really suitable for RenPy due to the limitations I keep facing.
]10 Gosub 100 : REM This a a rant and can be ignored
In the 80s I could work with games similar to Star Trek that used 8x8 matrixes which each contained an 8x8 matrix on a 1 Mhz computer with 64 KBs of memory. In the 90s I could sort mailing lists by zip code containing 5000-7000 addresses on a 60 Mhz computer with 8 MB of memory. Currently, object oriented languages seem to require that I hop up and down on a rail with one foot with a finger up my nose while whistling Yankee Doodle to accomplish what I would normally consider simple, basic tasks on my 1.8 Gigaherz computer with 3GB. I suppose a Computer Science person would think I'm just an eccentric crackpot. But, honestly here, just as an example... Python makes all division operations integer by default. In order to get sane results you have to declare your variable as floating point first. Why is this really necessary? For the 1 Mhz 6502 microprocessor there were four different methods for maintaining integrity of the floating point conversions on the binary level. There were only a handful of discrepencies, most of them known and documented, and in any case, (if my memory serves correct) the discrepencies were always less than a 10th of a decimal off.
]120 Return
I will need a copy of the variable later in the game that I can increment.
$ job_agency1 = ["Agency Assistant"], [1], [5.00], [0.0], [52], [5], [2]
$ open_agency = [None]
$ open_agency.insert(1, job_agency1) ; aj2 = 1
menu:
"Agency Openings" if ((len(open_agency)>1) and aj2) or customers:
$ i = 1 ; j = 0 ; ixtemp = 0
$ j = (len(open_agency))
if (j>1):
while (i<j):
$ ixtemp = open_agency[3][:]
if (ixtemp == 0):
$ temp = str(open_agency[0][:])
$ temp1 = str(open_agency[1][:])
"%(temp)s at level %(temp1)s at %(i)s and %(j)s"
$ i += 1
$ del ixtemp
if customers:
"You have %(customers)s"
Re: Floating point to integer through nested list
I finally got this to work by changing my list into a tuple before nesting. It is beyond my comprehension why it makes a difference to Python whether the data was nested as a list or a tuple when all I wanted to do was read the numerical value. I further discovered that issuing a statement such as $ a = [1], [2], [3], [4]. [5] makes the interpreter think I just issued a tuple, when in fact you can clearly see that it is formatted as a list. If one of the numbers above were to be a string, Python would see the statement correctly as a list. I don't know whether this is a bug or whether it's a Broken by Design moment, but this sort of thing seems totally irrational to me.
Re: Floating point to integer through nested list
Firstly, I'll say that I tried to read your code yesterday to see if I could answer your query (I had about five minutes spare before leaving the house) but I couldn't follow it easily 'cause all the indentation had been lost. I could just guess, I suppose, but for future reference, if you use the 'code' tags (there's a button for them at the top of the editor, between 'Quote' and 'List', if you don't want to type them out) the indentation will be preserved and reading your code will be a lot easier. Or, since Python has significant whitespace, a lot more possible. ;-)
If you want to write a list, you need to contain it in square brackets, so:
Tuples and Lists are both sequence types, which means they support some common operations. It's not hard to become confused when you start out with Python, it certainly does some things very differently to other languages for no discernible reason.
With regard to this:
Then indeed - 'myVar[3]' refers to the 4th item (sequences are zero-indexed) in the tuple, which is indeed a one-element list containing "d" ("myVar[3] == ["d"]" is True), which isn't the same as a string "d". If you wanted to structure your data like that, then to get at the value itself you'd need to do this:
- to break it down:
However, I've also used them many times myself for regular 'normal' list operations and never had any problems with them not working the same way as I'd expect a regular Python list to.
But to muddy the waters a little more, I'd have to say that Python isn't what I would call an Object-Oriented language; objects aren't really first-class language features in Python, they're something extra you can use if you want to. I don't know if there's an official term for it (which probably makes me a lousy computer scientist; my Programming Languages lecturer was on sabbatical the year I was eligible for the course, annoyingly) but I would call Python a type-oriented language. Its emphasis is not so much on objects, but on the rich types built into the language itself. Smalltalk, Java, C#... these are proper Object-Oriented languages, where it's not possible to write anything without first writing some objects/classes.
Also also:
Lastly, if you're writing a lot of Python in your Ren'Py script, then you can avoid having to put a '$' at the beginning of each line with a 'python:' block, which you can do anywhere:
Um... actually, (aside from the fact that I'm assuming the '.' after the '[4]' should have been a comma) I can clearly see that it is formatted as a tuple. What do you think you're writing? That's a tuple consisting of five elements, each of which is a single-element list containing a single integer each.WispoWill wrote:I further discovered that issuing a statement such as $ a = [1], [2], [3], [4]. [5] makes the interpreter think I just issued a tuple, when in fact you can clearly see that it is formatted as a list.
If you want to write a list, you need to contain it in square brackets, so:
Code: Select all
# The following is a tuple of five integers:
t1 = 1, 2, 3, 4, 5
# The following is a tuple of five lists, each of which contains a single integer:
t2 = [1], [2], [3], [4], [5]
# The following is a list of five integers:
l1 = [1, 2, 3, 4, 5]
# The following is a list of five lists, each containing a single integer:
l2 = [[1], [2], [3], [4], [5]]
Are you sure? What exactly do you mean, syntactically? If you put square brackets around the whole thing, Python should see it as a list... but if you replace one of the numbers with a string, I would expect both of the following to be tuples:WispoWill wrote: If one of the numbers above were to be a string, Python would see the statement correctly as a list.
Code: Select all
t1 = [1], [2], [3], "4", [5]
t2 = [1], [2], [3], ["4"], [5]
If you tried:WispoWill wrote: The if statement here is failing as the new variable is still seen as a "revertable list".
Code: Select all
myVar = ["a"], ["b"], ["c"], ["d"], ["e"]
if myVar[3] == "d":
# Do some stuff
Code: Select all
myVar = ["a"], ["b"], ["c"], ["d"], ["e"]
if myVar[3][0] == "d":
# Do some stuff
Code: Select all
x = myVar[3] # x == ["d"]
x[0] # Get the first element in the list ["d"], which is "d".
I'm pretty sure that yes, as you suspect, the 'RevertableList' type is one defined by Ren'Py to replace regular lists with a version that participates in RollBack.WispoWill wrote: The peculiar spelling of "revertable" rather than "revertible" makes me wonder if at least a couple of the other errors for things I've been trying aren't non-Python interpreter as well.
However, I've also used them many times myself for regular 'normal' list operations and never had any problems with them not working the same way as I'd expect a regular Python list to.
I believe - although I could be wrong - that if you put your code in a .py file instead of a .rpy file, then Ren'Py won't molest it. But on the other hand, it's a little trickier to use in your script, IIRC you have to give it a namespace (possibly inherited from the filename? It's been a while since I played with this notion) and import it explicitly into your Python blocks.WispoWill wrote: Even by passing code with the $ or python prefixes, code that runs on an interactive basis doesn't always in RenPy. Is there some way of disabling the rollback engine so that I can get results back that match standard python documentation?
Again I could be wrong, but I think that all Ren'Py does is munge all the Ren'Py script into Python instructions (e.g. turn a dialogue line into a renpy.say() call) and then fiddle with the Python statements and blocks to use Rollback types and then pass the whole thing off to the Python interpreter as a Python script anyway. I think the only difference you're facing, in a Python line or block, is the rollback types. Certainly I would expect a Python statement to at least be run in eval(), as plain Python code straight to the Python interpreter.WispoWill wrote: In lieau of that, is there someway of passing statements to a full-fledged interpreter instead of the limited one?
I don't think you're an eccentric crackpot, I think you're someone who's just not had Object Oriented programming properly introduced to them, and thus misses the fundamental details which would help you to understand it. (Although, that said, there are lots of people working as OO programmers who understand the syntax and the grammars but not the principles, soo...)WispoWill wrote: In the 80s I could work with games similar to Star Trek that used 8x8 matrixes which each contained an 8x8 matrix on a 1 Mhz computer with 64 KBs of memory. In the 90s I could sort mailing lists by zip code containing 5000-7000 addresses on a 60 Mhz computer with 8 MB of memory. Currently, object oriented languages seem to require that I hop up and down on a rail with one foot with a finger up my nose while whistling Yankee Doodle to accomplish what I would normally consider simple, basic tasks on my 1.8 Gigaherz computer with 3GB. I suppose a Computer Science person would think I'm just an eccentric crackpot.
But to muddy the waters a little more, I'd have to say that Python isn't what I would call an Object-Oriented language; objects aren't really first-class language features in Python, they're something extra you can use if you want to. I don't know if there's an official term for it (which probably makes me a lousy computer scientist; my Programming Languages lecturer was on sabbatical the year I was eligible for the course, annoyingly) but I would call Python a type-oriented language. Its emphasis is not so much on objects, but on the rich types built into the language itself. Smalltalk, Java, C#... these are proper Object-Oriented languages, where it's not possible to write anything without first writing some objects/classes.
This is really just a modern-script-language-feature thing, it's not anything to do with OO programming. Python tries to be convenient and if you use two integer values in a division, it presumes you want an integer result, because if you're working entirely with integers, that would be most convenient for you. If you want a float result, then convert to floats before you start (there's a handy float() method which does just that. There's also an int() that goes the other way, and a str() which... well, you'll get it.). In fact, only one operand needs to be a float to get a float result.WispoWill wrote: But, honestly here, just as an example... Python makes all division operations integer by default. In order to get sane results you have to declare your variable as floating point first. Why is this really necessary?
Also also:
Just in case you're unaware: I'm pretty sure this will give you a list with a single item in it, which is 'None'. So when you later insert a single item to the list and check the length, len will give you '2'. An empty list would have been:WispoWill wrote:Code: Select all
$ open_agency = [None]
Code: Select all
$ open_agency = []
I don't think you can break statements up with the semicolon like that in Python, but even if you can, it's worth knowing that the more-Pythony way of doing this would be:WispoWill wrote:Code: Select all
$ i = 1 ; j = 0 ; ixtemp = 0
Code: Select all
$ i, j, ixtemp = 1, 0, 0
Lastly, if you're writing a lot of Python in your Ren'Py script, then you can avoid having to put a '$' at the beginning of each line with a 'python:' block, which you can do anywhere:
Code: Select all
e "This is the middle of a regular Ren'Py script"
python:
x, y = 10, 3
f = float(x)/y
if f > 3 and f < 4:
renpy.say(e, "It works!")
Server error: user 'Jake' not found
Re: Floating point to integer through nested list
Thank you VERY much for your reply. It helped me in several ways, not the least of which was to help me see how cranky I sounded in the main message. I apologize for that.
When I first started my project I spent several days trying to figure out how to construct muti-dimension array. I started with a tuple, discovered they were immutable, then when looking into lists saw a number of complaints on how that nested lists in Python create symbiotic links to the original data. Slicing with empty assignments seemes to be the universally recommended way to force the variable to do a copy instead of link.
The developers have stated that this is Python's correct behavior. I really can't agree with this behavior, but grudgingly admit that its the developers right to do what they wish with a language. It certainly seems non-obvious to me though.
There was at least one or two other commands I could never get to work under RenPy, but don't remember off the top of my head what they were.
Since j is exclusive in the above, I don't have to be concerned with boundary errors in either direction if open_agency[0] is padded with nonfunctional data.
Thanks again for the reply. I'll be saving this page for reference for the next little while.
All Python documentation that I've seen so far have always shown tuples being defined as a = (1, 2, 3, 4, 5) . I had assumed that the parenthesis were both necessary and definitive to the tuple as a data type, just as the brackets were to list as a data type. I see from your clear examples this was a fundmental error in my thinking.What do you think you're writing? That's a tuple consisting of five elements, each of which is a single-element list containing a single integer each.
Actually, in my original code the variable was coming off of a nested link. So in the above example wouldn't I want to use the following instead?- to break it down:Code: Select all
x = myVar[3] # x == ["d"] x[0] # Get the first element in the list ["d"], which is "d".
Code: Select all
x = myVar[3][:]
The developers have stated that this is Python's correct behavior. I really can't agree with this behavior, but grudgingly admit that its the developers right to do what they wish with a language. It certainly seems non-obvious to me though.
Interesting. If that works like described it could be the answer to some ideas I've had. However, the whole project is taking a great deal longer than anticipated due to the many roadblocks I've had in learning to use Python correctly and the likelihood of my trying to actually implement those ideas continues to sink.I believe - although I could be wrong - that if you put your code in a .py file instead of a .rpy file, then Ren'Py won't molest it. But on the other hand, it's a little trickier to use in your script, IIRC you have to give it a namespace (possibly inherited from the filename? It's been a while since I played with this notion) and import it explicitly into your Python blocks.
I haven't been able to get For... Next loops to function in any meaningful way in RenPy. Another post on the forum led me to believe that this had been at least one thing that was disabled. Using the While statement works fine, but due to While not being a part of my early programming experience I habitually always use For.. Next loops.Again I could be wrong, but I think that all Ren'Py does is munge all the Ren'Py script into Python instructions (e.g. turn a dialogue line into a renpy.say() call) and then fiddle with the Python statements and blocks to use Rollback types and then pass the whole thing off to the Python interpreter as a Python script anyway. I think the only difference you're facing, in a Python line or block, is the rollback types. Certainly I would expect a Python statement to at least be run in eval(), as plain Python code straight to the Python interpreter.
There was at least one or two other commands I could never get to work under RenPy, but don't remember off the top of my head what they were.
It's a bit scary that that actually made sense. ^_^Python tries to be convenient and if you use two integer values in a division, it presumes you want an integer result, because if you're working entirely with integers, that would be most convenient for you. If you want a float result, then convert to floats before you start (there's a handy float() method which does just that. There's also an int() that goes the other way, and a str() which... well, you'll get it.). In fact, only one operand needs to be a float to get a float result.
WispoWill wrote:Code: Select all
$ open_agency = [None]
Unfortunately, empty lists kicks an "IndexError: list assignment index out of range" when trying to assign values from a variable rather than a constant. I initially started declaring the list with None so that I could use variables at will, then discovered that it is also quite useful when doing loops based on index values.jake wrote: Just in case you're unaware: I'm pretty sure this will give you a list with a single item in it, which is 'None'. So when you later insert a single item to the list and check the length, len will give you '2'. An empty list would have been:Code: Select all
$ open_agency = []
Code: Select all
i=1 ; j=len(open_agency)
while (i<j):
$ temp = open_agency[i][0]
i += 1
WispoWill wrote:Code: Select all
$ i = 1 ; j = 0 ; ixtemp = 0
Actually, I only started doing this a few days ago after seeing the 2.6.5 documentation. It works just fine. Most languages I've been exposed to use the colon for this, but the first thing I learned about Python was that it uses the colon exclusively for blocks. I'm glad to know the "more Python way" though.jake wrote: I don't think you can break statements up with the semicolon like that in Python, but even if you can, it's worth knowing that the more-Pythony way of doing this would be:Code: Select all
$ i, j, ixtemp = 1, 0, 0
Thanks again for the reply. I'll be saving this page for reference for the next little while.
Re: Floating point to integer through nested list
Yeah... I'd prefer if it was necessary, myself, it'd be neater - although I guess it's probably necessary for some other thing Python does. Quite possibly the multiple assignment, even! In case you're unaware, there's one other weird thing about tuples: an empty tuple isWispoWill wrote: All Python documentation that I've seen so far have always shown tuples being defined as a = (1, 2, 3, 4, 5) . I had assumed that the parenthesis were both necessary and definitive to the tuple as a data type, just as the brackets were to list as a data type.
Code: Select all
()
Code: Select all
(item1, item2)
Code: Select all
(item1,)
Depends how much you care about not having the same reference, but yes - as you note, the slice with no params will make a simple copy of your list. In the context of the example, of course, they'll both return the same values.WispoWill wrote: Actually, in my original code the variable was coming off of a nested link. So in the above example wouldn't I want to use the following instead?Code: Select all
x = myVar[3][:]
Oh, I have this reaction to about a third of the things I learn about Python. ;-)WispoWill wrote: It certainly seems non-obvious to me though.
I've been using for loops quite extensively inside Python blocks inside Ren'Py script, but I wouldn't be at all surprised if they were a bit funny in python statements preceeded by a dollar sign.WispoWill wrote: I haven't been able to get For... Next loops to function in any meaningful way in RenPy.
(Of course, Python doesn't have a 'next', and you specify the bounds of your for loop differently to many other languages, but still...)
I'm not sure I follow what you mean - certainly in the context of the example code you posted in your first post, shouldn't you have been able to use append quite happily on an empty list? I'm pretty sure I've done that with no problems at all...WispoWill wrote: Unfortunately, empty lists kicks an "IndexError: list assignment index out of range" when trying to assign values from a variable rather than a constant.
For this kind of thing, could you not just use:WispoWill wrote: I initially started declaring the list with None so that I could use variables at will, then discovered that it is also quite useful when doing loops based on index values.Code: Select all
i=1 ; j=len(open_agency) while (i<j): $ temp = open_agency[i][0] i += 1
Code: Select all
python:
for temp in open_agency:
# temp == each item in list 'open_agency' in turn for each loop of the for
# etc.
Unless your point was that an empty first item means you don't have to think in 0-indexed terms? It would seem to me a shame to lose out on conveniences like the one above just to avoid learning to index your lists by 0...
Out of interest, what are those languages? I don't think I remember seing anything that uses colon like that, all the ones I can think of which allow you to write more than one statement on a line use the semicolon...WispoWill wrote: Most languages I've been exposed to use the colon for this
Server error: user 'Jake' not found
Who is online
Users browsing this forum: Bing [Bot]