/******************************************************************************
Curse of War -- Real Time Strategy Game for Linux.
Copyright (C) 2013 Alexey Nikolaev.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
******************************************************************************/
#include "grid.h"
int is_a_city(enum tile_class t) {
switch(t) {
case village: return 1;
case town: return 1;
case castle: return 1;
default: return 0;
}
}
int is_inhabitable(enum tile_class t) {
switch(t) {
case abyss:
case mountain:
case mine: return 0;
default: return 1;
}
}
int is_visible(enum tile_class t) {
switch(t) {
case abyss: return 0;
default: return 1;
}
}
const struct loc dirs[DIRECTIONS] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}, {1,-1}, {-1, 1}};
void grid_init(struct grid *g, int w, int h){
g->width = MIN(w, MAX_WIDTH);
g->height = MIN(h, MAX_HEIGHT);
int i, j;
for(i=0; iwidth; ++i) {
for(j=0; jheight; ++j) {
g->tiles[i][j].cl = grassland;
int x = rand() % 20;
if(0 == x) {
int y = rand() % 6;
switch (y){
case 0:
g->tiles[i][j].cl = castle; break;
case 1: case 2:
g->tiles[i][j].cl = town; break;
default:
g->tiles[i][j].cl = village;
}
}
if(x > 0 && x < 5) {
// mountains and mineis
if (rand() % 10 == 0)
g->tiles[i][j].cl = mine;
else
g->tiles[i][j].cl = mountain;
g->tiles[i][j].pl = NEUTRAL;
}
else {
x = 1 + rand() % (MAX_PLAYER - 1);
if (x < MAX_PLAYER) g->tiles[i][j].pl = x;
else
g->tiles[i][j].pl = NEUTRAL;
}
int p, c;
for (p=0; ptiles[i][j].units[p][c] = 0;
}
}
if (is_a_city(g->tiles[i][j].cl)) {
int owner = g->tiles[i][j].pl;
g->tiles[i][j].units[owner][citizen] = 10;
}
}
}
}
/* Stencils */
int stencil_avlbl_loc_num (enum stencil st){
switch(st) {
case st_rhombus: return 4;
case st_rect: return 4;
case st_hex: return 6;
}
return 0;
}
#define X_OF_IJ(i,j) 0.5*(j) + (i)
#define Y_OF_IJ(i,j) (float)(j)
void stencil_rhombus (struct grid *g, int d, struct loc loc[MAX_AVLBL_LOC]) {
int xs[] = {d, g->width-1-d, d, g->width-1-d};
int ys[] = {d, g->height-1-d, g->height-1-d, d};
int loc_num = 4;
int k;
for(k=0; kheight-1) - epsilon;
float y0 = Y_OF_IJ(0, 0) - epsilon;
float x1 = X_OF_IJ(g->width-1, 0) + epsilon;
float y1 = Y_OF_IJ(0, g->height-1) + epsilon;
for (i=0; iwidth; ++i)
for (j=0; jheight; ++j) {
x = X_OF_IJ(i,j);
y = Y_OF_IJ(i,j);
if (xx1 || yy1)
g->tiles[i][j].cl = abyss;
}
int loc_num = 4;
int dx = g->height/2;
struct loc temp_loc[] = {
{dx+d-1, d},
{g->width-dx-1-d+1, g->height-1-d},
{d+1, g->height-1-d},
{g->width-1-d-1, d}
};
int k;
for(k=0; kheight/2;
for (i=0; iwidth; ++i)
for (j=0; jheight; ++j) {
if (i+jg->width-1+g->height-1-dx)
g->tiles[i][j].cl = abyss;
}
int loc_num = 6;
struct loc temp_loc[] = {
{dx+d-2, d}, // tl
{d, g->height-1-d}, // bl
{g->width-1-d, dx}, // cr
{d, dx}, // cl
{g->width-1-d-2+2, d}, // tr
{g->width-1-dx-d+2, g->height-1-d} // br
};
int k;
for(k=0; kwidth; ++i)
for (j=0; jheight; ++j) {
if (g->tiles[i][j].cl == abyss) {
int p;
for(p=0; ptiles[i][j].units[p][citizen] = 0;
g->tiles[i][j].pl = NEUTRAL;
}
}
}
}
/* Ended Stencils */
/* helper.
* floodfill with value val, the closest distance has priority */
void floodfill_closest (struct grid *g, int u[MAX_WIDTH][MAX_HEIGHT], int d[MAX_WIDTH][MAX_HEIGHT], int x, int y, int val, int dist) {
if (x < 0 || x >= g->width || y < 0 || y >= g->height || is_inhabitable(g->tiles[x][y].cl) == 0 || d[x][y] <= dist) {
return;
}
u[x][y] = val;
d[x][y] = dist;
int k;
for (k = 0; kwidth; ++i)
for(j=0; jheight; ++j) {
d[i][j] = MAX_WIDTH * MAX_HEIGHT + 1;
u[i][j] = unreachable;
}
int k;
for(k=0; kwidth; ++i)
for(j=0; jheight; ++j){
if (is_inhabitable (g->tiles[i][j].cl)) {
g->tiles[i][j].units[u[i][j]][citizen] = 1;
g->tiles[i][j].pl = u[i][j];
}
}
*/
for(i=0; iwidth; ++i)
for(j=0; jheight; ++j){
if (g->tiles[i][j].cl == mine) {
int single_owner = unreachable;
int max_dist = 0;
int min_dist = MAX_WIDTH * MAX_HEIGHT + 1;
for (k = 0; k= g->width || y < 0 || y >= g->height || is_inhabitable(g->tiles[x][y].cl) == 0) {
continue;
}
//g->tiles[x][y].units[u[x][y]][citizen] = 401;
//g->tiles[x][y].pl = u[x][y];
if (single_owner == unreachable) {
single_owner = u[x][y];
max_dist = d[x][y];
min_dist = d[x][y];
}
else {
if (u[x][y] == single_owner) {
max_dist = MAX(max_dist, d[x][y]);
min_dist = MIN(min_dist, d[x][y]);
}
else if (u[x][y] != unreachable) single_owner = competition;
}
}
if (single_owner != competition && single_owner != unreachable)
result[single_owner] += (int) ( 100.0 * (MAX_WIDTH + MAX_HEIGHT) * exp(-10.0 * (float)max_dist*min_dist / (MAX_WIDTH*MAX_HEIGHT)) );
}
}
return;
}
/* simple shuffling of an array of integers */
void shuffle (int arr[], int len) {
int t, i, j, s;
for(t=0; twidth; ++i) {
for(j=0; jheight; ++j) {
for (p=0; p< MAX_PLAYER; ++p) {
for (c = 0; ctiles[i][j].units[p][c] = 0;
g->tiles[i][j].pl = NEUTRAL;
if (is_a_city(g->tiles[i][j].cl))
g->tiles[i][j].cl = grassland;
//g->tiles[i][j].pl = NEUTRAL;
}
}
}
}
locations_num = IN_SEGMENT(locations_num, 2, available_loc_num);
int num = MIN(locations_num, players_num + ui_players_num);
/* shift in the positions arrays */
int di = rand() % available_loc_num;
struct loc chosen_loc [MAX_AVLBL_LOC];
i = 0;
while (i < num) {
int ii = (i + di + available_loc_num) % available_loc_num;
int x = loc_arr[ii].i;
int y = loc_arr[ii].j;
chosen_loc[i].i = x;
chosen_loc[i].j = y;
g->tiles[x][y].cl = castle;
/* place mines nearby */
int dir = rand() % DIRECTIONS;
int ri = dirs[dir].i;
int rj = dirs[dir].j;
int m = 1;
int mine_i = x + m*ri;
int mine_j = y + m*rj;
g->tiles[mine_i][mine_j].cl = mine;
g->tiles[mine_i][mine_j].pl = NEUTRAL;
mine_i = x - 2*m*ri;
mine_j = y - 2*m*rj;
g->tiles[mine_i][mine_j].cl = mine;
g->tiles[mine_i][mine_j].pl = NEUTRAL;
mine_i = x - m*ri;
mine_j = y - m*rj;
g->tiles[mine_i][mine_j].cl = grassland;
g->tiles[mine_i][mine_j].pl = NEUTRAL;
i++;
}
/* eval locations */
int eval_result[] = {0, 0, 0, 0, 0, 0, 0};
int loc_index[] = {0, 1, 2, 3, 4, 5, 6};
eval_locations(g, chosen_loc, eval_result, num);
/* sort in increasing order */
sort(eval_result, loc_index, num);
/* Compute inequality */
if (ineq != RANDOM_INEQUALITY)
{
float avg = 0;
for(i=0; i50) return -1; break;
case 1: if (x<=50 || x>100) return -1; break;
case 2: if (x<=100 || x>250) return -1; break;
case 3: if (x<=250 || x>500) return -1; break;
case 4: if (x<=500) return -1; break;
}
}
/* suffled computer players */
int *sh_players_comp = (int*)malloc(sizeof(int)*players_num);
for(i=0; i 0) {
int select = IN_SEGMENT(num - conditions, 0, num-1);
ihuman = loc_index[select];
}
i = 0;
while (i < num) {
int ii = loc_index[i];
int x = chosen_loc[ ii ].i;
int y = chosen_loc[ ii ].j;
/*
if (human_player != NEUTRAL && ihuman == ii)
g->tiles[x][y].pl = human_player;
else
g->tiles[x][y].pl = sh_players[i];
*/
if (ui_players_num > 1) {
g->tiles[x][y].pl = sh_players[i];
}
else {
if (ii == ihuman)
g->tiles[x][y].pl = ui_players[0];
else
g->tiles[x][y].pl = sh_players_comp[i];
}
g->tiles[x][y].units[ g->tiles[x][y].pl ][citizen] = 10;
i++;
}
/* free allocated memory */
free(sh_players);
free(sh_players_comp);
return 0;
}
/* helper */
void floodfill (struct grid *g, int u[MAX_WIDTH][MAX_HEIGHT], int x, int y, int val) {
if (x < 0 || x >= g->width || y < 0 || y >= g->height || is_inhabitable(g->tiles[x][y].cl) == 0 ||
u[x][y] == val) {
return;
}
u[x][y] = val;
int k;
for (k = 0; kwidth; ++i)
for(j=0; jheight; ++j)
m[i][j] = 0;
int colored = 0;
for(i=0; iwidth; ++i) {
for(j=0; jheight; ++j) {
if (g->tiles[i][j].pl != NEUTRAL) {
if (colored && m[i][j] == 0) return 0;
colored = 1;
floodfill(g, m, i, j, 1);
}
}
}
return 1;
}
void flag_grid_init(struct flag_grid *fg, int w, int h) {
fg->width = MIN(w, MAX_WIDTH);
fg->height = MIN(h, MAX_HEIGHT);
int i, j;
for(i=0; iwidth; ++i) {
for(j=0; jheight; ++j) {
fg->flag[i][j] = FLAG_OFF;
fg->call[i][j] = 0;
}
}
}
void spread (struct grid *g, int u[MAX_WIDTH][MAX_HEIGHT], int v[MAX_WIDTH][MAX_HEIGHT], int x, int y, int val, int factor) {
if (x < 0 || x >= g->width || y < 0 || y >= g->height || is_inhabitable(g->tiles[x][y].cl) == 0) {
return;
}
int d = val - u[x][y];
if (d > 0) {
v[x][y] = MAX(0, v[x][y] + d * factor);
u[x][y] += d;
int k;
for (k = 0; k= g->width || y < 0 || y >= g->height || v[x][y] == val) {
return;
}
v[x][y] = val;
int k;
for (k = 0; k= g->width || y < 0 || y >= g->height ||
is_inhabitable(g->tiles[x][y].cl) == 0 || fg->flag[x][y] == FLAG_ON) {
return;
}
int u[MAX_WIDTH][MAX_HEIGHT];
int i, j;
for(i=0; i< MAX_WIDTH; ++i){
for(j=0; jflag[x][y] = FLAG_ON;
spread(g, u, fg->call, x, y, val, 1);
}
void remove_flag (struct grid *g, struct flag_grid *fg, int x, int y, int val) {
// exit if
if (x < 0 || x >= g->width || y < 0 || y >= g->height ||
is_inhabitable(g->tiles[x][y].cl) == 0 || fg->flag[x][y] == FLAG_OFF) {
return;
}
int u[MAX_WIDTH][MAX_HEIGHT];
int i, j;
for(i=0; i< MAX_WIDTH; ++i){
for(j=0; jflag[x][y] = FLAG_OFF;
spread(g, u, fg->call, x, y, val, -1);
}
void remove_flags_with_prob (struct grid *g, struct flag_grid *fg, float prob) {
int i, j;
for (i=0; iwidth; ++i) {
for (j=0; jheight; ++j) {
if (fg->flag[i][j] && (float)rand() / RAND_MAX <= prob) {
remove_flag(g, fg, i, j, FLAG_POWER);
}
}
}
}