public inbox for xconq7@sourceware.org
 help / color / mirror / Atom feed
* Unstable pre-release version of enhanced ai_plan_research
@ 2004-09-08  4:09 Lincoln Peters
  2004-09-08 18:02 ` Eric McDonald
  0 siblings, 1 reply; 2+ messages in thread
From: Lincoln Peters @ 2004-09-08  4:09 UTC (permalink / raw)
  To: Xconq list

This version of ai_plan_research is woefully inadequate, but less so
than the old version.  So far, it just weights the advances by the
number of units that depend on the advance.  It still chooses advances
randomly, but it has a higher chance of picking an advance that enables
more units.  And, no, it will not completely ignore advances that don't
enable any units (since there may be benefits to such advances that it
doesn't understand).

However, since I introduced the code to my local source tree, I tried
running "advances.g" under AI control and discovered that the new code
is causing Xconq to segfault at seemingly-random times.  Strangely
enough, it never seems to crash while executing the ai_plan_research
function.  I have verified that it is somehow related to the new code,
as I reverted to the old code and got no such crashes.

My best guess is that I did something wrong with the calls to malloc()
and/or free(); most of my programming experience is in C++, not C, and
so I had to study those two functions at the last minute in order to
figure out how to create a dynamic array without the aid of the "new" or
"delete" keywords (and the documentation I was able to find is cryptic
at best).

I've included the new code at the bottom of this message.  Perhaps
someone more knowledgeable about C can figure out what's wrong with it?

---
Lincoln Peters
<sampln@sbcglobal.net>

Don't worry about avoiding temptation -- as you grow older, it starts
avoiding you.
		-- The Old Farmer's Almanac


Here's the new function:

static void
ai_plan_research(Side *side)
{
	/*  There are many things to consider when choosing an advance:
	 * 1. What new units do I gain?
	 * 2. How does it affect my existing units?
	 * 3. How long will it take to gain this advance?
	 * 4. Based on all of these merits, how important is this advance?
	 *
	 * Unfortunately, many of these issues are impossible to thouroghly
	 * handle without radically re-engineering the AI, so I'll do what I
	 * can with what we have.
	 *           -- Lincoln Peters
	 */
	
	int numAdvances = 0;	/* Number of advances that could be researched */
	int tWeight = 0;	/* Total weight (potential value) of all advances */
	int *uWeight;		/* Peceived value of available advances */
	int count1 = 0;		/* Used in any place where a counter is needed */
	int count2 = 0;		/* Likewise */
	int count3 = 0;		/* Likewise */
	int result;		/* Random number to determine advance with weighting */
	
	int n, a, i;		/* Legacy code; will be removed after debugging */
	
	/* First, get a count of the available advances. */
	
	for_all_advance_types(count1) {
		if ( side_can_research( side, count1 ) ) {
			numAdvances++;
		}
	}
	
	if ( numAdvances == 0 ) {
		/* No advances are available! */
		Dprintf( "Warning: Trying to pick an advance when no advances are available.\n" );
		net_set_side_research( side, NONATYPE );
		return;
	}
	
	/* Now try to calculate the worth of those advances. */
	
	/* Allocating memory for this array is sooooo much easier in C++! */
	Dprintf( "About to allocate the array for tracking advance worth...\n" );
	uWeight = malloc( 2 * numAdvances );
	Dprintf( "Finished allocating the advance worth array.\n" );
	
	Dprintf( "Evaluating the worth of advances...\n" );
	for_all_advance_types(count1) {
		uWeight[count1] = 0;
		if ( side_can_research( side, count1 ) ) {
			
			/* Does it enable new units? */
			for_all_unit_types(count3) {
				if ( ua_needed_to_build( count3, count1 ) ) {
					/* This unit needs this advance. */
					uWeight[count2]++;
				}
				
				/* The following block of code refers to tables
				 * that exist in the documentation, but not in
				 * the code.  It should be possible to safely
				 * un-comment it once those tables are properly
				 * implemented.
				 
				if ( ua_multiply_production( count3, count1 ) > 1 ) {
					uWeight[count2] += ua_multiply_production( count3, count1 );
				} else if ( ua_multiply_production( count3, count1 ) < 1 ) {
					uWeight[count2] -= 1.0 / ua_multiply_production( count3, count1 );
				}
				
				uWeight[count2] = uWeight[count2] + ua_add_production( count3, count1 );
				*/
			}
			
			/* Just to be safe... */
			if ( uWeight[count2] < 1 ) {
				uWeight[count2] = 1;
			}
			
			tWeight += uWeight[count2];
			count2++;
		}
		
	}
	Dprintf( "Finished determines worth of advances.\n" );
	
	/* Need to adjust worth based on time required to achieve it. */
	
	/* Finally, choose a course of action! */
	
	result = xrandom(tWeight);
	count2 = 0;
	
	Dprintf( "Selecting an advance...\n" );
	for_all_advance_types(count1) {
		if ( side_can_research( side, count1 ) ) {
			if ( result <= uWeight[count2] ) {
				/* We have a course of action! */
				Dprintf( "Selected an advance!  Cleaning up...\n" );
				free( uWeight );
				Dprintf( "Successfully deallocated the advance worth array.\n" );
				net_set_side_research(side, count2);
				Dprintf( "Advance selection complete.\n" );
				return;
			} else {
				/* Not this one.  Keep looking... */
				result -= uWeight[count2];
			}
			
			count2++;
		}
	}
	
	/* If we've gotten here without a course of action being chosed,
	 * something really weird has happened. */
	 
	Dprintf( "AI failed to pick an advance; falling back to the bad decision-making process!\n");
	
	free( uWeight );
	
	

	i = 0;
	for_all_advance_types(a) {
	    if (side_can_research(side, a)) {
		++i;
	    }
	}
	n = xrandom(i);
	i = 0;
	for_all_advance_types(a) {
	    if (side_can_research(side, a)) {
		if (i == n) {
		    net_set_side_research(side, a);
		    return;
		}
		++i;
	    }
	}
	net_set_side_research(side, NONATYPE);
	
}


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Unstable pre-release version of enhanced ai_plan_research
  2004-09-08  4:09 Unstable pre-release version of enhanced ai_plan_research Lincoln Peters
@ 2004-09-08 18:02 ` Eric McDonald
  0 siblings, 0 replies; 2+ messages in thread
From: Eric McDonald @ 2004-09-08 18:02 UTC (permalink / raw)
  To: Lincoln Peters; +Cc: Xconq list

Lincoln Peters wrote:
	

> 	uWeight = malloc( 2 * numAdvances );


I would suggest:
   uweight = (int *)xmalloc(num_advances * sizeof(int));
Xconq's 'xmalloc' checks to see if the 'malloc' succeeded. If it failed, 
then 'run_error' is invoked. 'xmalloc' also scrubs the allocated memory 
to be 0 everywhere.
Furthermore, the problem could be here, because you allocate an array of 
2-byte slots, but you declared the storage type as an 'int' which is 
likely 4 bytes on your system. So, if 'numAdvances' is 4, then you 
allocate 8 bytes, but when you do 'uWeight[3]', you are accessing the 
12th through 15th bytes! Ooops.

> 	for_all_advance_types(count1) {
> 		uWeight[count1] = 0;

The problem could be here. Your 'count1' variable iterates from 0 to 
'numatypes', but the array is only allocated with 'numAdvances' 
positions. 'numAdvances' <= 'numatypes'. You have to worry about the < 
case, because that is a potential source of your crash.

> 				} else if ( ua_multiply_production( count3, count1 ) < 1 ) {
> 					uWeight[count2] -= 1.0 / ua_multiply_production( count3, count1 );
> 				}

The above snippet is a potential divide by zero case. Also, the 
righthand side evaluates to a floating point value, whereas the storage 
on the lefthand side is of an integer type. Furthermore, a factor of 1.0 
is internally 100 in Xconq, so to get a reciprocal, you can do:
   uweight[count2] -= 10000 / ua_multiply_production(count3, count1);
				
Eric

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2004-09-08  8:27 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-09-08  4:09 Unstable pre-release version of enhanced ai_plan_research Lincoln Peters
2004-09-08 18:02 ` Eric McDonald

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).