Homine Ludens / YATTT

Dependencies:   PokittoLib mbed-src

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "Pokitto.h"
00002 
00003 #define CELL_SIZE 32
00004 #define SIGN_SIZE 20
00005 #define CURSOR_SIZE 36
00006 
00007 #define MAX_GRID_SIZE 10
00008 
00009 #define MAX_PLAYERS 4
00010 #define MAX_MENU_SETTINGS 7
00011 
00012 #define PI2 PI/2.0
00013 #define PI4 PI/4.0
00014 #define PI3_4 PI*3.0/4.0
00015 
00016 const uint8_t logo[] = {
00017     188,38,
00018     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00019     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00020     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00021     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00022     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00023     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00024     0,0,0,0,0,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00025     0,0,0,0,0,0,21,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00026     0,0,0,0,0,0,21,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00027     0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00028     0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,
00029     0,1,85,85,85,64,0,0,0,0,0,0,0,0,0,0,85,85,85,80,1,0,0,0,0,0,0,0,0,0,0,0,1,85,85,85,64,0,0,0,0,0,0,0,0,0,0,
00030     0,5,85,85,85,0,85,0,0,5,85,80,0,0,0,1,85,85,85,64,21,64,0,0,0,0,21,85,64,0,0,0,5,85,85,85,0,21,85,0,0,0,5,85,0,0,0,
00031     0,21,85,85,64,1,85,0,0,21,85,84,0,0,0,5,85,85,80,0,85,80,0,0,0,1,85,85,64,0,0,0,21,85,85,64,0,85,85,80,0,0,85,85,64,0,0,
00032     0,80,5,80,0,0,85,0,1,80,5,84,0,0,0,20,1,84,0,0,5,84,0,0,0,5,64,85,64,0,0,0,80,5,80,0,1,85,85,84,0,1,80,21,80,0,0,
00033     0,0,5,64,0,0,21,0,1,64,0,0,0,0,0,0,1,80,0,0,1,85,0,0,0,20,0,0,0,0,0,0,0,5,64,0,5,64,5,85,0,5,64,5,80,0,0,
00034     0,0,5,64,0,0,21,0,5,0,0,0,0,0,0,0,1,80,0,0,0,85,64,0,0,84,0,0,0,0,0,0,0,5,64,0,5,0,0,85,64,21,0,5,64,0,0,
00035     0,0,5,64,0,0,21,0,21,0,0,0,0,0,0,0,1,80,0,0,0,21,80,0,0,84,0,0,0,0,0,0,0,5,64,0,21,0,0,21,80,20,0,85,85,84,0,
00036     0,0,5,64,0,0,21,0,21,0,0,0,0,0,0,0,1,80,0,0,0,21,80,0,0,80,0,0,0,0,0,0,0,5,64,0,21,0,0,5,80,85,85,85,85,80,0,
00037     0,0,5,64,0,0,21,0,21,0,0,0,0,0,0,0,1,80,0,0,0,85,84,0,1,80,0,0,0,0,0,0,0,5,64,0,21,0,0,5,80,85,85,85,85,64,0,
00038     0,0,5,64,0,0,21,0,21,0,0,0,0,0,0,0,1,80,0,0,1,65,85,0,1,80,0,0,0,0,0,0,0,5,64,0,21,0,0,1,80,84,0,0,0,0,0,
00039     0,0,5,64,0,0,21,0,21,0,0,0,0,0,0,0,1,80,0,0,21,0,85,64,1,84,0,0,0,0,0,0,0,5,64,0,21,64,0,1,64,84,0,0,0,0,0,
00040     0,0,5,64,0,0,21,0,21,0,0,0,0,0,0,0,1,80,0,0,21,0,21,80,1,84,0,0,0,0,0,0,0,5,64,0,21,64,0,1,64,85,0,0,0,0,0,
00041     0,0,5,64,0,0,21,0,21,64,0,5,0,0,0,0,1,80,0,0,21,0,21,84,0,85,0,0,16,0,0,0,0,5,64,0,21,80,0,5,0,85,64,0,0,0,0,
00042     0,0,5,65,0,0,21,0,21,80,0,85,0,0,0,0,1,80,64,0,21,64,85,85,0,85,64,1,80,0,0,0,0,5,65,0,5,85,64,20,0,21,80,0,0,0,0,
00043     0,0,5,85,0,0,21,84,5,85,85,84,0,0,0,0,1,85,64,0,21,85,81,85,64,85,85,85,80,0,0,0,0,5,85,0,1,85,85,80,0,21,85,85,64,0,0,
00044     0,0,5,84,0,0,21,80,1,85,85,80,0,0,0,0,1,85,0,0,5,85,0,85,0,21,85,85,0,0,0,0,0,5,84,0,0,85,85,64,0,1,85,85,0,0,0,
00045     0,0,1,80,0,0,21,64,0,21,85,0,0,0,0,0,0,84,0,0,1,80,0,16,0,1,85,80,0,0,0,0,0,1,80,0,0,5,84,0,0,0,85,80,0,0,0,
00046     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00047     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00048     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00049     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00050     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00051     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00052     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00053     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00054     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00055     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00056 };
00057 
00058 
00059 const uint8_t AI_logo[] = {
00060     20,14,
00061     0,0,0,0,0,
00062     0,85,85,85,0,
00063     1,85,85,85,64,
00064     1,0,0,0,64,
00065     1,0,0,0,64,
00066     1,1,65,64,64,
00067     1,1,65,64,64,
00068     1,0,0,0,64,
00069     1,0,0,0,64,
00070     1,0,85,0,64,
00071     1,0,20,0,64,
00072     1,0,0,0,64,
00073     1,0,0,0,64,
00074     1,85,85,85,64,
00075 };
00076 
00077 
00078 const uint8_t P_logo[] = {
00079     20,14,
00080     0,0,85,0,0,
00081     0,1,85,64,0,
00082     0,1,85,64,0,
00083     0,1,20,64,0,
00084     0,5,85,80,0,
00085     0,5,85,80,0,
00086     0,1,20,64,0,
00087     0,1,65,64,0,
00088     0,0,85,0,0,
00089     0,0,20,0,0,
00090     0,21,85,84,0,
00091     0,85,65,85,0,
00092     0,85,85,85,0,
00093     0,85,65,85,0,
00094 };
00095 
00096 
00097 Pokitto::Core game;
00098 Pokitto::Display disp;
00099 Pokitto::Sound snd;
00100 Pokitto::Buttons btn;
00101 
00102 typedef enum GameStates {
00103     Menu=0,
00104     InitGame,
00105     Move,
00106     Check,
00107     Winner,
00108     Drawn,
00109     Credits
00110 } GameStates;
00111 
00112 typedef enum Symbol {
00113     None=0,
00114     Cross,
00115     Circle,
00116     Triangle,
00117     Diamond,
00118 } Symbol;
00119 
00120 typedef struct {
00121     short x;
00122     short y;
00123 } Point;
00124 
00125 typedef struct {
00126     bool winner;
00127     Point from;
00128     Point to;
00129     Symbol symb;
00130     short time;
00131 } WinnerLine;
00132 
00133 typedef struct {
00134     Symbol symb;
00135     short x;
00136     short y;
00137     short diameter;
00138     short time;
00139     float angle;
00140 } Sign;
00141 
00142 typedef struct Player {
00143     bool AI;
00144     Symbol symb;
00145 } Player;
00146 
00147 typedef struct MenuItem {
00148     char * description;
00149     int minValue;
00150     int maxValue;
00151     int value;
00152     bool asBool;
00153 } MenuItem;
00154 
00155 
00156 MenuItem mainMenu[MAX_MENU_SETTINGS];
00157 char menuIndex=0;
00158 
00159 char setBoardSize=3;
00160 char setSigns2Win=3;
00161 char setNumPlayers=2;
00162 
00163 Sign board[MAX_GRID_SIZE][MAX_GRID_SIZE];
00164 Point cursor;
00165 
00166 Player players[MAX_PLAYERS];
00167 char playerTurn=0;
00168 WinnerLine winnerLine;
00169 GameStates gameState;
00170 Point boardPosition = {.x=5,.y=5};
00171 
00172 Sign scoreList[14];
00173 char scoreListIndx=0;
00174 
00175 uint32_t timer;
00176 
00177 
00178 int clip(int n, int lower, int upper)
00179 {
00180     if (n<lower) return lower;
00181     if (n>upper) return upper;
00182     return n;
00183 }
00184 
00185 template <typename T>
00186 T lerp(T a, T b, T t)
00187 {
00188     return a + (b - a) * cos(PI2*t/100.0);
00189 }
00190 
00191 void initMenu()
00192 {
00193     MenuItem menuSize;
00194     menuSize.description="Board Size (NxN)";
00195     menuSize.minValue=2;
00196     menuSize.maxValue=5;
00197     menuSize.value=3;
00198     menuSize.asBool=false;
00199     mainMenu[0]=menuSize;
00200 
00201     MenuItem menuSigns2Win;
00202     menuSigns2Win.description="Signs to win";
00203     menuSigns2Win.minValue=2;
00204     menuSigns2Win.maxValue=5;
00205     menuSigns2Win.value=3;
00206     menuSigns2Win.asBool=false;
00207     mainMenu[1]=menuSigns2Win;
00208 
00209     MenuItem menuNumPlayers;
00210     menuNumPlayers.description="Number of players";
00211     menuNumPlayers.minValue=2;
00212     menuNumPlayers.maxValue=4;
00213     menuNumPlayers.value=2;
00214     menuNumPlayers.asBool=false;
00215     mainMenu[2]=menuNumPlayers;
00216 
00217     MenuItem P1Settings;
00218     P1Settings.description="Player 1";
00219     P1Settings.minValue=0;
00220     P1Settings.maxValue=1;
00221     P1Settings.value=0;
00222     P1Settings.asBool=true;
00223     mainMenu[3]=P1Settings;
00224 
00225     MenuItem P2Settings;
00226     P2Settings.description="Player 2";
00227     P2Settings.minValue=0;
00228     P2Settings.maxValue=1;
00229     P2Settings.value=1;
00230     P2Settings.asBool=true;
00231     mainMenu[4]=P2Settings;
00232 
00233     MenuItem P3Settings;
00234     P3Settings.description="Player 3";
00235     P3Settings.minValue=0;
00236     P3Settings.maxValue=1;
00237     P3Settings.value=1;
00238     P3Settings.asBool=true;
00239     mainMenu[5]=P3Settings;
00240 
00241     MenuItem P4Settings;
00242     P4Settings.description="Player 4";
00243     P4Settings.minValue=0;
00244     P4Settings.maxValue=1;
00245     P4Settings.value=1;
00246     P4Settings.asBool=true;
00247     mainMenu[6]=P4Settings;
00248 
00249 }
00250 
00251 void drawMenuItem(short x,short y,MenuItem item)
00252 {
00253     disp.color=1;
00254     disp.print(x,y,item.description);
00255 
00256 
00257     if(item.asBool) {
00258         if (item.value==1) {
00259             disp.drawBitmap(x+112,y-(AI_logo[1]/2)+3,AI_logo);
00260         } else {
00261             disp.drawBitmap(x+112,y-(AI_logo[1]/2)+3,P_logo);
00262         }
00263 
00264     } else {
00265         disp.color=2;
00266         disp.print(x+120,y,(int)item.value);
00267     }
00268 }
00269 
00270 
00271 void drawPolygon (short xc, short yc, short r, short n,float a)
00272 {
00273     short lastx;
00274     short lasty;
00275     a-=PI2;
00276     short x = (int)((float)xc + (float)r * cos(a));
00277     short y = (int) ((float)yc + (float)r * sin(a));
00278 
00279     for (int i = 0; i < n; i++) {
00280         lastx = x;
00281         lasty = y;
00282         a = a + (2 * PI / n);
00283         x = (int) ((float)xc + (float)r * cos(a));
00284         y = (int) ((float)yc + (float)r * sin(a));
00285         disp.drawLine(lastx, lasty, x, y);
00286     }
00287 }
00288 
00289 void drawCross(short xc, short yc, short r, short n,float a)
00290 {
00291     short x;
00292     short y;
00293     a-=PI/4;
00294     for (int i = 0; i < n; i++) {
00295         x = (int) ((float)xc + (float)r * cos(a));
00296         y = (int) ((float)yc + (float)r * sin(a));
00297         a = a + (2 * PI / n);
00298         disp.drawLine(xc, yc, x, y);
00299     }
00300 }
00301 
00302 void drawSign(Sign symb)
00303 {
00304     if (symb.symb==Cross) {
00305         disp.color=1;
00306         drawCross(symb.x,symb.y,symb.diameter/2,4,symb.angle);
00307     }
00308 
00309     if (symb.symb==Circle) {
00310         disp.color=2;
00311         disp.drawCircle(symb.x,symb.y,symb.diameter/2-sin(symb.angle)*symb.diameter/5.0);// symb.diameter/2 + 2*PI/symb.angle );
00312     }
00313 
00314     if (symb.symb==Triangle) {
00315         disp.color=3;
00316         drawPolygon(symb.x,symb.y,symb.diameter/2,3,symb.angle);
00317     }
00318 
00319     if (symb.symb==Diamond) {
00320         disp.color=1;
00321         drawPolygon(symb.x,symb.y,symb.diameter/2,4,symb.angle);
00322     }
00323 }
00324 
00325 void drawRectangle(double x1,double y1,double x2,double y2,double width,double offsetAngle)
00326 {
00327     Point pp[4];
00328     //Base angle
00329     double angle=-atan2(y1-y2,x1-x2)+PI2;
00330 
00331     double xc=(x1+x2)/2;
00332     double yc=(y1+y2)/2;
00333     double d2=sqrt(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)))/2;
00334 
00335     x1=xc+d2*sin(angle+offsetAngle);
00336     y1=yc+d2*cos(angle+offsetAngle);
00337     x2=xc+d2*sin(angle+offsetAngle-PI);
00338     y2=yc+d2*cos(angle+offsetAngle-PI);
00339 
00340     //Recalculate angle after offset angle is applied
00341     angle=-atan2(y1-y2,x1-x2);
00342 
00343     pp[0].x=x1+width*sin(angle+PI4);
00344     pp[0].y=y1+width*cos(angle+PI4);
00345     pp[1].x=x2+width*sin(angle-PI4);
00346     pp[1].y=y2+width*cos(angle-PI4);
00347 
00348     pp[2].x=x2+width*sin(angle-PI3_4);
00349     pp[2].y=y2+width*cos(angle-PI3_4);
00350     pp[3].x=x1+width*sin(angle+PI3_4);
00351     pp[3].y=y1+width*cos(angle+PI3_4);
00352 
00353     for(short i=0; i<4; i++) {
00354         disp.drawLine(pp[i].x,pp[i].y,pp[(i+1)%4].x,pp[(i+1)%4].y);
00355         //disp.drawLine(xc,yc,pp[i].x,pp[i].y);
00356     }
00357     //disp.drawLine(x1,y1,x2,y2);
00358 
00359 }
00360 
00361 void drawWinningLine(short xo,short yo,WinnerLine win)
00362 {
00363     short x1=xo+win.from.x * CELL_SIZE + CELL_SIZE/2;
00364     short y1=yo+win.from.y * CELL_SIZE+ CELL_SIZE/2;
00365     short x2=xo+win.to.x * CELL_SIZE+ CELL_SIZE/2;
00366     short y2=yo+win.to.y * CELL_SIZE+ CELL_SIZE/2;
00367     double a=lerp(0.0,2.0*PI,(double)win.time);
00368 
00369     disp.color=3;
00370     //drawRectangle(x1,y1,x2,y2,SIGN_SIZE,a);
00371     drawRectangle(x1,y1,x2,y2,SIGN_SIZE-2,a);
00372 }
00373 
00374 void drawMenu()
00375 {
00376     short xo;
00377     short yo;
00378 
00379     xo=(disp.width-logo[0])/2;
00380 
00381     //draw logo
00382     disp.drawBitmap(xo,0,logo);
00383 
00384     yo=logo[1];//logo height
00385     xo=40;
00386 
00387     //draw cursor
00388     disp.color=3;
00389     disp.print(xo-10,yo+(menuIndex*16),">");
00390     //draw menu items
00391     for (char m=0; m<sizeof(mainMenu)/sizeof(MenuItem); m++) {
00392         drawMenuItem(xo,yo,mainMenu[m]);
00393         yo+=16;
00394     }
00395 
00396     //draw instructions
00397     disp.color=3;
00398     disp.print(25,disp.height-30,"       Up/Down select menu");
00399     disp.print(25,disp.height-20,"    Left/Right change value");
00400     disp.print(25,disp.height-10,"A=Start Game B=Shuffle C=Menu");
00401 }
00402 
00403 void drawGameInfo()
00404 {
00405     disp.print((int)setNumPlayers);
00406     disp.print("P [");
00407     disp.print((int)setBoardSize);
00408     disp.print("x");
00409     disp.print((int)setBoardSize);
00410     disp.print("] ");
00411     disp.print((int)setSigns2Win);
00412     disp.print(" to win");
00413 }
00414 
00415 void drawBoard(short xo,short yo)
00416 {
00417     short xc;
00418     short yc;
00419 
00420     drawGameInfo();
00421 
00422     //Vertical lines
00423     disp.color=1;
00424     for (char x=1; x<setBoardSize; x++) {
00425         disp.drawLine(xo+(CELL_SIZE*x),yo,xo+(CELL_SIZE*x),yo+(CELL_SIZE*(setBoardSize)));
00426     }
00427     //Horizontal lines
00428     for (char y=1; y<setBoardSize; y++) {
00429         disp.drawLine(xo,yo+(CELL_SIZE*y),xo+CELL_SIZE*(setBoardSize),yo+(CELL_SIZE*y));
00430     }
00431 
00432     //Draw Cell
00433     for (char x=0; x<setBoardSize; x++) {
00434         for (char y=0; y<setBoardSize; y++) {
00435             //Update symbols time for animations
00436             if ( board[x][y].time<100) board[x][y].time+=5;
00437             board[x][y].angle=lerp((float)0,(float)2*PI,(float)board[x][y].time);
00438 
00439             //Calculate center of the cell
00440             xc=xo+(x*CELL_SIZE)+(CELL_SIZE/2);
00441             yc=yo+(y*CELL_SIZE)+(CELL_SIZE/2);
00442             board[x][y].x=xc;
00443             board[x][y].y=yc;
00444 
00445             //Draw cursor
00446             if (cursor.x==x && cursor.y==y) {
00447                 disp.color=3;
00448                 drawPolygon(xc,yc,CURSOR_SIZE/2,4,-PI/4);
00449             }
00450 
00451             //Draw symbol of the board
00452             drawSign(board[x][y]);
00453         }
00454     }
00455 
00456     //Draw player symbol at top/right corner
00457     Sign playerSign;
00458     playerSign.symb=players[playerTurn].symb;
00459     playerSign.x=disp.width-(SIGN_SIZE/2);
00460     playerSign.y=SIGN_SIZE/2;
00461     playerSign.diameter=SIGN_SIZE;
00462     drawSign(playerSign);
00463 
00464     //draw winner list
00465     disp.drawRect(disp.width-SIGN_SIZE,0,SIGN_SIZE-1,SIGN_SIZE);
00466     disp.drawRect(disp.width-SIGN_SIZE,0,SIGN_SIZE-1,disp.height-1);
00467     for (int i=0; i<sizeof(scoreList)/sizeof(Sign); i++) {
00468         drawSign(scoreList[i]);
00469     }
00470 }
00471 
00472 void initGame()
00473 {
00474     //Center board
00475     boardPosition.x=((disp.width-20)-(setBoardSize*CELL_SIZE))/2;
00476     boardPosition.y=6+((disp.height-6)-(setBoardSize*CELL_SIZE))/2;
00477 
00478     //Initialize cursor position
00479     cursor.x=(int)(setBoardSize/2);
00480     cursor.y=(int)(setBoardSize/2);
00481 
00482     //reset winnerLine
00483     winnerLine.winner=false;
00484 
00485     //Clear board
00486     for (char x=0; x<setBoardSize; x++) {
00487         for (char y=0; y<setBoardSize; y++) {
00488             board[x][y].symb=None;
00489             board[x][y].diameter=SIGN_SIZE;
00490         }
00491     }
00492 
00493     //Begin game
00494     gameState=Move;
00495 }
00496 
00497 void updateMenu()
00498 {
00499     //Scroll the menu settings
00500     if (btn.pressed(BTN_DOWN)) menuIndex++;
00501     if (btn.pressed(BTN_UP)) menuIndex--;
00502     menuIndex=clip(menuIndex,0,MAX_MENU_SETTINGS-1);
00503 
00504     //Change menu values
00505     if (btn.pressed(BTN_RIGHT))mainMenu[menuIndex].value++;
00506     if (btn.pressed(BTN_LEFT))mainMenu[menuIndex].value--;
00507     mainMenu[menuIndex].value=clip(mainMenu[menuIndex].value,mainMenu[menuIndex].minValue,mainMenu[menuIndex].maxValue);
00508 
00509     //Start game
00510     if (btn.pressed(BTN_A)) {
00511         setBoardSize=mainMenu[0].value;
00512         setSigns2Win=mainMenu[1].value;
00513         setNumPlayers=mainMenu[2].value;
00514 
00515         //
00516         players[0].symb=Cross;
00517         players[0].AI=mainMenu[3].value==1;
00518 
00519         players[1].symb=Circle;
00520         players[1].AI=mainMenu[4].value==1;
00521 
00522         players[2].symb=Triangle;
00523         players[2].AI=mainMenu[5].value==1;
00524 
00525         players[3].symb=Diamond;
00526         players[3].AI=mainMenu[6].value==1;
00527 
00528         gameState=InitGame;
00529     }
00530 
00531     //Randomize data
00532     if(btn.pressed((BTN_B))) {
00533         mainMenu[0].value=random(3,5); //board
00534         mainMenu[1].value=random(2,mainMenu[0].value); //signs to win
00535         mainMenu[2].value=random(2,4);//players
00536 
00537         mainMenu[3].value=random(0,1);//P1 AI
00538         mainMenu[4].value=random(0,1);//P2 AI
00539         mainMenu[5].value=random(0,1);//P3 AI
00540         mainMenu[6].value=random(0,1);//P4 AI
00541     }
00542     drawMenu();
00543 }
00544 
00545 
00546 bool isWinner(Sign originalBoard[MAX_GRID_SIZE][MAX_GRID_SIZE],Symbol symb,short xm=-1,short ym=-1)
00547 {
00548     short xc;
00549     short yc;
00550 
00551     //Copy board to test
00552     Sign boardTest[setBoardSize][setBoardSize];
00553     for (char x=0; x<setBoardSize; x++) {
00554         for (char y=0; y<setBoardSize; y++) {
00555             boardTest[x][y]=originalBoard[x][y];
00556         }
00557     }
00558 
00559     //If a move is request
00560     if(xm>-1 && ym>-1) {
00561         //place the symbol, if we can
00562         if(boardTest[xm][ym].symb==None) {
00563             boardTest[xm][ym].symb=symb;
00564         }
00565     }
00566 
00567     //NOW check all winning conditions
00568     bool win;
00569     winnerLine.time=0;
00570     for (char x=0; x<setBoardSize; x++) {
00571         for (char y=0; y<setBoardSize; y++) {
00572             //horizontal win
00573             win=true;
00574             for (char c=0; c<setSigns2Win; c++ ) {
00575                 xc=c+x;
00576                 yc=y;
00577                 if(xc>=0 && xc<setBoardSize && yc>=0 && yc<setBoardSize)
00578                     win=win && boardTest[xc][yc].symb==symb;
00579                 else
00580                     win=false;
00581             }
00582 
00583             if(win) {
00584                 winnerLine.winner=true;
00585                 winnerLine.from.x=x;
00586                 winnerLine.from.y=y;
00587                 winnerLine.to.x=x+setSigns2Win-1;
00588                 winnerLine.to.y=y;
00589                 winnerLine.symb=symb;
00590                 return true;
00591             }
00592 
00593             //vertical win
00594             win=true;
00595             for (char c=0; c<setSigns2Win; c++ ) {
00596                 xc=x;
00597                 yc=c+y;
00598                 if(xc>=0 && xc<setBoardSize && yc>=0 && yc<setBoardSize)
00599                     win=win && boardTest[xc][yc].symb==symb;
00600                 else
00601                     win=false;
00602             }
00603 
00604             if(win) {
00605                 winnerLine.winner=true;
00606                 winnerLine.from.x=x;
00607                 winnerLine.from.y=y;
00608                 winnerLine.to.x=x;
00609                 winnerLine.to.y=y+setSigns2Win-1;
00610                 winnerLine.symb=symb;
00611                 return true;
00612             }
00613 
00614             //diagonal top/right win
00615             win=true;
00616             for (char c=0; c<setSigns2Win; c++ ) {
00617                 xc=c+x;
00618                 yc=c+y;
00619                 if(xc>=0 && xc<setBoardSize && yc>=0 && yc<setBoardSize)
00620                     win=win && boardTest[xc][yc].symb==symb;
00621                 else
00622                     win=false;
00623             }
00624 
00625             if(win) {
00626                 winnerLine.winner=true;
00627                 winnerLine.from.x=x;
00628                 winnerLine.from.y=y;
00629                 winnerLine.to.x=x+setSigns2Win-1;
00630                 winnerLine.to.y=y+setSigns2Win-1;
00631                 winnerLine.symb=symb;
00632                 return true;
00633             }
00634 
00635             //diagonal top/left win
00636             win=true;
00637             for (char c=0; c<setSigns2Win; c++ ) {
00638                 xc=-c+x;
00639                 yc=c+y;
00640                 if(xc>=0 && xc<setBoardSize && yc>=0 && yc<setBoardSize)
00641                     win=win && boardTest[xc][yc].symb==symb;
00642                 else
00643                     win=false;
00644             }
00645 
00646             if(win) {
00647                 winnerLine.winner=true;
00648                 winnerLine.from.x=x;
00649                 winnerLine.from.y=y;
00650                 winnerLine.to.x=x-setSigns2Win+1;
00651                 winnerLine.to.y=y+setSigns2Win-1;
00652                 winnerLine.symb=symb;
00653                 return true;
00654             }
00655         }
00656     }
00657 
00658     winnerLine.winner=false;
00659     return false;
00660 }
00661 
00662 bool isDrawn(Sign originalBoard[MAX_GRID_SIZE][MAX_GRID_SIZE])
00663 {
00664     //All cells not None
00665     for (char x=0; x<setBoardSize; x++) {
00666         for (char y=0; y<setBoardSize; y++) {
00667             if (originalBoard[x][y].symb==None) {
00668                 return false;
00669             }
00670         }
00671     }
00672     return true;
00673 }
00674 
00675 
00676 void AI(Symbol symb)
00677 {
00678     //Check if I can win
00679     for (char x=0; x<setBoardSize; x++) {
00680         for (char y=0; y<setBoardSize; y++) {
00681             if (isWinner(board,symb,x,y)) {
00682                 //Place winning move
00683                 board[x][y].time=0;
00684                 board[x][y].symb=symb;
00685                 cursor.x=x;
00686                 cursor.y=y;
00687                 return;
00688             }
00689         }
00690     }
00691 
00692     //Check if anyone can win with a move
00693     for(char p=0; p<setNumPlayers; p++) {
00694         for (char x=0; x<setBoardSize; x++) {
00695             for (char y=0; y<setBoardSize; y++) {
00696                 if (isWinner(board,players[p].symb,x,y)) {
00697                     //Place winning move
00698                     board[x][y].time=0;
00699                     board[x][y].symb=symb;
00700                     cursor.x=x;
00701                     cursor.y=y;
00702                     return;
00703                 }
00704             }
00705         }
00706     }
00707 
00708 
00709     //TODO:
00710     //Check if I can win in 2 moves
00711     //as homework
00712 
00713     //place a random move
00714     while(true) {
00715         char x=random(0,setBoardSize-1);
00716         char y=random(0,setBoardSize-1);
00717         if(board[x][y].symb==None) {
00718             board[x][y].time=0;
00719             board[x][y].symb=symb;
00720             cursor.x=x;
00721             cursor.y=y;
00722             return;
00723         }
00724     }
00725 }
00726 
00727 void updateGame()
00728 {
00729     //Move
00730     if(players[playerTurn].AI) {
00731         AI(players[playerTurn].symb);
00732         gameState=Check;
00733     } else {
00734         if (btn.pressed(BTN_UP)) cursor.y-=1;
00735         if (btn.pressed(BTN_DOWN)) cursor.y+=1;
00736         if (btn.pressed(BTN_LEFT)) cursor.x-=1;
00737         if (btn.pressed(BTN_RIGHT)) cursor.x+=1;
00738 
00739         //Limit cursor to the board
00740         if (cursor.x>=setBoardSize) cursor.x=0;
00741         if (cursor.x<0) cursor.x=setBoardSize-1;
00742         if (cursor.y>=setBoardSize) cursor.y=0;
00743         if (cursor.y<0) cursor.y=setBoardSize-1;
00744 
00745 
00746         if (btn.pressed(BTN_A)) {
00747             if (board[cursor.x][cursor.y].symb==None) {
00748                 board[cursor.x][cursor.y].time=0;
00749                 board[cursor.x][cursor.y].symb=players[playerTurn].symb;
00750                 gameState=Check;
00751             }
00752         }
00753     }
00754 
00755     //Draw
00756     drawBoard(boardPosition.x,boardPosition.y);
00757 }
00758 
00759 void updateCheck()
00760 {
00761 
00762     if(isWinner(board,players[playerTurn].symb)) {
00763         cursor.x=-1;
00764         cursor.y=-1;
00765         gameState=Winner;
00766         timer=game.getTime()+1500;
00767     } else if (isDrawn(board)) {
00768         cursor.x=-1;
00769         cursor.y=-1;
00770         gameState=Drawn;
00771         timer=game.getTime()+1500;
00772     } else {
00773 
00774         gameState=Move;
00775     }
00776 
00777     //Next player
00778     playerTurn++;
00779     playerTurn=playerTurn%setNumPlayers;
00780 
00781     //Draw
00782     drawBoard(boardPosition.x,boardPosition.y);
00783 }
00784 
00785 void updateWin()
00786 {
00787     drawBoard(boardPosition.x,boardPosition.y);
00788 
00789     //Winner line
00790     if (winnerLine.time <100) winnerLine.time+=10;
00791     drawWinningLine(boardPosition.x,boardPosition.y,winnerLine);
00792 
00793     if (btn.pressed(BTN_A) || game.getTime()>timer) {
00794         //move list symbols
00795         for (int i=0; i<sizeof(scoreList)/sizeof(Sign); i++) {
00796             scoreList[i].y+=SIGN_SIZE/2;
00797         }
00798 
00799         //add winner symbol
00800         Sign winSign;
00801         winSign.x=disp.width-(SIGN_SIZE/2);
00802         winSign.y=SIGN_SIZE+SIGN_SIZE/2;
00803         winSign.symb=winnerLine.symb;
00804         winSign.diameter=SIGN_SIZE/2;
00805         scoreList[scoreListIndx]=winSign;
00806         scoreListIndx=(scoreListIndx+1)%(sizeof(scoreList)/sizeof(Sign));
00807 
00808         gameState=InitGame;
00809     }
00810     disp.color=0;
00811     disp.fillRectangle(55,disp.height/2-2,100,10);
00812     disp.color=2;
00813     disp.println(55,disp.height/2,"There's a winner!");
00814 }
00815 
00816 void updateDrawn()
00817 {
00818     drawBoard(boardPosition.x,boardPosition.y);
00819 
00820     disp.color=0;
00821     disp.fillRectangle(55,disp.height/2-2,80,10);
00822     disp.color=2;
00823     disp.print(60,disp.height/2,"It's a drawn");
00824 
00825     if (btn.pressed(BTN_A) || game.getTime()>timer) {
00826         gameState=InitGame;
00827     }
00828 }
00829 
00830 
00831 int main ()
00832 {
00833     initMenu();
00834     game.begin();
00835 
00836     //load palette
00837     disp.palette[0]=COLOR_BLACK;
00838     disp.palette[1]=COLOR_WHITE;
00839     disp.palette[2]=COLOR_GREEN;
00840     disp.palette[3]=COLOR_RED;
00841 
00842     while (game.isRunning()) {
00843         if (game.update()) {
00844             //Exit to menu
00845             if(btn.pressed((BTN_C))) {
00846                 gameState=Menu;
00847             }
00848 
00849             //Game states
00850             switch (gameState) {
00851                 case Menu:
00852                     updateMenu();
00853                     break;
00854                 case InitGame:
00855                     initGame();
00856                     break;
00857                 case Move:
00858                     updateGame();
00859                     break;
00860                 case Check:
00861                     updateCheck();
00862                     break;
00863                 case Winner:
00864                     updateWin();
00865                     break;
00866                 case Drawn:
00867                     updateDrawn();
00868                     break;
00869                 default:
00870                     break;
00871             }
00872         }
00873     }
00874 
00875     return 1;
00876 }