Which is faster? Indexing a data structure or calling 3 SDK methods?

Baldyr

"Hit It"
Joined
Dec 5, 2009
Messages
5,530
Location
Sweden
I'm curious to know which setup would be faster (in theory that is - I could just time it myself, I know):

1. Use CyTeam.isAtWar(CyGlobalContext.getPlayer().getTeam()) each time a unit moves onUnitMove to check whether or not the unit's owner is at war with a specific player/team.

2. Keep track of which teams are at war with the specific player/team by keeping a Python data structure around and updating a team index with True/False values with the onChangeWar call-up from the SDK. Then index the data structure with only the player ID onUnitMove to make the check.

Which would be faster? Maintaining and indexing a data structure or making three separate method invocations? And would a dictionary or a list/tuple be faster for indexing by a integer value?
 
Not sure about the speed, but #2 is definitely much more error-prone.

My hunch says the speed difference will be negligible since in both cases there is a python code which is running, but I can't say for sure.

How many calls will happen on each unit move in the case of #1?
 
How many calls will happen on each unit move in the case of #1?
The state of war thing needs to be checked on each unitMove event. So in order to fetch all the necessary values it would probably take three calls:

CyGlobalContext.getPlayer() to get the CyPlayer instance of the unit owner
CyPlayer.getTeam () to get the team ID for the unit's owner
CyTeam.isAtWar() to check the actual diplomatic relationship

The player ID of the unit owner needs to be fetched anyway and the CyTeam instance for the isAtWar() method is a constant.

The alternative would then be:
Code:
if lAtWar[ePlayer]:
 
I think you'll need a 2-dimensional array (list of lists, actually), since you'd want to know for each team (or each player, in your code) whether it's at war with each player.

So: Either have a global list of lists, or have a list stored in the player class (is it even possible? I think you get a new instance each time you call getPlayer()).
Or maybe a dictionary of lists.
In any case, the access to these data structures will probably cost you almost the same as the calls you make here.

So I think you should stick with option #1.
 
No, all checks would be done against one single team (the constant I mentioned) so a one-dimensional array is sufficient.

This is in fact related to the General Winter Unique Power of the Russian Civilization in Rhye's and Fall of Civilization.
 
Oh, then I misunderstood it :blush:

In that case #2 might be slightly faster (again, not even sure that's true), but I'd still go with #1 for simplicity.

In #2 you need to update the list when a war starts or ends, when someone capitulates (not sure if it triggers the same events), not to mention you'll have to update it whenever you load a saved game and initialize the list correctly on start up and on map regeneration.

Not sure if I helped at all...
 
Thinking about it, it does feel wasteful to run those three checks on every unitMove event. Why not just check this once on a turn-to-turn basis (like onBeginGameTurn)?
 
Because a lot can happen in a single turn.
onBeginGameTurn is called once for all teams each turn, and this can lead to situations such as Russia declares on the Aztecs, and then the aztec unit moves into Russian borders but since onBeginGameTurn was not called yet - the flag is still off.

As I said, this is much more error prone.
And calling 3 SDK methods is not bad at all (much faster than calling 3 python methods from the SDK).
 
I agree with Asaf that #1 would be the way to go due to less potential errors. I always try to stay away from having two pieces of code doing the same thing - if they get out of sync you have errors. I'm not exactly sure how you are implementing the calls, but if I understand things properly you could also use CyUnit.getTeam() to remove one of the calls if you use example #1.
 
I'm not exactly sure how you are implementing the calls, but if I understand things properly you could also use CyUnit.getTeam() to remove one of the calls if you use example #1.
Yeah, thats about right. I don't think I've ever use CyUnit.getTeam() - but now I will. :king:
 
Rule #1 of Optimization: Premature optimization is the root of all evil.

It's generally better to write the easy solution first and optimize only once you have determined that the easy solution is too slow. If that happens, write the complicated solution and measure the difference. If the difference is significant enough to warrant the risks of the complexity, keep it.

That being said, my gut says that tracking the teams with which a single team is at war--even all team combinations--would be faster than three calls into the SDK. Are you sure it's three calls? CyUnit should have getTeam() which returns the owning team. You can pass this to the "constant" CyTeam. Note that holding on to any Cy* objects can be error-prone, but it should be safe as long as the game isn't reloaded/restarted, etc.

I also believe tracking the at-war states shouldn't be too tough given the events that are fired. I think the changeWar event is fired in all cases. Just make sure you test, test, test. :)
 
Top Bottom