Mercurial > MadButterfly
view examples/tank/enemy.c @ 1434:4be04f29fa70
Add functions to search for the text recursively inside coord_t tree. Once we find the first instance, we change the text of it. We need to think about how to manage the multiple segment texts, which is composed of several tspan.
author | wycc |
---|---|
date | Mon, 11 Apr 2011 12:52:09 +0800 |
parents | 45fcbd54e873 |
children |
line wrap: on
line source
#include <stdio.h> #include <time.h> #include <stdlib.h> #include <string.h> #include "tank.h" struct _enemy { tank_rt_t *tank_rt; tank_t *tank; int memory[4]; }; typedef struct _enemy enemy_t; /*! \brief Pheromone Map trace the freq. the enemy tanks moving on an area. * * Every time a tank move to an area, it leaves 100 units of pheromone * on the area. And 9 of 10 pheromone are removed from the area for * every time slice (1/3 second). The max value of phereomone in an * area is 991. */ static int pheromone_map[MAP_H][MAP_W]; static void init_pheromone_map(void) { int i, j; for(i = 0; i < MAP_H; i++) for(j = 0; j < MAP_W; j++) pheromone_map[i][j] = 0; } static void remove_pheromone(void) { int i, j; for(i = 0; i < MAP_H; i++) for(j = 0; j < MAP_W; j++) pheromone_map[i][j] = pheromone_map[i][j] * 9 / 10; } static void leave_pheromone(int x, int y) { pheromone_map[y][x] += 100; } /* \brief Fire and move to the target tank if they are in a row or column. */ static int try_fire(tank_t *me, tank_t *target, tank_rt_t *tank_rt) { int x, y; int *tracer = NULL; int target_value; int target_dir; tank_t **enemies; int i; if(me->map_x == target->map_x) { /* In a row */ tracer = &y; target_value = target->map_y; if(me->map_y < target->map_y) target_dir = TD_DOWN; else target_dir = TD_UP; } if(me->map_y == target->map_y) { /* In a column */ tracer = &x; target_value = target->map_x; if(me->map_x < target->map_x) target_dir = TD_RIGHT; else target_dir = TD_LEFT; } if(tracer == NULL) return 0; /* Not in a row or column */ /* Check obstacles between tanks */ x = me->map_x; y = me->map_y; enemies = tank_rt->tank_enemies; if(*tracer < target_value) { while(++*tracer < target_value) { if(map[y][x] != MUD) break; for(i = 0; i < tank_rt->n_enemy; i++) { if(enemies[i]->map_x == x && enemies[i]->map_y == y) break; } if(i != tank_rt->n_enemy) break; } } else { while(--*tracer > target_value) { if(map[y][x] != MUD) break; for(i = 0; i < tank_rt->n_enemy; i++) { if(enemies[i]->map_x == x && enemies[i]->map_y == y) break; } if(i != tank_rt->n_enemy) break; } } if(*tracer == target_value) { /* No any obstacle between tanks */ /* Fire and move to target */ if(me->direction == target_dir && me->bullet == NULL) tank_fire_bullet(tank_rt, me); tank_move(me, target_dir, tank_rt); leave_pheromone(me->map_x, me->map_y); return 1; } return 0; /* Find one or more obstacles */ } #define NOTHING 0 #define SOMETHING 1 static void move_tank(enemy_t *enemy, tank_rt_t *tank_rt) { tank_t *me; tank_t **tanks, *tank; static const int shift_xy[4][2] = { {1, 0}, {0, 1}, {-1, 0}, {0, -1}}; int status[4]; int x, y; int i, tank_i; int dir, chk_dir; int interest_areas[4]; int all_interest; int min_interest; int possibles; int interest_dir; me = enemy->tank; tanks = tank_rt->tanks; /* Collect status */ for(i = 0; i < 4; i++) { x = me->map_x + shift_xy[i][0]; y = me->map_y + shift_xy[i][1]; interest_areas[i] = 0; /* Check obstacles */ if(x == -1 || y == -1 || x >= MAP_W || y >= MAP_H) { /* Out of range */ status[i] = SOMETHING; continue; } if(map[y][x] == MUD) { status[i] = NOTHING; interest_areas[i] = 992 - pheromone_map[y][x]; } else status[i] = SOMETHING; /* Check tanks */ for(tank_i = 0; tank_i < tank_rt->n_tanks; tank_i++) { tank = tanks[tank_i]; if(tank->map_x == x && tank->map_y == y) { status[i] = SOMETHING; break; } } } /* Try the same direction if status is not changed. */ for(i = 0; i < 4; i++) { if(status[i] != enemy->memory[i]) break; } if(i == 4) { /* Status is not changed */ tank_move(me, me->direction, tank_rt); leave_pheromone(me->map_x, me->map_y); return; } memcpy(enemy->memory, status, sizeof(int) * 4); /* Check possible directions except backward. */ switch(me->direction) { case TD_UP: dir = 3; break; case TD_RIGHT: dir = 0; break; case TD_DOWN: dir = 1; break; case TD_LEFT: dir = 2; break; } /* Compute itnerest for nearby areas */ possibles = 0; all_interest = 0; min_interest = 992; for(i = 0; i < 3; i++) { chk_dir = (dir + 3 + i) % 4; if(status[chk_dir] == NOTHING) { possibles++; all_interest += interest_areas[chk_dir]; if(min_interest > interest_areas[chk_dir]) min_interest = interest_areas[chk_dir]; } } all_interest -= (min_interest * possibles) + possibles; for(i = 0; i < 4; i++) interest_areas[i] = interest_areas[i] - min_interest + 1; if(possibles == 0) { /* Only can move backward */ switch(me->direction) { case TD_UP: tank_move(me, TD_DOWN, tank_rt); break; case TD_RIGHT: tank_move(me, TD_LEFT, tank_rt); break; case TD_DOWN: tank_move(me, TD_UP, tank_rt); break; case TD_LEFT: tank_move(me, TD_RIGHT, tank_rt); break; } leave_pheromone(me->map_x, me->map_y); return; } if(all_interest == 0) /* all nearby places are occupied */ return; interest_dir = (rand() % all_interest) + 1; for(i = 0; i < 3; i++) { chk_dir = (dir + 3 + i) % 4; if(status[chk_dir] == NOTHING) { interest_dir -= interest_areas[chk_dir]; if(interest_dir <= 0) break; } } switch(chk_dir) { case 0: tank_move(me, TD_RIGHT, tank_rt); break; case 1: tank_move(me, TD_DOWN, tank_rt); break; case 2: tank_move(me, TD_LEFT, tank_rt); break; case 3: tank_move(me, TD_UP, tank_rt); break; } leave_pheromone(me->map_x, me->map_y); } static void _drive_enemy_tank(enemy_t *enemy) { tank_rt_t *tank_rt; tank_t *me, *tank1, *tank2; int r; tank_rt = enemy->tank_rt; tank1 = tank_rt->tank1; tank2 = tank_rt->tank2; me = enemy->tank; r = try_fire(me, tank1, tank_rt); if(r) return; r = try_fire(me, tank2, tank_rt); if(r) return; move_tank(enemy, tank_rt); } static enemy_t *enemies = NULL; static mb_timer_man_t *timer_man; static void enemy_tick(int hdl, const mb_timeval_t *tmo, const mb_timeval_t *now, void *data); /*! \brief Drive every enemy tanks. */ static void enemy_tank_driver(tank_rt_t *tank_rt) { enemy_t *enemy; int n_enemy; mb_timeval_t timeout, addend; int i; n_enemy = tank_rt->n_enemy; for(i = 0; i < n_enemy; i++) { enemy = enemies + i; if(enemy->tank->progm == NULL) _drive_enemy_tank(enemy); } get_now(&timeout); MB_TIMEVAL_SET(&addend, 0, 300000); MB_TIMEVAL_ADD(&timeout, &addend); mb_timer_man_timeout(timer_man, &timeout, enemy_tick, tank_rt); } static void enemy_tick(int hdl, const mb_timeval_t *tmo, const mb_timeval_t *now, void *data) { tank_rt_t *tank_rt = (tank_rt_t *)data; remove_pheromone(); enemy_tank_driver(tank_rt); } /*! \brief Start a timer for enemy tank driver. */ static void start_enemy_tank_timer(tank_rt_t *tank_rt) { mb_timeval_t timeout, addend; timer_man = mb_runtime_timer_man(tank_rt->mb_rt); get_now(&timeout); MB_TIMEVAL_SET(&addend, 0, 300000); MB_TIMEVAL_ADD(&timeout, &addend); mb_timer_man_timeout(timer_man, &timeout, enemy_tick, tank_rt); } void init_enemies(tank_rt_t *tank_rt) { int n_enemy; tank_t **tank_enemies; tank_t *tank; int i, j; n_enemy = tank_rt->n_enemy; tank_enemies = tank_rt->tank_enemies; enemies = (enemy_t *)malloc(sizeof(enemy_t) * n_enemy); for(i = 0; i < n_enemy; i++) { tank = tank_enemies[i]; enemies[i].tank_rt = tank_rt; enemies[i].tank = tank; for(j = 0; j < 4; j++) enemies[i].memory[j] = SOMETHING; } srand(time(NULL)); start_enemy_tank_timer(tank_rt); }