static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/util/wldchk.c,v 2.1 1995/07/09 21:03:29 empire Exp $";
/**********************************************************************
 * wldchk.c
 *
 * For BSD Empire.
 *
 * check the newly created world for goodies.
 *
 * Print out world wide summary,
 *    land, water and mountain summaries,
 *    land only continents summaries,
 *    land & mountain continent summaries.
 *
 * This program is intended to give an idea of what the distribution
 * of resources is in the world, and how balanced the continents are.
 *
 * Reworked from empchk.c
 *
 * Usage:
 *     wldchk [-c X Y [-a]] [-s sectorfile]
 *
 *   where:
 *         -s sectorfile  specifies a specific sector file to examine.
 *         -c X Y  specifies a specific continent (of which X,Y is part of)
 *         -a      include mountains in continent check.
 *         -d      don't print % distributions.
 *
 *   note that X & Y are in POGO coordinates.
 *
 * D.Hay, Dec 12, 1989
 * Electrical & Computer Engineering,
 * University of Waterloo, Waterloo, Ontario, Canada.
 *
 * $Log: wldchk.c,v $
 * Revision 2.1  1995/07/09  21:03:29  empire
 * b1r19 changes - see REVISIONS
 *
 */

#include <stdio.h>
#include "gamesdef.h"
#include "misc.h"
#include "var.h"
#include "sect.h"
#include "file.h"
#include "path.h"
#include "product.h"

struct sctstr sects[WORLD_Y*WORLD_X/2];
struct s_s {
    s_char f;
    struct sctstr *sect;
} s[WORLD_X][WORLD_Y];

/*
 * A structure for the things we want to count.
 */
#define NUM_DIVS 13
typedef struct counts_s {
    int sectors;
    int gold[NUM_DIVS];
    int iron[NUM_DIVS];
    int fertil[NUM_DIVS];
    int oil[NUM_DIVS];
    int uran[NUM_DIVS];
    int nzgold;
    int nziron;
    int nzfertil;
    int nzoil;
    int nzuran;
    double  total_gold;
    double  total_iron;
    double  total_fertil;
    double  total_oil;
    double  total_uran;
} counts_t;

counts_t wc, waterc, landc, mountc, con, tot;

int print_dist = 1;

/******************************
 * zero_cnts
 *
 * Erase the counting structure.
 */
zero_cnts(res)
    counts_t *res;
{
    res->sectors = 0;
    bzero(res->gold, sizeof(res->gold));
    bzero(res->iron, sizeof(res->iron));
    bzero(res->fertil, sizeof(res->fertil));
    bzero(res->oil, sizeof(res->oil));
    bzero(res->uran, sizeof(res->uran));
    res->nzgold = res->nziron = res->nzfertil = res->nzoil =
	res->nzuran = 0;
    res->total_iron = res->total_gold = res->total_fertil =
	res->total_oil = res->total_uran = 0.0;
}

/***************************
 * count_cell
 *
 * Add the resource, etc from a cell into
 * the resource counting structure.
 */

count_cell(res, sp)
    counts_t *res;
    struct sctstr *sp;
{

    if (!res) return;

    res->sectors++;

    /* Add in the gold counts */
    res->gold[sp->sct_gmin / 10]++;
    res->total_gold += (double) sp->sct_gmin;
    if (sp->sct_gmin) res->nzgold++;

    /* Add in the iron/mineral counts */
    res->iron[sp->sct_min / 10]++;
    res->total_iron += (double) sp->sct_min;
    if (sp->sct_min) res->nziron++;

    /* Add in the fertility counts */
    res->fertil[sp->sct_fertil / 10]++;
    res->total_fertil += (double) sp->sct_fertil;
    if (sp->sct_fertil) res->nzfertil++;

    /* Add in the oil counts */
    res->oil[sp->sct_oil / 10]++;
    res->total_oil += (double) sp->sct_oil;
    if (sp->sct_oil) res->nzoil++;

    /* Add in the uranium counts */
    res->uran[sp->sct_uran / 10]++;
    res->total_uran += (double) sp->sct_uran;
    if (sp->sct_uran) res->nzuran++;
}

/******************************
 * add_cnts
 *
 * Add one resource count summary
 * to another.
 */

add_cnts(sum, add)
    counts_t *sum, *add;
{
    int i;

    if (!sum || !add) return;

    sum->sectors += add->sectors;
    sum->total_iron += add->total_iron;
    sum->total_gold += add->total_gold;
    sum->total_fertil += add->total_fertil;
    sum->total_oil += add->total_oil;
    sum->total_uran += add->total_uran;
    for (i=0; i<NUM_DIVS; i++) {
	sum->iron[i] += add->iron[i];
	sum->gold[i] += add->gold[i];
	sum->fertil[i] += add->fertil[i];
	sum->oil[i] += add->oil[i];
	sum->uran[i] += add->uran[i];
    }
}

/*******************************
 * print_res
 *
 * Print out the resource summary for a
 * count structure.
 */

print_res(res)
    counts_t *res;
{
    register int y, x;
    double totp;

    if (!res) return;

    printf("%d sectors\n", res->sectors);

    /* Gold distribution */
    if (print_dist) {
	printf("\n");
	for (x = 12; x >= 0; x--) {
	    if (res->gold[x] != 0)
		printf("%4d with gold mineral assay %2d0 - %2d9\n",
			res->gold[x], x, x);
	}
    }
    /* Gold summary */
    totp = 100.0 * res->total_gold / pchr[P_DUST].p_nrdep;
    printf("Average gold assay is %.2f, total %.0f, nonzero %d (%.2f%%), dust %.0f\n",
		res->total_gold / (double) res->sectors, res->total_gold,
		res->nzgold,
		(100.0 * (double) res->nzgold/(double) res->sectors),
		totp);

    /* Oil distribution */
    if (print_dist) {
	printf("\n");
	for (x = 12; x >= 0; x--) {
	    if (res->oil[x] != 0)
		printf("%4d with oil content %2d0 - %2d9\n",
			res->oil[x], x, x);
	}
    }
    /* Oil summary */
    totp = 100.0 * res->total_oil / pchr[P_OIL].p_nrdep;
    printf( "Average oil content is %.2f, total %.0f, nonzero %d (%.2f%%), crude %.0f\n",
		res->total_oil / (double) res->sectors, res->total_oil,
		res->nzoil,
		(100.0 * (double) res->nzoil/(double) res->sectors),
		totp);

    /* Iron/mineral distribution */
    if (print_dist) {
	printf("\n");
	for (x = 12; x >= 0; x--) {
	    if (res->iron[x] != 0)
		printf("%4d with iron mineral assay %2d0%% - %2d9%%\n",
			res->iron[x], x, x);
	}
    }
    printf("Average mineral assay is %.2f, total %.2f, nonzero %d (%.2f%%)\n",
		res->total_iron / (double) res->sectors, res->total_iron,
		res->nziron,
		(100.0 * (double) res->nziron/(double) res->sectors));

    /* Uranium distribution */
    if (print_dist) {
	printf("\n");
	for (x = 12; x >= 0; x--) {
	    if (res->uran[x] != 0)
		printf("%4d with uranium mineral assay %2d0%% - %2d9%%\n",
			res->uran[x], x, x);
	}
    }
    /* Uranium summary */
    totp = 100.0 * res->total_uran / pchr[P_URAN].p_nrdep;
    printf("Average uranium assay is %.2f, total %.0f, nonzero %d (%.2f%%), rads %.0f\n",
		res->total_uran / (double) res->sectors, res->total_uran,
		res->nzuran,
		(100.0 * (double) res->nzuran/(double) res->sectors),
		totp);

    /* Fertility distribution */
    if (print_dist) {
	printf("\n");
	for (x = 12; x >= 0; x--) {
	    if (res->fertil[x] != 0)
		printf("%4d with fertility %2d0 - %2d9\n",
			res->fertil[x], x, x);
	}
    }
    /* Fertility summary */
    printf("Average fertility is %.2f, total %.2f, nonzero %d (%.2f%%)\n",
		res->total_fertil / (double) res->sectors, res->total_fertil,
		res->nzfertil,
		(100.0 * (double) res->nzuran/(double) res->sectors));
}

/*************************
 * scnt
 *
 * Count all the continents in the world, as
 * defined by flag.
 */

scnt(flag, res, sum)
    int     flag;
    counts_t *res, *sum;
{
    register int count;
    register int y;
    register int x;
    int masses[128];
    int overmass=0;

    x = 128;
    while (--x >= 0) {
	masses[x] = 0;
    }
    y = WORLD_Y;
    while (--y >= 0) {
	x = WORLD_X;
	while (--x >= 0) {
	    if (((x ^ y) & 1) == 0)
		s[x / 2][y].f |= 1;
	}
    }
    y = WORLD_Y;
    while (--y >= 0) {
	x = WORLD_X;
	while (--x >= 0) {
	    if (((x ^ y) & 1) == 0 && (s[x / 2][y].f & 0x1) != 0 &&
	        (s[x / 2][y].f & flag) != 0) {
		if (res)
		    zero_cnts(res);
		count = neighbors(x, y, flag, res);
		if (count < 128)
		    masses[count]++;
		else
		    overmass++;
		if (flag == 8) {
		    if (count >10) {
			int nx, ny;
			nx = x>WORLD_X/2 ? x - WORLD_X : x;
			ny = y>WORLD_Y/2 ? y - WORLD_Y : y;
			printf("#########\n");
			printf("Landmass with %4d sectors, near %d,%d, or POGO %d,%d\n",
				count, x, y, nx, ny);
			if (res)
			    print_res(res);
		    }
		}
		add_cnts(sum, res);
	    }
	}
    }
    /* Number of continents over 128 sectors */
    if (overmass)
	printf("%d with >= 128 sector(s)\n", overmass);
    /* Distribution of continent sizes */
    x = 128;
    while (--x >= 0) {
	if (masses[x] == 1)
	    printf("One with %4d sector(s)\n", x);
	else if (masses[x] > 1)
	    printf("%3d with %4d sector(s)\n", masses[x], x);
    }
    printf("\n\n");
}

/**************************************
 * sector_check
 *
 * Check out the continent containing a
 * specific sector.
 */

sector_check(sx, sy, all)
    int sx, sy, all;
{
    int count;
    int x, y;
    int flag;
    counts_t res;

    zero_cnts(&res);
    y = WORLD_Y;
    while (--y >= 0) {
	x = WORLD_X;
	while (--x >= 0) {
	    if (((x ^ y) & 1) == 0)
		s[x / 2][y].f |= 1;
	}
    }
    flag = all ? 12 : 8;
    x = sx<0 ? WORLD_X + sx : sx;
    y = sy<0 ? WORLD_Y + sy : sy;
    if (!(s[x/2][y].f & flag)) {
	fprintf(stderr, "Sector %d,%d is not land or mountain\n",
	    sx, sy);
	return;
    }
    count = neighbors(x, y, flag, &res);
    
    printf("Landmass with %4d sectors, near %d,%d, or POGO %d,%d\n",
	    count, x, y, sx, sy);
    if (all) {
	printf("Counting mountains\n");
    } else
	printf("Land sectors only\n");
    print_res(&res);
}

/****************************************
 * neighbors
 *
 * Count the number of connected neighboring cells
 * to the current one.
 */
 
neighbors(this_x, this_y, flag, res)
    int     this_x;
    int     this_y;
    int     flag;
    counts_t *res;
{
    register int count;
    register int y;
    register int x;
    register int direction;

    s[this_x / 2][this_y].f &= ~1;
    if (res)
	count_cell(res, s[this_x/2][this_y].sect);
    count = 1;
    for (direction = 1; direction <= 6; direction++) {
	x = (diroff[direction][0] + this_x + WORLD_X) % WORLD_X;
	y = (diroff[direction][1] + this_y + WORLD_Y) % WORLD_Y;
	if ((s[x / 2][y].f & 0x1) != 0 && (s[x / 2][y].f & flag) != 0)
	    count += neighbors(x, y, flag, res);
    }
    return count;
}

/************************************************
 * transfer_sect
 *
 * Set up the sector pointer structure, and
 * count the global land, mountain, water and total
 * summaries.
 */
transfer_sect()
{
    register struct sctstr *sp;
    register int y;
    register int x;

    sp = sects;
    for (y = 0; y < WORLD_Y; y++) {
	for (x = 0; x < WORLD_X; x++) {
	    if (((x ^ y) & 1))
		continue;
	    if (sp->sct_type == SCT_WATER) {
		s[x / 2][y].f = 2;
		count_cell(&waterc, sp);
	    } else if (sp->sct_type == SCT_MOUNT) {
		s[x / 2][y].f = 4;
		count_cell(&mountc, sp);
	    } else {
		s[x / 2][y].f = 8;
		count_cell(&landc, sp);
	    }
	    s[x/2][y].sect = sp;
	    count_cell(&wc, sp);
	    sp++;
	}
    }
}

/********************************************
 * default_chk
 *
 * The default series of checks to perform if
 * not checking a specific continent.
 */

default_chk()
{
    printf("***********************\n");
    printf("World wide resources, water, land, mountains\n");
    print_res(&wc);

    printf("***********************\n");
    printf("World wide resources, land only\n");
    print_res(&landc);

    printf("***********************\n");
    printf("World wide resources, water only\n");
    print_res(&waterc);

    printf("***********************\n");
    printf("World wide resources, mountains only\n");
    print_res(&mountc);

    printf("***********************\n");
    printf("CONTINENTS\n");
    printf("Counting only rural...\n");
    scnt(8, &con, &tot);

    printf("***********************\n");
    printf("Total res of counted land\n");
    print_res(&tot);

    printf("***********************\n");
    printf("Counting rural & mount...\n");
    scnt(12, 0L, 0L);

    return(0);
}


main (argc, argv)
    int argc;
    s_char *argv[];
{
    int   argi, optcont, p1, p2;
    s_char  *arg;
    s_char  *sectfil;
    int   sectf;
    int   sectchk=0, sx, sy;
    int   all;


    zero_cnts(&wc);
    zero_cnts(&tot);
    zero_cnts(&landc);
    zero_cnts(&waterc);
    zero_cnts(&mountc);
    sectfil = empfile[EF_SECTOR].file;

    argi = 0;
    while(++argi < argc) {	/* While there are args to process */
	arg = argv[argi];
	if ( *arg == '-' ) {	/* minus options */
	    optcont = 1;
	    while ( *++arg && optcont ) {   /* while option chars */
		switch ( *arg ) {   /* case on minus option chars */
		    case 's':
			if (++argi < argc) {
			    sectfil = argv[argi];
			} else usagequit(1);
			optcont=0;  break;
		    case 'e':
			if (++argi < argc)
				emp_config (argv[argi]);
			else usagequit(4);
			break;
		    case 'a':
			all = !all;  break;
		    case 'd':
			print_dist = !print_dist; break;
		    case 'c':
			if (++argi < argc) {
			    p1=atoi(argv[argi]);
			    if (++argi < argc) {
				p2=atoi(argv[argi]);
				if ((p2<-WORLD_Y/2) || (p2>=WORLD_Y/2) ||
					(p1<-WORLD_X/2) || (p1>=WORLD_X/2))
				    usagequit(3);
				sectchk = 1;
				sx = p1;  sy = p2;
			    } else usagequit(2);
			} else usagequit(2);
			optcont = 0;  break;
		    default:
			printf("Invalid option : '%c' in '%s'\n",
					*arg, argv[argi]);
			usagequit(0);
		} /* switch */
	    } /* while */
	} else {	/* Not an option */
	    usagequit(0);
	}    /* end of if else sequence */
    }  /* end of while on arguments passed */


    sectf = open(sectfil, 0);
    if (sectf < 0) {
	perror(sectfil);
	exit(1);
    }
    read(sectf, sects, sizeof(sects));
    close(sectf);
    printf("Examining sector file %s\n", sectfil);

    transfer_sect();

    if (sectchk) {
	sector_check(sx, sy, all);
    } else
	default_chk();
}

usagequit(typ)
    int typ;
{
    if (typ == 1) {
	printf("Usage: -s sectorfilename\n");
    } else if (typ == 2) {
	printf("Usage: -c X Y\n");
    } else if (typ == 3) {
	printf("Usage: X must be between %d & %d\n", -WORLD_X/2, WORLD_X/2-1);
	printf("Usage: Y must be between %d & %d\n", -WORLD_Y/2, WORLD_Y/2-1);
    } else if (typ == 4) {
        printf ("Usage: -e configfile\n");
    } else {
	printf("Usage: [-e configfile] [-s sectfile] [-c X Y [-a]] [-d]\n");
    }
    exit(1);
}
