Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 ... 568 569 [570] 571 572 ... 796

Author Topic: if self.isCoder(): post() #Programming Thread  (Read 902615 times)

EnigmaticHat

  • Bay Watcher
  • I vibrate, I die, I vibrate again
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8535 on: December 01, 2015, 08:50:16 am »

The best variable for fractions is integers.  Store it the way a computer understands, display to the user the a humans understand :P

5/10 = .5?  Ty 500 / 10 = 50.  Display as .5, or 1/2, or however you want really.

Unless its something humans were never meant to read, like coordinates in a 3D graphics engine.
Logged
"T-take this non-euclidean geometry, h-humanity-baka. I m-made it, but not because I l-li-l-like you or anything! I just felt s-sorry for you, b-baka."
You misspelled seance.  Are possessing Draignean?  Are you actually a ghost in the shell? You have to tell us if you are, that's the rule

i2amroy

  • Bay Watcher
  • Cats, ruling the world one dwarf at a time
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8536 on: December 01, 2015, 12:35:06 pm »

Today I learned something about division in C#.
Code: [Select]
int aNumber = 30;
double result;

result = aNumber / 100;       //This returns 0, which is wrong.
result = aNumber / 100.0;     //This returns 0.3, which is correct.
Apparently, if you divide by an integer, you get an integer.
If you divide by a real number, you get a real number.
Actually, that's the correct result it should produce, come to think of it. C is modular and tries to produce consistent code for the same input.

"aNumber/100" is integer-integer division. This statement will always produce an int/int opcode.

the "=" operator is just a binary operator that takes the output from the RHS and tries to store it in the LHS, it will implicitly cast things if needed/possible, but it only does that on the entire result for the RHS, not any component parts thereof.

So, here, producing consistent code for the same input trumps trying to second-guess where the programmer made a mistake and arbitrarily cast variables by itself based on non-local code. Such automatically mutating code behaviour might be helpful sometimes to avoid manual casts, but many other times, producing basically arbitrary code for the same input would be sure to produce untrackable bugs. So the compiler goes for consistency of individual operations.
This right here. If we read that line out as several steps for the computer to do it would be:
1) Do aNumber/100
2) aNumber/100 is int/int, so floor the result to make it fit into an int
3) we need to store that int into a double, so cast it to double and store

If you want to think about it in terms of order of operations, you could say that the "=" operator (and any associated casting) has the lowest priority, meaning that everything on the right hand side is going to be completely evaluated as if it didn't exist, and only then will it all be cast and stored in the appropriate variable.
Logged
Quote from: PTTG
It would be brutally difficult and probably won't work. In other words, it's absolutely dwarven!
Cataclysm: Dark Days Ahead - A fun zombie survival rougelike that I'm dev-ing for.

breadman

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8537 on: December 01, 2015, 04:04:28 pm »

Python 3 switched from int/int returning int to returning a float, even when the answer is a whole number.  I'm thinking it didn't go far enough, particularly given that it now switches dynamically between int and long, with the latter having an essentially infinite range.

In a dynamically typed language, division should return a rational number, as should constants with decimal points.  Floating-point should only come into play for irrational numbers, such as e, π, square roots, trigonometric functions, non-integer exponentiation, or the like.  Granted, the programmer should be able to cast to a floating-point type for performance reasons, but correctness should be the default.
Logged
Quote from: Kevin Wayne, in r.g.r.n
Is a "diety" the being pictured by one of those extremely skinny aboriginal statues?

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8538 on: December 01, 2015, 05:39:29 pm »

...what's 0.1+0.1 in not-float? you saying fixed point or?

Orange Wizard

  • Bay Watcher
  • mou ii yo
    • View Profile
    • S M U G
Re: if self.isCoder(): post() #Programming Thread
« Reply #8539 on: December 01, 2015, 06:06:48 pm »

There is no fixed-point in Python, it's either int or float. 0.1 + 0.1 is either 0 or 0.2.
Logged
Please don't shitpost, it lowers the quality of discourse
Hard science is like a sword, and soft science is like fear. You can use both to equally powerful results, but even if your opponent disbelieve your stabs, they will still die.

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8540 on: December 01, 2015, 06:30:42 pm »

And 0.1+0.2 is 0.30000000000000004, as is natural and right.

At least, it is in Python 3.

Shadowlord

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8541 on: December 01, 2015, 06:35:42 pm »

That's why you never compare floating point numbers with ==  :P
Logged
<Dakkan> There are human laws, and then there are laws of physics. I don't bike in the city because of the second.
Dwarf Fortress Map Archive

Bauglir

  • Bay Watcher
  • Let us make Good
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8542 on: December 01, 2015, 06:51:03 pm »

That's why you never compare floating point numbers with ==  :P
use is instead

what could go wrong >________________>
Logged
In the days when Sussman was a novice, Minsky once came to him as he sat hacking at the PDP-6.
“What are you doing?”, asked Minsky. “I am training a randomly wired neural net to play Tic-Tac-Toe” Sussman replied. “Why is the net wired randomly?”, asked Minsky. “I do not want it to have any preconceptions of how to play”, Sussman said.
Minsky then shut his eyes. “Why do you close your eyes?”, Sussman asked his teacher.
“So that the room will be empty.”
At that moment, Sussman was enlightened.

Bumber

  • Bay Watcher
  • REMOVE KOBOLD
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8543 on: December 02, 2015, 01:01:11 am »

Python 3 switched from int/int returning int to returning a float, even when the answer is a whole number.  I'm thinking it didn't go far enough, particularly given that it now switches dynamically between int and long, with the latter having an essentially infinite range.

In a dynamically typed language, division should return a rational number, as should constants with decimal points.  Floating-point should only come into play for irrational numbers, such as e, π, square roots, trigonometric functions, non-integer exponentiation, or the like.  Granted, the programmer should be able to cast to a floating-point type for performance reasons, but correctness should be the default.
I think you need to use int//int for integer division. They separated integer and floating point division into two distinct operators.
Logged
Reading his name would trigger it. Thinking of him would trigger it. No other circumstances would trigger it- it was strictly related to the concept of Bill Clinton entering the conscious mind.

THE xTROLL FUR SOCKx RUSE WAS A........... DISTACTION        the carp HAVE the wagon

A wizard has turned you into a wagon. This was inevitable (Y/y)?

Orange Wizard

  • Bay Watcher
  • mou ii yo
    • View Profile
    • S M U G
Re: if self.isCoder(): post() #Programming Thread
« Reply #8544 on: December 02, 2015, 01:07:47 am »

That's why you never compare floating point numbers with ==  :P
use is instead

what could go wrong >________________>
Code: (Python 3) [Select]
>>> 5 == 5
True
>>> 5 is 5
True
>>> float (5) is 5
False
>>> float (5) == 5
True
So, yes. is actually is useful, somehow.

...

I think you need to use int//int for integer division. They separated integer and floating point division into two distinct operators.
The // operator works with floats too, but returns a float. It always returns a rounded number, though.

Really, the only time the distinction between int and float matters in Python is when you can just chuck an int() function in there (which truncates any decimals anyway).
« Last Edit: December 02, 2015, 01:12:27 am by Orange Wizard »
Logged
Please don't shitpost, it lowers the quality of discourse
Hard science is like a sword, and soft science is like fear. You can use both to equally powerful results, but even if your opponent disbelieve your stabs, they will still die.

Mesa

  • Bay Watcher
  • Call me River.
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8545 on: December 02, 2015, 05:33:31 am »

While y'all are still on the subject of Python, could someone take a look at this thing?

I'm kinda sick today so I decided to be at least somewhat productive and whip up some sort of random name generator, however because I'm still a newbie I've run into a small (well, literally making it impossible to work) problem with it and I can't exactly tell how to get around it.

(The way the names are chosen would probably be seeded in whatever actual project I'd end up using this in, and it would not be printed to the console either but you get the idea.)

Code: (Python 3) [Select]
import random

"""Random post-apocalyptic name generator
Generates a random name out of concatenated strings pulled from thematic pools and returns it as a string
nameTypeId corresponds to what theme of the name is supposed to be:
        0 - desert
        1 - jungle
        2 - tundra/iceland/glacier
        3 - city
        4 - spaceship
        5 - hell
"""
def generateName(nameTypeId): 
        # pulls the appropriate name pool viat the getNamePool fuction as a list and stores them in the namePool dict
        # name1 and name2 are randomly chosen from the frontPart and backPart lists and concatenaded to create the desired name
        # sort of doesn't work though :s 
        if nameTypeId not in range(0,6):
                return print("Yo, this ain't gonna work. bud.")
        namePool = {"frontPart": getNamePool,"backPart": getNamePool}
        nameFront = namePool["frontPart"]("frontPart",nameTypeId)
        nameBack = namePool["backPart"]("backPart",nameTypeId)
        name1 = random.choice(nameFront)
        name2 = random.choice(nameBack)
        return name1+" "+name2

def getNamePool(part,nameTypeId):
        names = [
        ["Rock","Sand","Dust","Rocky","Sandy","Dusty","Flat","Dry","Storm","Cracked","Stone","Oasis","Sun","Skull","Drought","Red","Brown","Yellow","Orange","Hazel","Rolling"],
        ["Lands","Land","Valley","Plain","Plains","Rocks","Peaks","Pit","Canyon","Straits","Stones"],
        ["Toxic","Vine","Acid","Dark","Black","Sher","Muta","Savage","Wild","Great","Rotten","Green"],
        ["Jungle","Woods","Valley","Wood","Log","Trees","Bushes","Bush","Safari"],
        ["Cold","Frozen","Frost","Cool","White","Ice","Snow","Blizzard","Hail","Cryo","Blue","Chill","Freeze","Winter","Aurora"],
        ["Borealis","Wastes","Plains","Glacier","Wall"],
        ["Break","Kalash","Dead","Remington","Crushed","Steel","Iron","Fallen","Killer","Ruined","Nuke","Gray","Sky","Scrap","Bolt","Nut","Gun","New","Red","Blue","Grey","White","Black","Orange"],
        ["Town","City","York","Angeles","Peaks","Burg","Fort","Huts","Towers","Yard","Valley","Marino","Maria","Meltdown"],
        ["Red","Blue","Purple","Star","Great","Colossal","Space","Fallen","Green","Astral","Phantom","Mother"],
        ["Conqueror","Explorer","Empress","Odyssey","Scout","Comet","Storm","Hammer","Sword","Axe","Sun","Queen","Princess","Priestess","Mother"],
        ["Hot","Boiling","Scorched","Damned","Burned","Burning","Hell's","Melting","Molten","Lava","Magma","Sulfur","Fire","Brimstone","Abaddon","Soul","Devil","Devil's","Demon","Cursed"],
        ["Pit","Hole","Caves","Rocks","Mountain","Graves","Hive","Tunnels","Circle","Terror","Tremor","Quake","Dimension","Land"]
        ]
                #Desert names
        if part == "frontPart"  and nameTypeId == 0:
                return names[0]
        elif nameTypeId == "backPart" and nameTypeId == 0:
                return names[1]
        #Jungle names
        elif part == "frontPart"  and nameTypeId == 1:
                return names[2]
        elif part == "backPart" and nameTypeId == 1:
                return names[3]
        #Tundra names
        elif part == "frontPart"  and nameTypeId == 2:
                return names[4]
        elif part == "backPart" and nameTypeId == 2:
                return names[5]
        #City names
        elif part == "frontPart"  and nameTypeId == 3:
                return names[6]
        elif part == "backPart" and nameTypeId == 3:
                return names[7]
        #Spaceship names
        elif part == "frontPart"  and nameTypeId == 4:
                return names[8]
        elif part == "backPart" and nameTypeId == 4:
                return names[9]
        #Hell names
        elif part == "frontPart"  and nameTypeId == 5:
                return names[10]
        elif part == "backPart" and nameTypeId == 5:
                return names[11]

#Testing if the function works properly
print(generateName(7))
print(generateName(0))
print(generateName(1))
print(generateName(2))
print(generateName(3))
print(generateName(4))
print(generateName(5))

I thikn the problem is related to these lines here, at least if the call traceback is anything to go by.
Code: [Select]
        namePool = {"frontPart": getNamePool,"backPart": getNamePool}
        nameFront = namePool["frontPart"]("frontPart",nameTypeId)
        nameBack = namePool["backPart"]("backPart",nameTypeId)
        name1 = random.choice(nameFront)
        name2 = random.choice(nameBack)
        return name1+" "+name2

Code: [Select]
Traceback (most recent call last):
  File "nameGen.py", line 74, in <module>
    print(generateName(0))
  File "nameGen.py", line 23, in generateName
    name2 = random.choice(nameBack)
  File "/usr/lib/python3.4/random.py", line 253, in choice
    i = self._randbelow(len(seq))
TypeError: object of type 'NoneType' has no len()

I'm not exactly sure how combining functions as dictionary values and lists within lists works, as you can probably tell. :S
I kinda feel that the getNamePool function doesn't return the list properly since the random.choice() function is the root of the problem, so I'm not sure if I have to use a dict in place of that list with lists in it or if it's something else entirely.
I also tried using a randint instead of choice but it gave a similar kind of error.

(Plus there might be other issues for all I know but it doesn't seem to be the case).
Logged

Orange Wizard

  • Bay Watcher
  • mou ii yo
    • View Profile
    • S M U G
Re: if self.isCoder(): post() #Programming Thread
« Reply #8546 on: December 02, 2015, 06:12:02 am »

The crash you're getting is (I think) because you're calling random.choice on a dictionary.

You can call random.choice on the keys() method, which returns a list of the dictionary's keys, and use the choice as a reference.
Code: [Select]
#pick a random key
a = random.choice(dictionary.keys())

#get the value of the key
b = dictionary[a]

...

I think there are some other issues, but that's probably just because I'm half asleep and can't really figure out what your code's doing.
Honestly, I'd do things quite a bit differently. But then again I write all kinds of abominations, so YMMV.
Logged
Please don't shitpost, it lowers the quality of discourse
Hard science is like a sword, and soft science is like fear. You can use both to equally powerful results, but even if your opponent disbelieve your stabs, they will still die.

Mesa

  • Bay Watcher
  • Call me River.
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8547 on: December 02, 2015, 07:04:05 am »

Okay, after a bit of fiddling I got it to work. Had to fix some other issues and re-do the getNamePool logic, but it's working now! :>
Now I can probably expand it to include more creative names following different naming schemes (currently it's just "X Y", but I could do something like "The X of Y" or "X-Y" or "The X-Y of Z" etc.), but it's nice to have something that's actually working properly.
Logged

Bauglir

  • Bay Watcher
  • Let us make Good
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8548 on: December 02, 2015, 12:45:08 pm »

So, yes. is actually is useful, somehow.

...
the is operator checks for object identity, i'm pretty sure

in other words

Code: [Select]
>>> a = [5]
>>> b = [5]
>>> a == b
True
>>> a is b
False

i think

anyway, the joke is that the difference in operator choice has absolutely nothing to do with this particular issue, and will in fact result in even more wacky, unexpected behavior

edit: changed the example slightly, because i forgot that there's just one integer object for each integer number in Python, so if i didn't make them lists the example would've been incorrect
« Last Edit: December 02, 2015, 12:50:02 pm by Bauglir »
Logged
In the days when Sussman was a novice, Minsky once came to him as he sat hacking at the PDP-6.
“What are you doing?”, asked Minsky. “I am training a randomly wired neural net to play Tic-Tac-Toe” Sussman replied. “Why is the net wired randomly?”, asked Minsky. “I do not want it to have any preconceptions of how to play”, Sussman said.
Minsky then shut his eyes. “Why do you close your eyes?”, Sussman asked his teacher.
“So that the room will be empty.”
At that moment, Sussman was enlightened.

breadman

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #8549 on: December 02, 2015, 04:37:44 pm »

...what's 0.1+0.1 in not-float? you saying fixed point or?

As a constant, 0.1 should be translated into Rational(1, 10).  (Printed, it should be 0.1, though its repr could be 1/10.)  Two of those added together would be Rational(2, 10), which could be reduced to Rational(1, 5).


While y'all are still on the subject of Python, could someone take a look at this thing?

Code: [Select]
Traceback (most recent call last):
  File "nameGen.py", line 74, in <module>
    print(generateName(0))
  File "nameGen.py", line 23, in generateName
    name2 = random.choice(nameBack)
  File "/usr/lib/python3.4/random.py", line 253, in choice
    i = self._randbelow(len(seq))
TypeError: object of type 'NoneType' has no len()

I'm not exactly sure how combining functions as dictionary values and lists within lists works, as you can probably tell. :S
I kinda feel that the getNamePool function doesn't return the list properly since the random.choice() function is the root of the problem, so I'm not sure if I have to use a dict in place of that list with lists in it or if it's something else entirely.
I also tried using a randint instead of choice but it gave a similar kind of error.

You're right; getNamePool() doesn't return the list properly for this particular case.  Instead, it returns None (the only object of type 'NoneType'), which is the default value returned when you don't return anything else.  That's because it fails every single one of your if/elif clauses, reaching the end of the function.

Looking at your stack trace, the problem is with the nameBack generated with nameTypeId 0.  Indeed, that particular clause reads:

Code: (Python 3) [Select]
        elif nameTypeId == "backPart" and nameTypeId == 0:
                return names[1]

Spot the problem?

This code is highly unpythonic, partly because it violates the Don't Repeat Yourself principle.  That entire if block would have been better as a single statement with a computed index:

Code: (Python 3) [Select]
        return names[(nameTypeId * 2) + (part == "backPart")]

Granted, even that doesn't go far enough.  Given that you generally want both the front part and the back part, why not return them both at once?  Given that they're naturally paired, why not write them as such in the structure itself?  While we're at it, docstrings traditionally go inside the function, not outside.  Throwing in a few other simplifications:

Code: (Python 3) [Select]
import random

def generateName(nameTypeId):
    """Random post-apocalyptic name generator
    Generates a random name out of concatenated strings pulled from thematic pools and returns it as a string
    nameTypeId corresponds to what theme of the name is supposed to be:
        0 - desert
        1 - jungle
        2 - tundra/iceland/glacier
        3 - city
        4 - spaceship
        5 - hell
    """
   
    names = [
        (
            #Desert names
            ["Rock","Sand","Dust","Rocky","Sandy","Dusty","Flat","Dry","Storm","Cracked","Stone","Oasis","Sun","Skull","Drought","Red","Brown","Yellow","Orange","Hazel","Rolling"],
            ["Lands","Land","Valley","Plain","Plains","Rocks","Peaks","Pit","Canyon","Straits","Stones"],
        ),
        (
            #Jungle names
            ["Toxic","Vine","Acid","Dark","Black","Sher","Muta","Savage","Wild","Great","Rotten","Green"],
            ["Jungle","Woods","Valley","Wood","Log","Trees","Bushes","Bush","Safari"],
        ),
        (
            #Tundra names
            ["Cold","Frozen","Frost","Cool","White","Ice","Snow","Blizzard","Hail","Cryo","Blue","Chill","Freeze","Winter","Aurora"],
            ["Borealis","Wastes","Plains","Glacier","Wall"],
        ),
        (
            #City names
            ["Break","Kalash","Dead","Remington","Crushed","Steel","Iron","Fallen","Killer","Ruined","Nuke","Gray","Sky","Scrap","Bolt","Nut","Gun","New","Red","Blue","Grey","White","Black","Orange"],
            ["Town","City","York","Angeles","Peaks","Burg","Fort","Huts","Towers","Yard","Valley","Marino","Maria","Meltdown"],
        ),
        (
            #Spaceship names
            ["Red","Blue","Purple","Star","Great","Colossal","Space","Fallen","Green","Astral","Phantom","Mother"],
            ["Conqueror","Explorer","Empress","Odyssey","Scout","Comet","Storm","Hammer","Sword","Axe","Sun","Queen","Princess","Priestess","Mother"],
        ),
        (
            #Hell names
            ["Hot","Boiling","Scorched","Damned","Burned","Burning","Hell's","Melting","Molten","Lava","Magma","Sulfur","Fire","Brimstone","Abaddon","Soul","Devil","Devil's","Demon","Cursed"],
            ["Pit","Hole","Caves","Rocks","Mountain","Graves","Hive","Tunnels","Circle","Terror","Tremor","Quake","Dimension","Land"],
        ),
    ]
   
    parts = names[nameTypeId]
    return ' '.join(random.choice(name) for name in parts)

Yes, this now throws an IndexError when you try to use an improper value, but that's up to the caller to fix.  If you're willing to change the type that generateName expects, a string may be a better choice, though enum.Enum may best of all.  In either case, the names structure can easily be switched to a dict.
Logged
Quote from: Kevin Wayne, in r.g.r.n
Is a "diety" the being pictured by one of those extremely skinny aboriginal statues?
Pages: 1 ... 568 569 [570] 571 572 ... 796