Mercurial > MadButterfly
annotate examples/tank/enemy.c @ 1103:2b8b6deb35c8
Fix bug of AI of tank
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Sun, 05 Dec 2010 14:26:19 +0800 |
parents | dbea3e42bf93 |
children | 236a47079c2b |
rev | line source |
---|---|
1100 | 1 #include <stdio.h> |
1102
dbea3e42bf93
Initial random number generator for tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1100
diff
changeset
|
2 #include <time.h> |
1100 | 3 #include <stdlib.h> |
4 #include <string.h> | |
5 #include "tank.h" | |
6 | |
7 struct _enemy { | |
8 tank_rt_t *tank_rt; | |
9 tank_t *tank; | |
10 int memory[4]; | |
11 }; | |
12 typedef struct _enemy enemy_t; | |
13 | |
14 /* \brief Fire and move to the target tank if they are in a row or column. | |
15 */ | |
16 static int | |
17 try_fire(tank_t *me, tank_t *target, tank_rt_t *tank_rt) { | |
18 int x, y; | |
19 int *tracer = NULL; | |
20 int target_value; | |
21 int target_dir; | |
1103
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
22 tank_t **enemies; |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
23 int i; |
1100 | 24 |
25 if(me->map_x == target->map_x) { /* In a row */ | |
26 tracer = &y; | |
27 target_value = target->map_y; | |
28 if(me->map_y < target->map_y) | |
29 target_dir = TD_DOWN; | |
30 else | |
31 target_dir = TD_UP; | |
32 } | |
33 if(me->map_y == target->map_y) { /* In a column */ | |
34 tracer = &x; | |
35 target_value = target->map_x; | |
36 if(me->map_x < target->map_x) | |
37 target_dir = TD_RIGHT; | |
38 else | |
39 target_dir = TD_LEFT; | |
40 } | |
41 | |
42 if(tracer == NULL) | |
43 return 0; /* Not in a row or column */ | |
44 | |
45 /* Check obstacles between tanks */ | |
46 x = me->map_x; | |
47 y = me->map_y; | |
1103
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
48 enemies = tank_rt->tank_enemies; |
1100 | 49 if(*tracer < target_value) { |
50 while(++*tracer < target_value) { | |
51 if(map[y][x] != MUD) | |
52 break; | |
1103
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
53 for(i = 0; i < tank_rt->n_enemy; i++) { |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
54 if(enemies[i]->map_x == x && enemies[i]->map_y == y) |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
55 break; |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
56 } |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
57 if(i != tank_rt->n_enemy) |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
58 break; |
1100 | 59 } |
60 } else { | |
61 while(--*tracer > target_value) { | |
62 if(map[y][x] != MUD) | |
63 break; | |
1103
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
64 for(i = 0; i < tank_rt->n_enemy; i++) { |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
65 if(enemies[i]->map_x == x && enemies[i]->map_y == y) |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
66 break; |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
67 } |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
68 if(i != tank_rt->n_enemy) |
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
69 break; |
1100 | 70 } |
71 } | |
72 | |
73 if(*tracer == target_value) { /* No any obstacle between tanks */ | |
74 /* Fire and move to target */ | |
75 if(me->direction == target_dir && me->bullet == NULL) | |
76 tank_fire_bullet(tank_rt, me); | |
77 tank_move(me, target_dir, tank_rt); | |
78 return 1; | |
79 } | |
80 | |
81 return 0; /* Find one or more obstacles */ | |
82 } | |
83 | |
84 #define NOTHING 0 | |
85 #define SOMETHING 1 | |
86 | |
87 static void | |
88 move_tank(enemy_t *enemy, tank_rt_t *tank_rt) { | |
89 tank_t *me; | |
90 tank_t **tanks, *tank; | |
91 static const int shift_xy[4][2] = { | |
92 {1, 0}, {0, 1}, | |
93 {-1, 0}, {0, -1}}; | |
94 int status[4]; | |
95 int x, y; | |
96 int i, tank_i; | |
97 int dir, chk_dir; | |
98 int possibles; | |
99 int which_dir; | |
100 | |
101 me = enemy->tank; | |
102 tanks = tank_rt->tanks; | |
103 | |
104 /* Collect status */ | |
105 for(i = 0; i < 4; i++) { | |
106 x = me->map_x + shift_xy[i][0]; | |
107 y = me->map_y + shift_xy[i][1]; | |
108 | |
109 /* Check obstacles */ | |
110 if(x == -1 || y == -1 || x >= MAP_W || y >= MAP_H) { | |
111 /* Out of range */ | |
112 status[i] = SOMETHING; | |
113 continue; | |
114 } | |
115 if(map[y][x] == MUD) | |
116 status[i] = NOTHING; | |
117 else | |
118 status[i] = SOMETHING; | |
119 | |
120 /* Check tanks */ | |
121 for(tank_i = 0; tank_i < tank_rt->n_tanks; tank_i++) { | |
122 tank = tanks[tank_i]; | |
123 if(tank->map_x == x && tank->map_y == y) { | |
124 status[i] = SOMETHING; | |
125 break; | |
126 } | |
127 } | |
128 } | |
129 | |
130 /* Try the same direction if status is not changed. */ | |
131 for(i = 0; i < 4; i++) { | |
132 if(status[i] != enemy->memory[i]) | |
133 break; | |
134 } | |
135 if(i == 4) { /* Status is not changed */ | |
136 tank_move(me, me->direction, tank_rt); | |
137 return; | |
138 } | |
139 | |
140 memcpy(enemy->memory, status, sizeof(int) * 4); | |
141 | |
142 /* Check possible directions except backward. */ | |
143 switch(me->direction) { | |
144 case TD_UP: | |
145 dir = 3; | |
146 break; | |
147 case TD_RIGHT: | |
148 dir = 0; | |
149 break; | |
150 case TD_DOWN: | |
151 dir = 1; | |
152 break; | |
153 case TD_LEFT: | |
154 dir = 2; | |
155 break; | |
156 } | |
157 | |
158 possibles = 0; | |
159 for(i = 0; i < 3; i++) { | |
1103
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
160 chk_dir = (dir + 3 + i) % 4; |
1100 | 161 if(status[chk_dir] == NOTHING) |
162 possibles++; | |
163 } | |
164 | |
165 if(possibles == 0) { /* Only can move backward */ | |
166 switch(me->direction) { | |
167 case TD_UP: | |
168 tank_move(me, TD_DOWN, tank_rt); | |
169 break; | |
170 case TD_RIGHT: | |
171 tank_move(me, TD_LEFT, tank_rt); | |
172 break; | |
173 case TD_DOWN: | |
174 tank_move(me, TD_UP, tank_rt); | |
175 break; | |
176 case TD_LEFT: | |
177 tank_move(me, TD_RIGHT, tank_rt); | |
178 break; | |
179 } | |
180 return; | |
181 } | |
182 | |
1103
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
183 which_dir = (rand() % possibles) + 1; |
1100 | 184 for(i = 0; i < 3; i++) { |
1103
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
185 chk_dir = (dir + 3 + i) % 4; |
1100 | 186 if(status[chk_dir] == NOTHING) { |
1103
2b8b6deb35c8
Fix bug of AI of tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1102
diff
changeset
|
187 which_dir--; |
1100 | 188 if(which_dir == 0) |
189 break; | |
190 } | |
191 } | |
192 switch(chk_dir) { | |
193 case 0: | |
194 tank_move(me, TD_RIGHT, tank_rt); | |
195 break; | |
196 case 1: | |
197 tank_move(me, TD_DOWN, tank_rt); | |
198 break; | |
199 case 2: | |
200 tank_move(me, TD_LEFT, tank_rt); | |
201 break; | |
202 case 3: | |
203 tank_move(me, TD_UP, tank_rt); | |
204 break; | |
205 } | |
206 } | |
207 | |
208 static void | |
209 _drive_enemy_tank(enemy_t *enemy) { | |
210 tank_rt_t *tank_rt; | |
211 tank_t *me, *tank1, *tank2; | |
212 int r; | |
213 | |
214 tank_rt = enemy->tank_rt; | |
215 tank1 = tank_rt->tank1; | |
216 tank2 = tank_rt->tank2; | |
217 me = enemy->tank; | |
218 | |
219 r = try_fire(me, tank1, tank_rt); | |
220 if(r) | |
221 return; | |
222 r = try_fire(me, tank2, tank_rt); | |
223 if(r) | |
224 return; | |
225 | |
226 move_tank(enemy, tank_rt); | |
227 } | |
228 | |
229 static enemy_t *enemies = NULL; | |
230 static mb_timer_man_t *timer_man; | |
231 | |
232 /*! \brief Drive every enemy tanks. | |
233 */ | |
234 static void | |
235 enemy_tank_driver(int hdl, const mb_timeval_t *tmo, | |
236 const mb_timeval_t *now, void *data) { | |
237 tank_rt_t *tank_rt = (tank_rt_t *)data; | |
1102
dbea3e42bf93
Initial random number generator for tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1100
diff
changeset
|
238 enemy_t *enemy; |
1100 | 239 int n_enemy; |
240 mb_timeval_t timeout, addend; | |
241 int i; | |
242 | |
243 n_enemy = tank_rt->n_enemy; | |
244 for(i = 0; i < n_enemy; i++) { | |
1102
dbea3e42bf93
Initial random number generator for tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1100
diff
changeset
|
245 enemy = enemies + i; |
dbea3e42bf93
Initial random number generator for tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1100
diff
changeset
|
246 if(enemy->tank->progm == NULL) |
dbea3e42bf93
Initial random number generator for tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1100
diff
changeset
|
247 _drive_enemy_tank(enemy); |
1100 | 248 } |
249 | |
250 get_now(&timeout); | |
251 MB_TIMEVAL_SET(&addend, 0, 300000); | |
252 MB_TIMEVAL_ADD(&timeout, &addend); | |
253 mb_timer_man_timeout(timer_man, &timeout, enemy_tank_driver, tank_rt); | |
254 } | |
255 | |
256 /*! \brief Start a timer for enemy tank driver. | |
257 */ | |
258 static void | |
259 start_enemy_tank_timer(tank_rt_t *tank_rt) { | |
260 mb_timeval_t timeout, addend; | |
261 | |
262 timer_man = mb_runtime_timer_man(tank_rt->mb_rt); | |
263 | |
264 get_now(&timeout); | |
265 MB_TIMEVAL_SET(&addend, 0, 300000); | |
266 MB_TIMEVAL_ADD(&timeout, &addend); | |
267 mb_timer_man_timeout(timer_man, &timeout, enemy_tank_driver, tank_rt); | |
268 } | |
269 | |
270 void | |
271 init_enemies(tank_rt_t *tank_rt) { | |
272 int n_enemy; | |
273 tank_t **tank_enemies; | |
274 tank_t *tank; | |
275 int i, j; | |
276 | |
277 n_enemy = tank_rt->n_enemy; | |
278 tank_enemies = tank_rt->tank_enemies; | |
279 | |
280 enemies = (enemy_t *)malloc(sizeof(enemy_t) * n_enemy); | |
281 | |
282 for(i = 0; i < n_enemy; i++) { | |
283 tank = tank_enemies[i]; | |
284 enemies[i].tank_rt = tank_rt; | |
285 enemies[i].tank = tank; | |
286 for(j = 0; j < 4; j++) | |
287 enemies[i].memory[j] = SOMETHING; | |
288 } | |
289 | |
1102
dbea3e42bf93
Initial random number generator for tank
Thinker K.F. Li <thinker@codemud.net>
parents:
1100
diff
changeset
|
290 srand(time(NULL)); |
1100 | 291 start_enemy_tank_timer(tank_rt); |
292 } |