Using the resource maps

Using the resource maps

Here is where ideas can be collected for the skirmish AI in development

Moderators: hoijui, Moderators

User avatar
LoidThanead
Posts: 58
Joined: 27 Feb 2008, 16:16

Using the resource maps

Post by LoidThanead »

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
slogic
AI Developer
Posts: 626
Joined: 17 Mar 2008, 19:03

Re: Using the resource maps

Post by slogic »

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.
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Re: Using the resource maps

Post by Kloot »

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.
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.)
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?
The maps are all stored in row-major order.
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.
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.
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.
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. ;)
Last edited by Kloot on 16 Mar 2009, 16:55, edited 4 times in total.
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Using the resource maps

Post by hoijui »

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
User avatar
LoidThanead
Posts: 58
Joined: 27 Feb 2008, 16:16

Re: Using the resource maps

Post by LoidThanead »

Thanks for your replies, everyone.
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. ;)
D'oh. Of course you're right. That was a really silly mistake of me. It makes much more sense now.
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.
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.)
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.
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. :)
User avatar
LoidThanead
Posts: 58
Joined: 27 Feb 2008, 16:16

Re: Using the resource maps

Post by LoidThanead »

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?
Attachments
metalmap.jpg
Contours of the metalmap of Small Divide
(40.63 KiB) Downloaded 55 times
Auswaschbar
Spring Developer
Posts: 1254
Joined: 24 Jun 2007, 08:34

Re: Using the resource maps

Post by Auswaschbar »

unsigned char, nuf said
User avatar
LoidThanead
Posts: 58
Joined: 27 Feb 2008, 16:16

Re: Using the resource maps

Post by LoidThanead »

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.
imbaczek
Posts: 3629
Joined: 22 Aug 2006, 16:19

Re: Using the resource maps

Post by imbaczek »

add 128 to the byte value, then.

BTW what do you use to make that plot?
User avatar
LoidThanead
Posts: 58
Joined: 27 Feb 2008, 16:16

Re: Using the resource maps

Post by LoidThanead »

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.
User avatar
Peet
Malcontent
Posts: 4384
Joined: 27 Feb 2006, 22:04

Re: Using the resource maps

Post by Peet »

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.
Auswaschbar
Spring Developer
Posts: 1254
Joined: 24 Jun 2007, 08:34

Re: Using the resource maps

Post by Auswaschbar »

Know shit about java, so here in C++:

Code: Select all

int realValue = oldValue;
if (realValue < 0)
    realValue += 256;
Where int needs to be big enough to store all values in [-128, 256]
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Using the resource maps

Post by hoijui »

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).
User avatar
lurker
Posts: 3842
Joined: 08 Jan 2007, 06:13

Re: Using the resource maps

Post by lurker »

Does using java corrupt people's minds when it comes to how signed numbers work? ADD 256 DONE
User avatar
Pxtl
Posts: 6112
Joined: 23 Oct 2004, 01:43

Re: Using the resource maps

Post by Pxtl »

lurker wrote:Does using java corrupt people's minds when it comes to how signed numbers work? ADD 256 DONE
Reading is fundamental. RTFT.
User avatar
lurker
Posts: 3842
Joined: 08 Jan 2007, 06:13

Re: Using the resource maps

Post by lurker »

Pxtl wrote:
lurker wrote:Does using java corrupt people's minds when it comes to how signed numbers work? ADD 256 DONE
Reading is fundamental. RTFT.
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.
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).
Auswaschbar
Spring Developer
Posts: 1254
Joined: 24 Jun 2007, 08:34

Re: Using the resource maps

Post by Auswaschbar »

@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
imbaczek
Posts: 3629
Joined: 22 Aug 2006, 16:19

Re: Using the resource maps

Post by imbaczek »

short javaIsDumb = byteValue >= 0? byteValue : byteValue+128;

adding 256 won't solve anything...
User avatar
lurker
Posts: 3842
Joined: 08 Jan 2007, 06:13

Re: Using the resource maps

Post by lurker »

imbaczek wrote:short javaIsDumb = byteValue >= 0? byteValue : byteValue+256;

adding 256 will solve anything...
FTFY

(well, it still depends on if you have to cast to short before you add to it, I have no idea)
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Using the resource maps

Post by hoijui »

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.

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 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:

Code: Select all

unsigned int (CALLING_CONV *Clb_UnitDef_getCategory)(int teamId, int unitDefId);
we would have:

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);
though, what would we do with eg this:

Code: Select all

unsigned int (CALLING_CONV *Clb_WeaponDef_getCollisionFlags)(int teamId, int weaponDefId);
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.
Post Reply

Return to “AI”