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