# HG changeset patch # User Thinker K.F. Li # Date 1291523009 -28800 # Node ID fb79175e6cc34fa269961f81b2f603c14efebeb8 # Parent c18ad321844dcb09ea97c59f1a05dc71379a2152 Add AI for enemy tanks diff -r c18ad321844d -r fb79175e6cc3 examples/tank/Makefile.am --- a/examples/tank/Makefile.am Sat Dec 04 16:22:11 2010 +0800 +++ b/examples/tank/Makefile.am Sun Dec 05 12:23:29 2010 +0800 @@ -4,7 +4,7 @@ #EXTRA_DIST = svg_sources = brick.c bullet.c bush.c mud.c rock.c \ tank1.c tank2.c tank_en.c bang.c -tank_SOURCES = tank_main.c +tank_SOURCES = tank_main.c enemy.c nodist_tank_SOURCES = svgs.h \ $(svg_sources) $(svg_sources:.c=.h) $(svg_sources:.c=.mb) tank_CPPFLAGS = $(APPCFLAGS) diff -r c18ad321844d -r fb79175e6cc3 examples/tank/enemy.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/tank/enemy.c Sun Dec 05 12:23:29 2010 +0800 @@ -0,0 +1,272 @@ +#include +#include +#include +#include "tank.h" + +struct _enemy { + tank_rt_t *tank_rt; + tank_t *tank; + int memory[4]; +}; +typedef struct _enemy enemy_t; + +/* \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; + + 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; + if(*tracer < target_value) { + while(++*tracer < target_value) { + if(map[y][x] != MUD) + break; + } + } else { + while(--*tracer > target_value) { + if(map[y][x] != MUD) + 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); + 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 possibles; + int which_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]; + + /* 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; + 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); + 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; + } + + possibles = 0; + for(i = 0; i < 3; i++) { + chk_dir = (dir - 1 + i) % 4; + if(status[chk_dir] == NOTHING) + possibles++; + } + + 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; + } + return; + } + + which_dir = rand() % possibles; + for(i = 0; i < 3; i++) { + chk_dir = (dir - 1 + i) % 4; + if(status[chk_dir] == NOTHING) { + if(which_dir == 0) + break; + which_dir--; + } + } + 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; + } +} + +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; + +/*! \brief Drive every enemy tanks. + */ +static void +enemy_tank_driver(int hdl, const mb_timeval_t *tmo, + const mb_timeval_t *now, void *data) { + tank_rt_t *tank_rt = (tank_rt_t *)data; + int n_enemy; + mb_timeval_t timeout, addend; + int i; + + n_enemy = tank_rt->n_enemy; + for(i = 0; i < n_enemy; i++) { + _drive_enemy_tank(enemies + i); + } + + get_now(&timeout); + MB_TIMEVAL_SET(&addend, 0, 300000); + MB_TIMEVAL_ADD(&timeout, &addend); + mb_timer_man_timeout(timer_man, &timeout, 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_tank_driver, 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; + } + + start_enemy_tank_timer(tank_rt); +} diff -r c18ad321844d -r fb79175e6cc3 examples/tank/tank.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/tank/tank.h Sun Dec 05 12:23:29 2010 +0800 @@ -0,0 +1,99 @@ +#ifndef __TANK_H_ +#define __TANK_H_ + +#include +#include "svgs.h" + +/*! \ingroup tank + * @{ + */ +/*! \brief Tile types in a map. */ +enum { MUD, ROC, BRI, BSH }; + +/*! \brief Map of the game. */ +extern char map[12][16]; + +#define MAP_W 16 +#define MAP_H 12 +/* @} */ + +/*! \defgroup bullet_elf Bullet Elf + * \ingroup tank + * @{ + */ +/*! \brief Information about bullet elf + */ +struct _tank_bullet { + redraw_man_t *rdman; + coord_t *coord_pos; + coord_t *coord_rot; + bullet_t *bullet_obj; + int start_map_x, start_map_y; + int direction; + mb_progm_t *progm; + mb_timeval_t start_time; + observer_t *observer_redraw; + int hit_tmr; + mb_timer_man_t *timer_man; +}; +typedef struct _tank_bullet tank_bullet_t; +/*! \brief The direction a bullet is going. + */ +enum { BU_UP = 0, BU_RIGHT, BU_DOWN, BU_LEFT }; +/* @} */ + +/*! \defgroup tank_elf Tank Elf + * \brief Tank elf module provides control functions of tanks in game. + * \ingroup tank + * @{ + */ +/*! \brief Information about a tank elf. */ +struct _tank { + coord_t *coord_pos; /*!< \brief coordinate for position */ + coord_t *coord_rot; /*!< \brief coordinate for rotation */ + coord_t *coord_center; + int map_x, map_y; + int direction; + mb_progm_t *progm; + tank_bullet_t *bullet; + struct _tank_rt *tank_rt; /*!< \brief for bullet to check + * hitting on tanks. + */ +}; +typedef struct _tank tank_t; +enum { TD_UP = 0, TD_RIGHT, TD_DOWN, TD_LEFT }; + +/* @} */ + +/* + * \ingroup tank + * @{ + */ +typedef struct _tank_rt tank_rt_t; + +/*! \brief Runtime information for tank, this game/example. + */ +struct _tank_rt { + tank_t *tank1; + tank1_t *tank1_o; + tank_t *tank2; + tank2_t *tank2_o; + int n_enemy; + tank_t *tank_enemies[10]; + tank_en_t *tank_enemies_o[10]; + tank_t *tanks[12]; + int n_tanks; + void *map[12][16]; + mb_rt_t *mb_rt; + observer_t *kb_observer; +}; + +extern void tank_move(tank_t *tank, int direction, tank_rt_t *tank_rt); +extern void tank_fire_bullet(tank_rt_t *tank_rt, tank_t *tank); + +/* From enemy.c */ +extern void init_enemies(tank_rt_t *tank_rt); + +/* @} */ + +#endif /* __TANK_H_ */ diff -r c18ad321844d -r fb79175e6cc3 examples/tank/tank_main.c --- a/examples/tank/tank_main.c Sat Dec 04 16:22:11 2010 +0800 +++ b/examples/tank/tank_main.c Sun Dec 05 12:23:29 2010 +0800 @@ -3,16 +3,13 @@ #include #include #include +#include "tank.h" #include "svgs.h" /*! \defgroup tank Example Tank * @{ */ -/*! \brief Tile types in a map. */ -enum { MUD, ROC, BRI, BSH }; - -/*! \brief Map of the game. */ -static char map[12][16] = { +char map[12][16] = { { MUD, MUD, MUD, MUD, MUD, MUD, MUD, MUD, MUD, MUD, MUD, MUD, MUD, MUD, MUD, MUD}, { MUD, ROC, ROC, ROC, MUD, BSH, BSH, ROC, @@ -38,78 +35,8 @@ { MUD, MUD, MUD, MUD, MUD, MUD, BRI, MUD, MUD, BRI, MUD, BRI, MUD, MUD, MUD, MUD} }; - -#define MAP_W 16 -#define MAP_H 12 /* @} */ -/*! \defgroup bullet_elf Bullet Elf - * \ingroup tank - * @{ - */ -/*! \brief Information about bullet elf - */ -struct _tank_bullet { - redraw_man_t *rdman; - coord_t *coord_pos; - coord_t *coord_rot; - bullet_t *bullet_obj; - int start_map_x, start_map_y; - int direction; - mb_progm_t *progm; - mb_timeval_t start_time; - observer_t *observer_redraw; - int hit_tmr; - mb_timer_man_t *timer_man; -}; -typedef struct _tank_bullet tank_bullet_t; -/*! \brief The direction a bullet is going. - */ -enum { BU_UP = 0, BU_RIGHT, BU_DOWN, BU_LEFT }; -/* @} */ - -/*! \defgroup tank_elf Tank Elf - * \brief Tank elf module provides control functions of tanks in game. - * \ingroup tank - * @{ - */ -/*! \brief Information about a tank elf. */ -struct _tank { - coord_t *coord_pos; /*!< \brief coordinate for position */ - coord_t *coord_rot; /*!< \brief coordinate for rotation */ - coord_t *coord_center; - int map_x, map_y; - int direction; - mb_progm_t *progm; - tank_bullet_t *bullet; - struct _tank_rt *tank_rt; /*!< \brief for bullet to check - * hitting on tanks. - */ -}; -typedef struct _tank tank_t; -enum { TD_UP = 0, TD_RIGHT, TD_DOWN, TD_LEFT }; - -/* @} */ - -typedef struct _tank_rt tank_rt_t; - -/*! \brief Runtime information for tank, this game/example. - */ -struct _tank_rt { - tank_t *tank1; - tank1_t *tank1_o; - tank_t *tank2; - tank2_t *tank2_o; - int n_enemy; - tank_t *tank_enemies[10]; - tank_en_t *tank_enemies_o[10]; - tank_t *tanks[12]; - int n_tanks; - void *map[12][16]; - mb_rt_t *mb_rt; - observer_t *kb_observer; -}; - /*! \ingroup tank_elf * @{ */ @@ -165,8 +92,8 @@ #define PI 3.1415926 -static void tank_move(tank_t *tank, int direction, - tank_rt_t *tank_rt) { +void +tank_move(tank_t *tank, int direction, tank_rt_t *tank_rt) { mb_rt_t *mb_rt = tank_rt->mb_rt; redraw_man_t *rdman; mb_timer_man_t *timer_man; @@ -488,7 +415,8 @@ } /*! \brief To fire a bullet for a tank. */ -static void tank_fire_bullet(tank_rt_t *tank_rt, tank_t *tank) { +void +tank_fire_bullet(tank_rt_t *tank_rt, tank_t *tank) { mb_rt_t *mb_rt; redraw_man_t *rdman; int map_x, map_y; @@ -738,6 +666,8 @@ initial_tank(&tank_rt, rt); + /* init_enemies(&tank_rt); */ + mb_runtime_event_loop(rt); mb_runtime_free(rt);