Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: PokittoLib mbed-src
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 }
Generated on Sat Jul 23 2022 16:36:18 by
