Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 ... 313 314 [315] 316 317 ... 796

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

dreadmullet

  • Bay Watcher
  • Inadequate Comedian
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #4710 on: July 21, 2013, 06:37:36 pm »

Code: [Select]
MyClass() = delete;
I did not know you could do this. Very cool.
Logged

Mego

  • Bay Watcher
  • [PREFSTRING:MADNESS]
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #4711 on: July 21, 2013, 07:05:06 pm »

Code: [Select]
MyClass() = delete;
I did not know you could do this. Very cool.

It's new in C++11. Constructors that would normally be automatically added (default and copy) can be explicitly deleted like so. Also, they can instead be explicitly "defaulted" by the same syntax, only with the keyword default, which makes them perform their default behavior (default constructor constructs all member fields with default values, copy constructor makes shallow copies of member fields).

EDIT: So, I discovered one problem with my above code: the overridden getdata function only works if T is void*. Otherwise it doesn't match the base class's signature. D'oh.
« Last Edit: July 21, 2013, 07:17:41 pm by Mego »
Logged

MagmaMcFry

  • Bay Watcher
  • [EXISTS]
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #4712 on: July 21, 2013, 08:23:17 pm »

Code: [Select]
MyClass() = delete;
I did not know you could do this. Very cool.

It's new in C++11. Constructors that would normally be automatically added (default and copy) can be explicitly deleted like so. Also, they can instead be explicitly "defaulted" by the same syntax, only with the keyword default, which makes them perform their default behavior (default constructor constructs all member fields with default values, copy constructor makes shallow copies of member fields).

EDIT: So, I discovered one problem with my above code: the overridden getdata function only works if T is void*. Otherwise it doesn't match the base class's signature. D'oh.
You could make the myClass<>'s getData() return &data, typecast to void*, but then you would have to manually differentiate between the data types when you do a getData call for an object in the container, and you need to find out the object's type to find out the data type, so all you would have then is a totally redundant layer over a container<void*>. Congrats, I think?

What types of data would you save in that container, and what kind of stuff would you do with the elements? Because if there are only a few types of data, you could put all the different data types in a separate container, and if there are only a few things to do with the data (e.g. convert it to a string), you could just add specific abstract methods for those situations in BaseClass (e.g. BaseClass::toString()).
Logged

MorleyDev

  • Bay Watcher
  • "It is not enough for it to just work."
    • View Profile
    • MorleyDev
Re: if self.isCoder(): post() #Programming Thread
« Reply #4713 on: July 22, 2013, 12:07:54 pm »

I'm just gonna throw out there that this is usually a bad idea in Java, nevermind C++. Bringing something down to a void* outside of very specific scenarios is just asking for some very subtle bugs and crashes.

Same with Java and Object, but Java's better exception tracing at least makes it easier to track down problem. Not to say that should let people forget prevention is the best cure :-)

Usually I find it's better to take a step back and look at why you think you need this solution. As hard as I find it to do, going back to the bigger picture for a bit is often enlightening.
« Last Edit: July 22, 2013, 12:11:39 pm by MorleyDev »
Logged

Mego

  • Bay Watcher
  • [PREFSTRING:MADNESS]
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #4714 on: July 22, 2013, 04:32:20 pm »

Different containers are not feasible, because this is for a user library that will contain many different derived classes from the one class, plus whatever the user defines. My current approach is, since there is already a table of class names derived from another abstract base class, and the function will always return a pointer to that base class, to return a pair<void*, string>, which will allow the void* to be reinterpret_cast'ed as the proper class, given in the string.

MagmaMcFry

  • Bay Watcher
  • [EXISTS]
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #4715 on: July 22, 2013, 05:05:33 pm »

Different containers are not feasible, because this is for a user library that will contain many different derived classes from the one class, plus whatever the user defines. My current approach is, since there is already a table of class names derived from another abstract base class, and the function will always return a pointer to that base class, to return a pair<void*, string>, which will allow the void* to be reinterpret_cast'ed as the proper class, given in the string.
I should probably tell you that all of the alarm bells in my head are currently twerking their collective booties off. What is the user library for? Is it just a utility to store lots of different objects in one single container? There has to be a better way!
Logged

Mego

  • Bay Watcher
  • [PREFSTRING:MADNESS]
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #4716 on: July 22, 2013, 06:01:33 pm »

Different containers are not feasible, because this is for a user library that will contain many different derived classes from the one class, plus whatever the user defines. My current approach is, since there is already a table of class names derived from another abstract base class, and the function will always return a pointer to that base class, to return a pair<void*, string>, which will allow the void* to be reinterpret_cast'ed as the proper class, given in the string.
I should probably tell you that all of the alarm bells in my head are currently twerking their collective booties off. What is the user library for? Is it just a utility to store lots of different objects in one single container? There has to be a better way!

No, it's an attempt to add reflection to C++. There, now you're discovering new alarm bells you didn't know you had.

It's a project of mine that I've been wanting to do for a while.

MorleyDev

  • Bay Watcher
  • "It is not enough for it to just work."
    • View Profile
    • MorleyDev
Re: if self.isCoder(): post() #Programming Thread
« Reply #4717 on: July 22, 2013, 06:19:05 pm »

Okay, here it's probably more just a bad idea but I have done something kinda similar to this for Entity-Component systems and for an Event Queue. It requires RTTI though (Specifically: typeid) to do it safely (ish). You can easily reuse the basic concept of how the following idea works for Entity-Component (which is kinda like what you want here, btw). So you'd have to have another class that associates your entity (base) with it's components (data members) instead of doing it directly.

So my example of how to do this is an event queue container that holds a series of event queues of individual types.

Spoiler (click to show/hide)

The trick is to map the std::typeinfo to an std::shared_ptr<void>, and hide that behind template calls so you know what to cast to when you get the data back. The point is to keep the RTTI hidden, minimising the risks. Though a type info wrapper could be better than a string, in theory. Either way, you aren't going to get an elegant solution because what you're trying to do isn't very elegant. Even reflection is always a hack (imho).

To be honest, even with this solution...it'd be safer and cleaner to use a bunch of queues for each type than one queue with many types. Or an event queue that uses this same concept, but to also hold an event callback that is called with the event (thus preserving order across types) instead of this queue.
« Last Edit: July 22, 2013, 06:34:09 pm by MorleyDev »
Logged

Skyrunner

  • Bay Watcher
  • ?!?!
    • View Profile
    • Portfolio
Re: if self.isCoder(): post() #Programming Thread
« Reply #4718 on: July 23, 2013, 09:27:42 am »

For my game, an A-star algorithm is used to find paths. It's a tad slow, though, and through profiling I find that the method that takes the most time is, out the following pseudocode, is          current := the node in openset having the lowest f_score[] value. It takes up roughly 54% of runtime, which sounds like a serious problem. I implement it by making openset an std::map<coord, node> where node has a member 'f' that's the f-score. Finding the lowest f-score is naive, simply by running through the entire map and comparing each element, then returning the one with the lowest f-score. Is there a way to improve this somehow? I thought of making a map that had the f-score as the key, but that runs into the problem where two different tiles have the exact same f-score, meaning one of the tiles will be deleted. This can cause problems later.

Code: [Select]
function A*(start,goal)
     closedset := the empty set    // The set of nodes already evaluated.
     openset := {start}    // The set of tentative nodes to be evaluated, initially containing the start node
     came_from := the empty map    // The map of navigated nodes.
 
     g_score[start] := 0    // Cost from start along best known path.
     // Estimated total cost from start to goal through y.
     f_score[start] := g_score[start] + heuristic_cost_estimate(start, goal)
 
     while openset is not empty
         current := the node in openset having the lowest f_score[] value
         if current = goal
             return reconstruct_path(came_from, goal)
 
         remove current from openset
         add current to closedset
         for each neighbor in neighbor_nodes(current)
             tentative_g_score := g_score[current] + dist_between(current,neighbor)
             if neighbor in closedset and tentative_g_score >= g_score[neighbor]
                     continue
 
             if neighbor not in openset or tentative_g_score < g_score[neighbor]
                 came_from[neighbor] := current
                 g_score[neighbor] := tentative_g_score
                 f_score[neighbor] := g_score[neighbor] + heuristic_cost_estimate(neighbor, goal)
                 if neighbor not in openset
                     add neighbor to openset
 
     return failure
 
 function reconstruct_path(came_from, current_node)
     if current_node in came_from
         p := reconstruct_path(came_from, came_from[current_node])
         return (p + current_node)
     else
         return current_node
Logged

bay12 lower boards IRC:irc.darkmyst.org @ #bay12lb
"Oh, they never lie. They dissemble, evade, prevaricate, confoud, confuse, distract, obscure, subtly misrepresent and willfully misunderstand with what often appears to be a positively gleeful relish ... but they never lie" -- Look To Windward

MagmaMcFry

  • Bay Watcher
  • [EXISTS]
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #4719 on: July 23, 2013, 09:39:01 am »

Use a priority queue instead.

Edit: Wait, no, the C++ priority_queue doesn't support element handles and a decreaseKey() operation, which you'll need for this. You'll want a full-featured heap.

Also, you'll want to make the heap cross-referenced with your map, so you can get a handle to the heap element corresponding to a specific tile in O(1).
« Last Edit: July 23, 2013, 09:48:58 am by MagmaMcFry »
Logged

Skyrunner

  • Bay Watcher
  • ?!?!
    • View Profile
    • Portfolio
Re: if self.isCoder(): post() #Programming Thread
« Reply #4720 on: July 23, 2013, 09:44:53 am »

I dunno, it looks like priority_queue would work... What do you mean by element handles?
Logged

bay12 lower boards IRC:irc.darkmyst.org @ #bay12lb
"Oh, they never lie. They dissemble, evade, prevaricate, confoud, confuse, distract, obscure, subtly misrepresent and willfully misunderstand with what often appears to be a positively gleeful relish ... but they never lie" -- Look To Windward

Rose

  • Bay Watcher
  • Resident Elf
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #4721 on: July 23, 2013, 10:06:44 am »

How often would this map be generated?
Logged

Skyrunner

  • Bay Watcher
  • ?!?!
    • View Profile
    • Portfolio
Re: if self.isCoder(): post() #Programming Thread
« Reply #4722 on: July 23, 2013, 10:13:52 am »

It's pathfinding, not generating a map. 'S done like 5 times each step, on average, with 50 ships. Problem is long-distance pathfinding has that bottleneck. Short-distance ones are completed relatively quickly.
Logged

bay12 lower boards IRC:irc.darkmyst.org @ #bay12lb
"Oh, they never lie. They dissemble, evade, prevaricate, confoud, confuse, distract, obscure, subtly misrepresent and willfully misunderstand with what often appears to be a positively gleeful relish ... but they never lie" -- Look To Windward

MagmaMcFry

  • Bay Watcher
  • [EXISTS]
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #4723 on: July 23, 2013, 10:53:46 am »

I dunno, it looks like priority_queue would work... What do you mean by element handles?
Well, you would insert a node into the priority queue as soon as it gets an f_score, right? So what do you do when that f_score gets updated? You actually have two options: Either you implement that crosslinking option I told you about (which allows you to change an element's priority), or you just put the node into the priority queue again and throw the other instance of the node away when you pull that out. Actually, the second option should be better, since I don't think that your situation has that many f_score updates.

Edit: I just had an idea: If your ships only ever path to a relatively small set of trade ports, you wouldn't actually need lots of pathfinding at all. Instead, you could build a gradient field over the map for every single trade port on the map, so that when ships flow down a gradient field for a specific port, they always land at that port.
« Last Edit: July 23, 2013, 10:58:10 am by MagmaMcFry »
Logged

Mego

  • Bay Watcher
  • [PREFSTRING:MADNESS]
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #4724 on: July 23, 2013, 11:02:18 am »

If you want to stick with maps, you could use a std::multimap, and use the node as the key.
Pages: 1 ... 313 314 [315] 316 317 ... 796