1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/time.h>
4 #include "PuyoIA.h"
5
6 #define UP 2
7 #define LEFT 1
8 #define DOWN 0
9 #define RIGHT 3
10
11
12 struct PosEvaluator {
13 int c_direction;
14 int f_x;
15 int score;
16 bool keep;
17
updatePosEvaluator18 int update(PuyoGame *game, PuyoState f_color, PuyoState c_color,
19 int IAPuyoValue,
20 int IASecondLevelPuyoValue,
21 int IAConstructorLevel,
22 int IAHeightAgressivity,
23 int IAHeightFactor, int myRand)
24 {
25 int f_y = 0;
26 int c_x = 0;
27 int c_y = 0;
28
29 if (f_color == PUYO_EMPTY) return 0;
30 if (c_color == PUYO_EMPTY) return 0;
31
32 /* Calcul de la posisition finale des deux puyos */
33 switch (c_direction) {
34 case UP:
35 f_y = game->getColumnHeigth(f_x);
36 c_x = f_x;
37 c_y = f_y + 1;
38 break;
39 case DOWN:
40 c_y = game->getColumnHeigth(f_x);
41 c_x = f_x;
42 f_y = c_y + 1;
43 break;
44 case RIGHT:
45 f_y = game->getColumnHeigth(f_x);
46 c_x = f_x + 1;
47 c_y = game->getColumnHeigth(f_x + 1);
48 break;
49 case LEFT:
50 f_y = game->getColumnHeigth(f_x);
51 c_x = f_x - 1;
52 c_y = game->getColumnHeigth(f_x - 1);
53 break;
54 }
55 f_y = PUYODIMY - f_y - 1;
56 c_y = PUYODIMY - c_y - 1;
57
58 /* Si l'un des deux puyos est tout en haut => pire cas ! */
59 if ((f_y < 0) || (c_y < 0))
60 {
61 score = -10000;
62 return score;
63 }
64
65 /* On favorise les cas ou on regroupe les couleurs ! */
66 score = (game->getSamePuyoAround(f_x, f_y, f_color) + game->getSamePuyoAround(c_x, c_y, c_color) )*IAPuyoValue;
67
68 /* On favorise les cas ou on ne separe pas deux puyos de couleurs identiques qui tombent ! */
69 if ( (f_color == c_color) && ( (c_x==f_x) || (c_y==f_y) ) ) score += IAPuyoValue;
70
71 /* Si l'un des deux puyos est vraiment tres haut => vraiment pas bien ! */
72 if ((f_y < 2) || (c_y < 2)) score -= 1000;
73
74 /* Si les deux puyos sont suffisament bas => mode attaque ! */
75 if ((f_y >= IAHeightAgressivity) && (c_y >= IAHeightAgressivity))
76 {
77 /* On va defavoriser les cas ou on fait des trops petites constructions : */
78 PuyoState aboveStateF, aboveStateC;
79 bool F,C;
80
81 /* Main puyo may only make a block of 4 */
82 aboveStateF = (c_direction == UP) ? c_color : PUYO_EMPTY;
83 F = ((game->getSamePuyoAround(f_x, f_y, f_color) + ((aboveStateF == f_color)?1:0)) == 4);
84
85 /* Companion puyo may only make a block of 4 */
86 aboveStateC = (c_direction == DOWN) ? f_color : PUYO_EMPTY;
87 C = ((game->getSamePuyoAround(c_x, c_y, c_color) + ((aboveStateC == c_color)?1:0)) == 4);
88
89 if ((F || C) && !(F && C))
90 {
91 score -= IAConstructorLevel*IAPuyoValue;
92 /* fprintf(stderr,"--o--"); */
93 }
94 }
95
96 /* On favorise les cas ou les puyos sont envoyes le plus bas possible */
97 score += (f_y+c_y)*IAHeightFactor;
98
99 /* On favorise les regroupements verticaux apres demolition : */
100
101 /* xx2 */
102 /* xx3 Favoriser le cas ou on pose un '3' au milieu pour que les '2' se groupent apres destruction du '3' */
103 /* 152 */
104
105 /* xx2 */
106 /* x43 Favoriser aussi un peu le cas ou on pose un '5' sur le '4' */
107 /* 152 */
108
109 /* Puyo companion */
110 if (c_y < PUYODIMY-1) /* Si on est pas completement en bas */
111 {
112 if ((c_x<(PUYODIMX - 1)) && (c_color == (game->getPuyoAt(c_x+1,c_y))->getPuyoState())) /* Test du pattern a droite */
113 {
114 PuyoState cColorA = (game->getPuyoAt(c_x+1,c_y+1))->getPuyoState();
115 if ((c_color!=cColorA) && (cColorA>5) && (cColorA<11) && (cColorA == (game->getPuyoAt(c_x+1,c_y-1))->getPuyoState()))
116 {
117 score += game->getSamePuyoAround(c_x+1, c_y, cColorA)*IASecondLevelPuyoValue;
118 }
119 }
120
121 if ((c_x>0) && (c_color == (game->getPuyoAt(c_x-1,c_y))->getPuyoState())) /* Test du pattern a gauche */
122 {
123 PuyoState cColorB = (game->getPuyoAt(c_x-1,c_y+1))->getPuyoState();
124 if ((c_color!=cColorB) && (cColorB>5) && (cColorB<11) && (cColorB == (game->getPuyoAt(c_x-1,c_y-1))->getPuyoState()))
125 {
126 score += game->getSamePuyoAround(c_x-1, c_y, cColorB)*IASecondLevelPuyoValue;
127 }
128 }
129 }
130 if (c_y < PUYODIMY-2) /* Si on est pas trop en bas */
131 {
132 if (c_color == (game->getPuyoAt(c_x,c_y+2))->getPuyoState())
133 {
134 score += game->getSamePuyoAround(c_x, c_y+2, c_color)*IASecondLevelPuyoValue;
135 }
136 }
137
138 /* Puyo principal */
139 if (f_y < PUYODIMY-1) /* Si on est pas completement en bas */
140 {
141 if ((f_x<(PUYODIMX - 1)) && (f_color == (game->getPuyoAt(f_x+1,f_y))->getPuyoState())) /* Test du pattern a droite */
142 {
143 PuyoState fColorA = (game->getPuyoAt(f_x+1,f_y+1))->getPuyoState();
144 if ((f_color!=fColorA) && (fColorA>5) && (fColorA<11) && (fColorA == (game->getPuyoAt(f_x+1,f_y-1))->getPuyoState()))
145 {
146 score += game->getSamePuyoAround(f_x+1, f_y, fColorA)*IASecondLevelPuyoValue;
147 }
148 }
149
150 if ((f_x>0) && (f_color == (game->getPuyoAt(f_x-1,f_y))->getPuyoState())) /* Test du pattern a gauche */
151 {
152 PuyoState fColorB = (game->getPuyoAt(f_x-1,f_y+1))->getPuyoState();
153 if ((f_color!=fColorB) && (fColorB>5) && (fColorB<11) && (fColorB == (game->getPuyoAt(f_x-1,f_y-1))->getPuyoState()))
154 {
155 score += game->getSamePuyoAround(f_x-1, f_y, fColorB)*IASecondLevelPuyoValue;
156 }
157 }
158 }
159 if (f_y < PUYODIMY-2) /* Si on est pas trop en bas */
160 {
161 if (f_color == (game->getPuyoAt(f_x,f_y+2))->getPuyoState())
162 {
163 score += game->getSamePuyoAround(f_x, f_y+2, f_color)*IASecondLevelPuyoValue;
164 }
165 }
166
167 score += myRand;
168 return score;
169 }
170
initPosEvaluator171 void init(int col, int dir)
172 {
173 f_x = col;
174 c_direction = dir;
175 }
176
PosEvaluatorPosEvaluator177 PosEvaluator() { f_x = c_direction = 0; }
178
179 };
180
PuyoIA(IA_Type type,int level,PuyoView * targetView)181 PuyoIA::PuyoIA(IA_Type type, int level, PuyoView *targetView)
182 : PuyoPlayer(targetView), type(type), level(level)
183 {
184 attachedGame = targetView->getAttachedGame();
185 evaluator = new PosEvaluator[PUYODIMX * 4 - 2];
186 int iEval = 0;
187 for (int col=0; col<PUYODIMX; ++col) {
188 if (col != 0)
189 evaluator[iEval++].init(col, LEFT);
190 if (col != PUYODIMX - 1)
191 evaluator[iEval++].init(col, RIGHT);
192 evaluator[iEval++].init(col, UP);
193 evaluator[iEval++].init(col, DOWN);
194 }
195 choosenMove = -1;
196 firstLine = false;
197 }
198
extractColor(PuyoState A) const199 PuyoState PuyoIA::extractColor(PuyoState A) const
200 {
201 switch (A) {
202 case PUYO_FALLINGBLUE:
203 return PUYO_BLUE;
204 case PUYO_FALLINGRED:
205 return PUYO_RED;
206 case PUYO_FALLINGGREEN:
207 return PUYO_GREEN;
208 case PUYO_FALLINGVIOLET:
209 return PUYO_VIOLET;
210 case PUYO_FALLINGYELLOW:
211 return PUYO_YELLOW;
212 default:
213 return A;
214 }
215 }
216
cycle()217 void PuyoIA::cycle()
218 {
219 int IAPuyoValue = 100;
220 int IASecondLevelPuyoValue = 30;
221 int IAConstructorLevel = 3;
222 int IAHeightAgressivity = 6;
223 int IAHeightFactor = 2;
224
225 switch (type) {
226 case GYOM:
227 break;
228 case TANIA:
229 IAConstructorLevel = 1;
230 IAHeightAgressivity = 9;
231 break;
232 case JEKO:
233 IAConstructorLevel = 1;
234 IAHeightAgressivity = 3;
235 IAHeightFactor = 1;
236 break;
237 case FLOBO:
238 IAConstructorLevel = 0;
239 IAHeightAgressivity = 0xffff; // Inhibits agressivity.
240 IAHeightFactor = 0;
241 IAPuyoValue = 50;
242 IASecondLevelPuyoValue = 0;
243 break;
244 default:
245 break;
246 }
247
248 switch (type) {
249
250 case RANDOM:
251 switch (random() % 50) {
252 case 0:
253 attachedView->rotateLeft();
254 break;
255 case 1:
256 attachedView->moveLeft();
257 break;
258 case 2:
259 attachedView->moveRight();
260 break;
261 default:
262 break;
263 }
264 break;
265
266 default:
267 {
268 if (!firstLine && (attachedGame->getFallingY() == 1) && (choosenMove != -1))
269 choosenMove = -1;
270 firstLine = (attachedGame->getFallingY() == 1);
271 if ((choosenMove >= 0) && (random() % level < 10))
272 {
273 if (attachedGame->getFallingCompanionDir() != evaluator[choosenMove].c_direction)
274 attachedView->rotateLeft();
275 else if (attachedGame->getFallingX() < evaluator[choosenMove].f_x)
276 attachedView->moveRight();
277 else if (attachedGame->getFallingX() > evaluator[choosenMove].f_x)
278 attachedView->moveLeft();
279 else
280 attachedView->cycleGame();
281 }
282 else if (choosenMove == -1)
283 {
284 PuyoState f_color = extractColor(attachedGame->getFallingState());
285 PuyoState c_color = extractColor(attachedGame->getCompanionState());
286 int max = -100000;
287 for (int i=PUYODIMX*4-3; i>=0; --i)
288 {
289 if ((f_color == PUYO_EMPTY)||(c_color==PUYO_EMPTY)) return;
290 int myRand = 0;
291
292 if (type == FLOBO) {
293 myRand = (int) ((double)IAPuyoValue*2*(double)random()/(RAND_MAX+1.0));
294 }
295 else if (type == JEKO) {
296 myRand = (int) ((double)IAPuyoValue*(double)random()/(RAND_MAX+1.0)/2.0);
297 }
298
299
300 /* IAPuyoValue / IASecondLevelPuyoValue / IAConstructorLevel / IAHeightAgressivity / IAHeightFactor */
301 int val = evaluator[i].update(attachedGame, f_color, c_color,
302 IAPuyoValue, IASecondLevelPuyoValue, IAConstructorLevel, IAHeightAgressivity, IAHeightFactor,
303 myRand);
304
305 if (val >= max) max = val;
306 }
307
308 int nbKeep = 0;
309 for (int i=PUYODIMX*4-3; i>=0; --i)
310 {
311 if (evaluator[i].score == max) {
312 nbKeep ++;
313 evaluator[i].keep = true;
314 }
315 else evaluator[i].keep = false;
316 }
317
318 if (nbKeep > 0) {
319 int tmp = 1 + ((random() / 7) % nbKeep);
320
321 for (int i=PUYODIMX*4-3; i>=0; --i)
322 {
323 if (evaluator[i].keep)
324 {
325 if (tmp == 1)
326 {
327 /*fprintf(stderr,"\nchoice : %d/%d (%d)\n",i,nbKeep,evaluator[i].score);*/
328 choosenMove = i;
329 break;
330 }
331 tmp--;
332 }
333 }
334 }
335 }
336 }
337 }
338 }
339