#include #include #include #include #include #ifndef LOCI #define LOCI 1 #endif #include "africa.h" #include "variate.h" static struct climate climates[] = { { "Af", "Tropical Rain Forest", 3, 0, { 161,26,20 } }, { "Am", "Tropical Monsoon", 45, 0, { 255,33,26 } }, { "As", "Dry Savanna", 50, 0, { 255,163,150 } }, { "Aw", "Wet Savanna", 125, 0, { 255,205, 199 } }, { "Awf", "Wet Savanna forest", 100, 0, { 255,205, 199 } }, { "BSh", "Hot Steppe", 12, 0, { 211,139,27 } }, { "BSk", "Cold Steppe", 12, 0, { 207,169,81 } }, { "BWk", "Cold Desert", 3, 0, { 254,245,91 } }, { "BWh", "Hot Desert", 3, 0, { 255,197,13 } }, { "Cfa", "Warm Temperate", 125, 0, { 14,43,13 } }, { "Cfb", "Maritime", 50, 0, { 21,68,22 } }, { "Csa", "Med", 50, 0, { 17,214,16 } }, { "Csb", "Med", 50, 0, { 140,230,18 } }, { "Cwa", "Warm Termperate", 125, 0, { 184,103,24 } }, { "Cwb", "Maritime", 125, 0, { 154,100,25 } }, { "Lf", "Lake", 0, 0, { 0,0,245 } }, { {0} } }; struct alt_climate_search { int hex, year; }; static int alt_climate_compare(const void *key, const void *climate) { const struct climaterange *v; const struct alt_climate_search *k; v = climate; k = key; if (v->hex > k->hex) return -1; /* later hex */ if (v->hex < k->hex) return 1; /* earlier hex */ if (v->end < k->year) return 1; /* ends before year */ if (v->start > k->year) return -1; /* hasn't started yet */ return 0; } static int compare_cr(const void *av, const void *bv) { const struct climaterange *a, *b; a = av; b = bv; if (a->hex < b->hex) return -1; if (a->hex > b->hex) return 1; if (a->start < b->start) return -1; if (a->start > b->start) return 1; return 0; } struct climate *find_climate(char *code) { int i; for (i=0; climates[i].code[0]; i++) { if (!strcmp(code, climates[i].code)) { return &climates[i]; } } return 0; } struct afrhex *search_hex(struct afrhex *map, int64_t hex) { for (; map; map = map->next) { printf("checking %lld for %lld\n", map->hex, hex); if (map->hex == hex) { printf("found\n"); return map; } } return map; } struct afrhex *find_hex(struct afrhex *map, int64_t hex) { for (; map; map = map->next) { if (map->hex == hex) { return map; } } return map; } uint64_t total_pop(struct afrhex *map) { uint64_t count = 0; for (; map; map = map->next) { count += map->freq[0]; count += map->freq[1]; } return count/2; } /* set up climate cap */ /* base is people per 100 sq km */ /* we divide by an additional 4.0 for the small pop model */ #define SQRT3 1.73205080756887729352 void climate_init(double width, double capfactor) { double area; int i; area = width * width * SQRT3 / 2.0; for (i = 0; climates[i].code[0]; i++) { climates[i].cap = climates[i].basecap * area / 100.0 * capfactor; } } /* width in km */ struct afrhex *map_init(struct maphex *maphexes, double width, double capfactor) { int i, j; struct afrhex *hex, *prev, *map; hex = prev = 0; climate_init(width, capfactor); for (i=0; maphexes[i].hex; i++) { hex = malloc(sizeof *hex); hex->hex = maphexes[i].hex; for (j=0; j < 2; j++) { hex->freq[j] = 0; hex->outmigrate[j] = 0; hex->inmigrate[j] = 0; } hex->climate = find_climate(maphexes[i].climate); hex->map = &maphexes[i]; hex->pop = 0; hex->migrants = 0; hex->attract = 0; hex->next = prev; prev = hex; } map = hex; /* pre-compute hex pointers to adjacent hexes */ for (hex = map; hex; hex = hex->next) { for (i = 0; i < hex->map->nadj; i++) { hex->map->adjhex[i] = find_hex(map, hex->map->adjacent[i]); } } return map; } struct climaterange *find_alt_climate(int hex, int year) { static int sorted = 0; static size_t nmemb = -1; struct alt_climate_search s; #if 1 if (nmemb == -1) { nmemb = 0; while (altclimates[nmemb].code[0]) nmemb++; } if (!sorted) { qsort(altclimates, nmemb, sizeof(struct climaterange), compare_cr); sorted = 1; } s.hex = hex; s.year = year; return bsearch(&s, altclimates, nmemb, sizeof(struct climaterange), alt_climate_compare); #else int i; //fprintf(stderr, "scanning altclimate %d %d\n", hex, year); for (i=0; altclimates[i].code[0]; i++) { if (altclimates[i].hex == hex && altclimates[i].start <= year && altclimates[i].end >= year) { return &altclimates[i]; } } return 0; #endif } /* TODO implement change */ struct climate *climateyear(struct afrhex *hex, int year) { struct climate *c = 0; struct climaterange *alt; alt = find_alt_climate(hex->hex, year); if (alt) { c = find_climate(alt->code); } else { c = find_climate(hex->map->climate); } #if 0 if (c != hex->climate || hex->hex == 187) fprintf(stderr, "%d got new climate %s in %d\n", hex->hex, c->code, year); #endif return c; } #define POP(x) ( ((x[0]) + (x[1])) / 2) void nextgen(struct afrhex *hexlist, int year, unsigned int climate) { struct afrhex *hex; for (hex = hexlist; hex; hex = hex->next) { hex->outmigrate[0] = hex->outmigrate[1] = 0; hex->inmigrate[0] = hex->inmigrate[1] = 0; if (climate) { hex->climate = climateyear(hex, year); } } /* growth and emmigration */ for (hex = hexlist; hex; hex = hex->next) { unsigned int pop; unsigned int new[2]; hex->pop = POP(hex->freq); pop = (hex->freq[0] + hex->freq[1])/2; pop = hex->pop; if (pop == 0 ) { hex->attract = hex->climate->cap; continue; /* nothing else to do here */ } #if 0 printf("hex %lld (%s) pop = [%u, %u] (%d/%d ind)\n", hex->hex, hex->climate->code, hex->freq[0], hex->freq[1], hex->pop, hex->climate->cap); #endif /* poisson distribution on births ? */ if (pop > hex->climate->cap) { pop *= 0.6; /* should probably round down */ } else { pop *= 1.15; /* should probably round up */ } /* pick pop * 2 since we're diploid */ var_rmultinom(pop * 2, hex->freq, new); hex->freq[0] = new[0] ; hex->freq[1] = new[1]; hex->pop = POP(new); /* TODO if too small, say under 25, either move everyone or die */ hex->migrants = hex->pop - hex->climate->cap; if (hex->pop < 25) { hex->migrants = hex->pop; } if (hex->migrants > 0) { var_rhyperv(hex->migrants * 2, hex->freq, hex->outmigrate); /* TODO could just set it to a quarter of the cap or something */ } #if 0 printf("hex %lld new pop = [%u, %u] (%d ind) (-%u,-%u) (+%u,+%u)\n", hex->hex, hex->freq[0], hex->freq[1], hex->pop, hex->outmigrate[0], hex->outmigrate[1], hex->inmigrate[0], hex->inmigrate[1] ); #endif hex->attract = (int)sqrt((double)hex->climate->cap); if (hex->attract < hex->climate->cap - hex->pop) { hex->attract = hex->climate->cap - hex->pop; } } /* now handle immigration */ for (hex = hexlist; hex; hex = hex->next) { unsigned int attr[18]; int i; int tattr = 0; struct afrhex *target; if (hex->migrants <= 0) continue; /* gather attractiveness of migration targets */ #if 0 printf("hex %lld migrating: ( ", hex->hex); #endif for (i = 0; i < hex->map->nadj; i++) { attr[i] = hex->map->adjhex[i]->attract; tattr += attr[i]; #if 0 printf("%lld:%u ", hex->map->adjhex[i]->hex, attr[i]); #endif } #if 0 printf(")\n"); #endif /* no where to go ? */ if (tattr == 0) { hex->outmigrate[0] = 0; hex->outmigrate[1] = 0; hex->migrants = 0; continue; } i = var_pick(i, attr); #if 0 printf("choose %d = %lld\n", i+1, hex->map->adjhex[i]->hex); #endif target = hex->map->adjhex[i]; target->inmigrate[0] += hex->outmigrate[0]; target->inmigrate[1] += hex->outmigrate[1]; } /* and finally sum up population so we're ready for the next generation */ for (hex = hexlist; hex; hex = hex->next) { hex->freq[0] += hex->inmigrate[0]; hex->freq[1] += hex->inmigrate[1]; hex->freq[0] -= hex->outmigrate[0]; hex->freq[1] -= hex->outmigrate[1]; hex->pop = (hex->freq[0] + hex->freq[1])/2; #if 0 if (hex->pop > 0) { printf("hex %lld new pop = [%u, %u] (%d/%u ind) (-%u,-%u) (+%u,+%u)\n", hex->hex, hex->freq[0], hex->freq[1], hex->pop, hex->climate->cap, hex->outmigrate[0], hex->outmigrate[1], hex->inmigrate[0], hex->inmigrate[1] ); } #endif } }