// phmap1.c  MR May 2001
//
// Pheromone Map, for quick determining of distance to
// nearest pheromone-emitting entity on/in a chessboard world.
//
// This version uses "city-block distance".
// 

// User declares array int phmap[ XSIZE * YSIZE ], where
// X/YSIZE are the width/height of the chessboard.

// User makes func calls in this order:
//  1. phmap_init() (This sets all squares to -1.)
//  2. Call phmap_enteremitter() once for each pheromone-emitting
//     entity.
//  3. Call phmap_calc() to calculate the spreading of the pheromone
//     over the map.
//  4. To retrieve the results from the previous step, call 
//     phmap_getdist() as many times as you like to ask the
//     distance of a square to the nearest pheromone-emitting entity.
//     NOTE: phmap_getdist() returns -1 if there is NO pheromone
//     emitter anywhere on the map.


#include <stdio.h>
#include <assert.h>
#include "bool.h"


#define ELACCESS( pmap, xsize, ix, iy ) \
	( (pmap)[ (xsize) * (iy) + (ix) ] )

_bool inMap( int xsize, int ysize, int ix, int iy )
	{
	return ( 0 <= ix && ix < xsize &&
	         0 <= iy && iy < ysize );
	}



void phmap_init(
	int * pmap,
	int xsize,
	int ysize )
	{
	int i;
	for ( i = 0; i < xsize*ysize; i++ )	
		{
		pmap[i] = -1;
		}
	}


void phmap_enteremitter(
	int * pmap,
	int xsize,
	int ysize,
	int ix,
	int iy )
	// Tell the phmap that there's a pheromone-emitting entity
	// in square (ix,iy).
	{
	assert ( inMap( xsize, ysize, ix, iy ) );
	ELACCESS( pmap, xsize, ix, iy ) = 0;
	}


static _bool _SQV(  // SQuare Value
	int * pmap,
	int xsize,
	int ysize,
	int ix,
	int iy,
	int val )
	// Return 1 if square in map and has value 'val'.
	{
	return ( inMap( xsize, ysize, ix, iy ) &&
	         ELACCESS( pmap, xsize, ix, iy ) == val );
	}



void phmap_calc(
	int * pmap,
	int xsize,
	int ysize )
	// Calculate the pheromone spreading.
	{
	int iiter = 1;

	for(;;)
		{
		_bool donesomething = 0;
		int ix, iy;

		for ( ix = 0; ix < xsize; ix++ )
			{
			for ( iy = 0; iy < ysize; iy++ )
				{
				if ( ELACCESS( pmap, xsize, ix, iy ) != -1 )
					{ continue; }
	
				if ( _SQV(pmap,xsize,ysize,ix-1,iy,iiter-1) ||
				     _SQV(pmap,xsize,ysize,ix+1,iy,iiter-1) ||
				     _SQV(pmap,xsize,ysize,ix,iy-1,iiter-1) ||
				     _SQV(pmap,xsize,ysize,ix,iy+1,iiter-1) )
					{
					ELACCESS(pmap,xsize,ix,iy) = iiter;
					donesomething = 1;
					}
				}
			}

		if ( donesomething == 0 ) { return; } //Ready

		iiter++;
		}
	}




int phmap_getdist(
	const int * pmap,
	int xsize,
	int ysize,
	int ix,
	int iy )
	// Return city-block distance of square (ix,iy) to
	// nearest pheromone-emitting entity.
	// NOTE: returns -1 if there is NO pheromone
	// emitter anywhere on the map.
	{
	return ELACCESS( pmap, xsize, ix, iy );
	}


void phmap_fprint(  // (For testing purposes)
	FILE * fp,
	const int * pmap,
	int xsize,
	int ysize )
	{
	int ix, iy;
	for ( iy = 0; iy < ysize; iy++ )
		{
		for ( ix = 0; ix < xsize; ix++ )
			{
			int ival = ELACCESS( pmap, xsize, ix, iy );
			char c;

			if ( ival < 10 ) 
				{ c = '0' + ival; }
			else if ( ival < 36 ) 
				{ c = 'a' + ival - 10; }
			else if ( ival < 62 )
				{ c = 'A' + ival - 36; }
			else
				{ c = '$'; }

			fprintf( fp, " %c", c );
			}
		fprintf( fp, "\n" );
		}
	}


