Using the resource maps
Moderators: hoijui, Moderators
- LoidThanead
- Posts: 58
- Joined: 27 Feb 2008, 16:16
Using the resource maps
Hi all,
Since the release of the Java AI interface I've been working to create a simple Java AI. So far, it can build units and structurs, and order some units around. It even reacts to enemy units entering radar range and tries to destroy them.
Now I'm trying to get the AI to build metal extractors. The building itself is not the problem, but finding the proper locations to build at is.
I have looked, but could not find any documentation on the subject in the wiki, nor on the forums. Below is what I (think I) know so far.
The callback has a method 'getResourceMap,' but rather than a 2D or even 3D map, all I get is is a 1D array, a list, of byte values.
My first problem is mapping the entries in the list to map coordinates. I already discovered that the resource map resolution is different from the actual map resolution. The difference is an (apparently arbitrary) factor 2.
Assuming the first entry in the list corresponds to coordinates (0, 0), the second entry corresponds to either (0, 2) or (2, 0), right? Can anyone tell me which of the two is correct?
Besides the above problem, I am also unsure what the actual values in the list represent. a byte has either value 0 or 1, so I'm guessing it means that either a resource is present or it is not.
Is there anyone that can shed some light on the subject?
I'm also looking for an algorithm that will find the most efficient locations to build the extractors. I know there is a C++ implementation available, but I work in Java. In an ideal world, the metalspot finder algorithm would also be accessible through the Java interface... but that is probably wishful thinking.
If anyone can tell me the algorithm the C++ implementation uses, I may be able to find or build it in Java, for use for any other Java AI developers.
Thanks in advance,
Loid
Since the release of the Java AI interface I've been working to create a simple Java AI. So far, it can build units and structurs, and order some units around. It even reacts to enemy units entering radar range and tries to destroy them.
Now I'm trying to get the AI to build metal extractors. The building itself is not the problem, but finding the proper locations to build at is.
I have looked, but could not find any documentation on the subject in the wiki, nor on the forums. Below is what I (think I) know so far.
The callback has a method 'getResourceMap,' but rather than a 2D or even 3D map, all I get is is a 1D array, a list, of byte values.
My first problem is mapping the entries in the list to map coordinates. I already discovered that the resource map resolution is different from the actual map resolution. The difference is an (apparently arbitrary) factor 2.
Assuming the first entry in the list corresponds to coordinates (0, 0), the second entry corresponds to either (0, 2) or (2, 0), right? Can anyone tell me which of the two is correct?
Besides the above problem, I am also unsure what the actual values in the list represent. a byte has either value 0 or 1, so I'm guessing it means that either a resource is present or it is not.
Is there anyone that can shed some light on the subject?
I'm also looking for an algorithm that will find the most efficient locations to build the extractors. I know there is a C++ implementation available, but I work in Java. In an ideal world, the metalspot finder algorithm would also be accessible through the Java interface... but that is probably wishful thinking.
If anyone can tell me the algorithm the C++ implementation uses, I may be able to find or build it in Java, for use for any other Java AI developers.
Thanks in advance,
Loid
Re: Using the resource maps
For example take a look at AI\Global\KAIK-0.13\MetalMap.cpp, method GetNearestMetalSpot().
Last edited by slogic on 16 Mar 2009, 16:34, edited 1 time in total.
Re: Using the resource maps
There is only one such "resource map" at present (the metal map), and as was already explained here, all the maps requestable through the interface are one-dimensional. (Any higher-dimensional arrays are mapped to 1D at the machine level anyway.)The callback has a method 'getResourceMap,' but rather than a 2D or even 3D map, all I get is is a 1D array, a list, of byte values.
The maps are all stored in row-major order.Assuming the first entry in the list corresponds to coordinates (0, 0), the second entry corresponds to either (0, 2) or (2, 0), right? Can anyone tell me which of the two is correct?
Correct. Another way to think about it is to take the height-map as a baseline and sample it down by a factor of two along each dimension to get the size of the metal-map, by a factor of eight to get the radar-map resolution, etc.My first problem is mapping the entries in the list to map coordinates. I already discovered that the resource map resolution is different from the actual map resolution. The difference is an (apparently arbitrary) factor 2.
A byte has 256 possible values. For the metal-map, such a value <v> means "this square produces <v> * the map's metal-scale amount of metal" if claimed by an extractor. From there you should really be able to devise your own algorithm that outputs a list of extractor positions that maximize the global income.Besides the above problem, I am also unsure what the actual values in the list represent. a byte has either value 0 or 1, so I'm guessing it means that either a resource is present or it is not.

Last edited by Kloot on 16 Mar 2009, 16:55, edited 4 times in total.
Re: Using the resource maps
i just commited a lot of docu for the AI Interface this morning.
The resource map fetch function for example, was one of the things that got documented.
so you can get a recent buildbot installer, which should then contain the new java sources including the new docu.
yeah.. about the metal spot finder..
i will try to add it to the interface
edit: when i compare the docu with what Kloot just wrote, i seem to have some factors wrong though.
could you possibly have an eye at rts/ExternalAI/SSkirmishAICallback.h please, Kloot?
search for "getHeightMap", thats where these functions start
The resource map fetch function for example, was one of the things that got documented.
so you can get a recent buildbot installer, which should then contain the new java sources including the new docu.
yeah.. about the metal spot finder..
i will try to add it to the interface
edit: when i compare the docu with what Kloot just wrote, i seem to have some factors wrong though.
could you possibly have an eye at rts/ExternalAI/SSkirmishAICallback.h please, Kloot?
search for "getHeightMap", thats where these functions start
- LoidThanead
- Posts: 58
- Joined: 27 Feb 2008, 16:16
Re: Using the resource maps
Thanks for your replies, everyone.
And sure, I could probably devise my own algorithm. However, it'd be silly to re-invent the wheel, especially since I'd screw up in the process.
I'll look at the C++ code, but I'm pretty bad at interpretting correctly what it does, since I have very little C++ experience.
Also, how they are stored at machine level really should be inconsequential to a programmer. The compiler takes care of that. My point of view is that if something is called a map, it should be a map, not a list.
(I understand there are probably reasons for making it a list, and I'm not looking to bash any of them. I'm just a big believer in ease of use.)
I'll go and download the latest installer, Hoijui. Documentation is good. :)
D'oh. Of course you're right. That was a really silly mistake of me. It makes much more sense now.A byte has 256 possible values. For the metal-map, such a value <v> means "this square produces <v> * the map's metal-scale amount of metal" if claimed by an extractor. From there you should really be able to devise your own algorithm that outputs a list of extractor positions that maximize the global income.
And sure, I could probably devise my own algorithm. However, it'd be silly to re-invent the wheel, especially since I'd screw up in the process.
I'll look at the C++ code, but I'm pretty bad at interpretting correctly what it does, since I have very little C++ experience.
I can get a map for each resource from the Java callback. Haven't looked at the other maps' contents though. They might be empty.There is only one such "resource map" at present (the metal map), and as was already explained here, all the maps requestable through the interface are one-dimensional. (Any higher-dimensional arrays are mapped to 1D at the machine level anyway.)
Also, how they are stored at machine level really should be inconsequential to a programmer. The compiler takes care of that. My point of view is that if something is called a map, it should be a map, not a list.
(I understand there are probably reasons for making it a list, and I'm not looking to bash any of them. I'm just a big believer in ease of use.)
I'll go and download the latest installer, Hoijui. Documentation is good. :)
- LoidThanead
- Posts: 58
- Joined: 27 Feb 2008, 16:16
Re: Using the resource maps
After some playing around, I now have a nice and visualized metal map on my screen. It all looks good, except... for some reason, at the center of metalspots I find extremely low values. I've attached a contour map so you can see.
If I interpret things correctly, wouldn't this mean that the centers of the metal spots would produce very low amounts of metal? Or am I getting something wrong?
If I interpret things correctly, wouldn't this mean that the centers of the metal spots would produce very low amounts of metal? Or am I getting something wrong?
- Attachments
-
- metalmap.jpg
- Contours of the metalmap of Small Divide
- (40.63 KiB) Downloaded 55 times
-
- Spring Developer
- Posts: 1254
- Joined: 24 Jun 2007, 08:34
Re: Using the resource maps
unsigned char, nuf said
- LoidThanead
- Posts: 58
- Joined: 27 Feb 2008, 16:16
Re: Using the resource maps
As far as I know, there's no such thing in Java. I'm using the Java AI interface. I guess this means there's a small bug in the conversion from the C++ unsigned char to the Java byte value? Hoijui should be able to say more about that.
Re: Using the resource maps
add 128 to the byte value, then.
BTW what do you use to make that plot?
BTW what do you use to make that plot?
- LoidThanead
- Posts: 58
- Joined: 27 Feb 2008, 16:16
Re: Using the resource maps
I tried that, but that seems to have some odd effects. The main area outside the metal spots has value 0, as it should have, so bumping it up to 128 probably isn't correct. For now, I'm just using the absolute values, which is also not the proper solution, but it works for my purposes.
I made that plot using Matlab. After saving the metalmap in a text file, I loaded it in Matlab and made a simple contour plot.
I made that plot using Matlab. After saving the metalmap in a text file, I loaded it in Matlab and made a simple contour plot.
Re: Using the resource maps
Since java only has signed bytes, the range is from -128 to 127 as opposed to 0 to 255 in an unsigned byte. You could convert to a positive int by casting and then inverting bits 0-7 and adding 1 when the input is negative if you wanted to keep the full range (and waste 23 bits per metal pixel [..mexel?])...but I suggest you just shift the input by one bit to the right. Precision will be halved but if it's for a metal spot finding algorithm that won't make much of a difference.
-
- Spring Developer
- Posts: 1254
- Joined: 24 Jun 2007, 08:34
Re: Using the resource maps
Know shit about java, so here in C++:
Where int needs to be big enough to store all values in [-128, 256]
Code: Select all
int realValue = oldValue;
if (realValue < 0)
realValue += 256;
Re: Using the resource maps
yeah.. as Java does not support signed/unsigned types, the JNA people decided to treat all unsigned types the same way as the signed ones.
i think you have to use the two complement.
http://en.wikipedia.org/wiki/Two's_complement
if you do not know it already.. it seems to be explained complex on wiki...
works like this: take the number in binary format, change 1's to 0's and vice versa, and add 1 to the resulting number (i think it works like this, and i guess that is waht would give you the real numbers).
though.. it would probably be a good idea if i try to get rid of signed types on the C interface.
would it be acceptable to return an int[] instead of unsinged char[]?
performance wise, that should not really matter, only memory wise, right?
and even there only for native AIs (as in Java, it is all int anyway).
i think you have to use the two complement.
http://en.wikipedia.org/wiki/Two's_complement
if you do not know it already.. it seems to be explained complex on wiki...
works like this: take the number in binary format, change 1's to 0's and vice versa, and add 1 to the resulting number (i think it works like this, and i guess that is waht would give you the real numbers).
though.. it would probably be a good idea if i try to get rid of signed types on the C interface.
would it be acceptable to return an int[] instead of unsinged char[]?
performance wise, that should not really matter, only memory wise, right?
and even there only for native AIs (as in Java, it is all int anyway).
Re: Using the resource maps
Does using java corrupt people's minds when it comes to how signed numbers work? ADD 256 DONE
Re: Using the resource maps
Reading is fundamental. RTFT.lurker wrote:Does using java corrupt people's minds when it comes to how signed numbers work? ADD 256 DONE
Re: Using the resource maps
What are you on about? I'm talking about the very specific problem of converting a signed number into unsigned. As aus's post has, one if, one +, THAT'S IT.Pxtl wrote:Reading is fundamental. RTFT.lurker wrote:Does using java corrupt people's minds when it comes to how signed numbers work? ADD 256 DONE
Maybe it was unclear that Peet and Hoijui are the java users in that block of posts ending in mine.
Peet wrote:and then inverting bits 0-7 and adding 1 when the input is negative
hoijui wrote:i think you have to use the two complement.
http://en.wikipedia.org/wiki/Two's_complement
if you do not know it already.. it seems to be explained complex on wiki...
works like this: take the number in binary format, change 1's to 0's and vice versa, and add 1 to the resulting number (i think it works like this, and i guess that is waht would give you the real numbers).
-
- Spring Developer
- Posts: 1254
- Joined: 24 Jun 2007, 08:34
Re: Using the resource maps
@hoijui: you need to create a vector with the double size of the metal map, and copy the corrected values each time an AI access it. I would avoid it whenever possible and only do it for AIs that really need it
Re: Using the resource maps
short javaIsDumb = byteValue >= 0? byteValue : byteValue+128;
adding 256 won't solve anything...
adding 256 won't solve anything...
Re: Using the resource maps
FTFYimbaczek wrote:short javaIsDumb = byteValue >= 0? byteValue : byteValue+256;
adding 256 will solve anything...
(well, it still depends on if you have to cast to short before you add to it, I have no idea)
Re: Using the resource maps
resource maps will be fetched once by AI per game (if they do not use a cached version anyway).
i made a list with all callback functions that contain unsinged data type. it are really few, and with the possible exception of the four map fetcher functions, i would say the memory usage difference would not have a big impact.
unsinged int for categories
unsinged char for command options
unsinged int for tags
unsinged int for checksum
unsinged int for types
unsinged int for flags
... ouh WAIT!
genious at work now...
i could add a second to each of these functions!
instead of:
we would have:
though, what would we do with eg this:
unsinged int would have to be long long i guess (JNA sais, that is always 64bit)
or.. when i look at the functions using unsinged int, they all look as if they would never need such a big range anyway.
i made a list with all callback functions that contain unsinged data type. it are really few, and with the possible exception of the four map fetcher functions, i would say the memory usage difference would not have a big impact.
Code: Select all
unsigned int (CALLING_CONV *Clb_UnitDef_getCategory)(int teamId, int unitDefId);
unsigned int (CALLING_CONV *Clb_UnitDef_getNoChaseCategory)(int teamId, int unitDefId);
unsigned int (CALLING_CONV *Clb_UnitDef_WeaponMount_getBadTargetCategory)(int teamId, int unitDefId, int weaponMountId);
unsigned int (CALLING_CONV *Clb_UnitDef_WeaponMount_getOnlyTargetCategory)(int teamId, int unitDefId, int weaponMountId);
unsigned char (CALLING_CONV *Clb_Unit_CurrentCommand_getOptions)(int teamId, int unitId, int commandId);
unsigned int (CALLING_CONV *Clb_Unit_CurrentCommand_getTag)(int teamId, int unitId, int commandId);
unsigned char (CALLING_CONV *Clb_Group_OrderPreview_getOptions)(int teamId, int groupId);
unsigned int (CALLING_CONV *Clb_Group_OrderPreview_getTag)(int teamId, int groupId);
unsigned int (CALLING_CONV *Clb_Map_getChecksum)(int teamId);
int (CALLING_CONV *Clb_Map_0ARRAY1VALS0getLosMap)(int teamId, unsigned short losValues[], int losValues_max);
int (CALLING_CONV *Clb_Map_0ARRAY1VALS0getRadarMap)(int teamId, unsigned short radarValues[], int radarValues_max);
int (CALLING_CONV *Clb_Map_0ARRAY1VALS0getJammerMap)(int teamId, unsigned short jammerValues[], int jammerValues_max);
int (CALLING_CONV *Clb_Map_0ARRAY1VALS0REF1Resource2resourceId0getResourceMap)(int teamId, int resourceId, unsigned char resources[], int resources_max);
unsigned int (CALLING_CONV *Clb_WeaponDef_getOnlyTargetCategory)(int teamId, int weaponDefId);
unsigned int (CALLING_CONV *Clb_WeaponDef_Shield_getInterceptType)(int teamId, int weaponDefId);
unsigned int (CALLING_CONV *Clb_WeaponDef_getInterceptedByShieldType)(int teamId, int weaponDefId);
unsigned int (CALLING_CONV *Clb_WeaponDef_getCollisionFlags)(int teamId, int weaponDefId);
unsinged char for command options
unsinged int for tags
unsinged int for checksum
unsinged int for types
unsinged int for flags
... ouh WAIT!
genious at work now...
i could add a second to each of these functions!
instead of:
Code: Select all
unsigned int (CALLING_CONV *Clb_UnitDef_getCategory)(int teamId, int unitDefId);
Code: Select all
unsigned char (CALLING_CONV *Clb_Unit_CurrentCommand_0UNSIGNED0getOptions)(int teamId, int unitId, int commandId);
short (CALLING_CONV *Clb_Unit_CurrentCommand_0SIGNED0getOptions)(int teamId, int unitId, int commandId);
Code: Select all
unsigned int (CALLING_CONV *Clb_WeaponDef_getCollisionFlags)(int teamId, int weaponDefId);
or.. when i look at the functions using unsinged int, they all look as if they would never need such a big range anyway.