ECE 4180 - Lab 4 Tower of Hanoi
Dependencies: 4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player
main.cpp
00001 //ECE 4180 Lab 4 00002 //Tower of Hanoi Game - uLCD, joystick, sd card, speakers 00003 //Mark Francisco Olorvida, Khayame Maiki 00004 #include "mbed.h" 00005 #include "uLCD_4DGL.h" 00006 #include "SDFileSystem.h" 00007 #include "wave_player.h" 00008 #include "rtos.h" 00009 #include "stdlib.h" 00010 #include <stack> 00011 00012 00013 #define BROWN 0x663300 00014 #define YELLOW 0xFFFF00 00015 #define ORANGE 0xFFA500 00016 00017 using namespace std; 00018 00019 class Nav_Switch 00020 { 00021 public: 00022 Nav_Switch(PinName up,PinName down,PinName left,PinName right,PinName fire); 00023 int read(); 00024 //boolean functions to test each switch 00025 bool up(); 00026 bool down(); 00027 bool left(); 00028 bool right(); 00029 bool fire(); 00030 //automatic read on RHS 00031 operator int (); 00032 //index to any switch array style 00033 bool operator[](int index) { 00034 return _pins[index]; 00035 }; 00036 private: 00037 BusIn _pins; 00038 00039 }; 00040 Nav_Switch::Nav_Switch (PinName up,PinName down,PinName left,PinName right,PinName fire): 00041 _pins(up, down, left, right, fire) 00042 { 00043 _pins.mode(PullUp); //needed if pullups not on board or a bare nav switch is used - delete otherwise 00044 wait(0.001); //delays just a bit for pullups to pull inputs high 00045 } 00046 inline bool Nav_Switch::up() 00047 { 00048 return !(_pins[0]); 00049 } 00050 inline bool Nav_Switch::down() 00051 { 00052 return !(_pins[1]); 00053 } 00054 inline bool Nav_Switch::left() 00055 { 00056 return !(_pins[2]); 00057 } 00058 inline bool Nav_Switch::right() 00059 { 00060 return !(_pins[3]); 00061 } 00062 inline bool Nav_Switch::fire() 00063 { 00064 return !(_pins[4]); 00065 } 00066 inline int Nav_Switch::read() 00067 { 00068 return _pins.read(); 00069 } 00070 inline Nav_Switch::operator int () 00071 { 00072 return _pins.read(); 00073 } 00074 00075 Nav_Switch myNav( p16, p13, p14, p12, p15); //up, down, left, right, fire 00076 00077 uLCD_4DGL uLCD(p28,p27,p30); // serial tx, serial rx, reset pin; 00078 00079 SDFileSystem sd(p5, p6, p7, p8, "sd"); // sd(SPI mosi, SPI miso, SPI sck, digital out cs) 00080 00081 Mutex stdio_mutex; //mutex for the uLCD 00082 00083 AnalogOut DACout(p18); // used to play sound on speaker 00084 00085 PwmOut Speaker(p21); 00086 00087 //wave player plays a *.wav file to D/A and a PWM 00088 wave_player waver(&DACout); 00089 00090 00091 00092 00093 00094 00095 stack<int> col1; // 00096 stack<int> col2; 00097 stack<int> col3; 00098 00099 00100 00101 int source; // Source of ring that is going to be moved 00102 int destination; // Destination of ring that is going to be moved 00103 int direction; // don't actually use this right now 00104 int numRings; 00105 bool select; // 0 if selecting source, 1 if selecting destination 00106 int cursor; // position of destination selecting cursor 00107 int count = 0; 00108 00109 00110 void move(); //move rectangles between columns 00111 void drawMove( int , int , int ); //draw the change in Rings i.e. moving Ring 1 from Src1 --> Src 2 results in col. 1 = 4 3 2 and col.2 = 1 00112 bool checkVictory(); //function to check win condition (all rings move to a separate column from the starting column 00113 void drawCursor(int , int ); 00114 void drawSourceSelect(); 00115 void drawDestinationSelect(); 00116 void game(); //main game function 00117 00118 int main() 00119 { 00120 //Title Screen 00121 00122 uLCD.printf("\n Tower of Hanoi\n"); 00123 //3 vertical lines at x = 32, 64, 96 00124 //have circles to mark the positions of columns 00125 uLCD.filled_circle(32, 110, 2, BLUE); 00126 uLCD.filled_circle(64, 110, 2, BLUE); 00127 uLCD.filled_circle(96, 110, 2, BLUE); 00128 //rectangles - each rectangle increases in width based on its number 00129 //rectangles go from 1-6 going down 00130 uLCD.filled_rectangle(32-2*1, 35+15*1-1, 32+2*1, 35+15*1, RED); //(filled_rectangle*(32(x-coordinate of vertical line)-2*(num_rectangle (1,2,3 or 4)), 35 + (60/num_rectangles)-1, first param but with addition, 2nd param but no extra 1 subtracted)) 00131 uLCD.filled_rectangle(32-2*2, 35+15*2-1, 32+2*2, 35+15*2, ORANGE); 00132 uLCD.filled_rectangle(32-2*3, 35+15*3-1, 32+2*3, 35+15*3, YELLOW); 00133 uLCD.filled_rectangle(32-2*4, 35+15*4-1, 32+2*4, 35+15*4, GREEN); 00134 00135 //play intro wave file 00136 FILE *wave_file; 00137 //open file 00138 wave_file = fopen("/sd/wavfiles/intro.wav" ,"r"); 00139 if (wave_file == NULL){ 00140 error("Could not open file for read\n"); 00141 } 00142 //play file 00143 Speaker.period(1.0/400000.0); 00144 waver.play(wave_file); 00145 //close file 00146 fclose(wave_file); 00147 00148 uLCD.cls(); // clear screen 00149 //tutorial 00150 uLCD.printf("\n HOW TO PLAY\n"); 00151 uLCD.printf("Goal: Move all rectangles to another pole.\n"); 00152 uLCD.printf("\n1. You can only move one rectangle at a time.\n"); 00153 uLCD.printf("\n2. Large rectangles can not be put on top of smaller rectangles.\n"); 00154 while(1){ //loop until user pushes left right or fire after reading tutorial 00155 if (myNav.left() or myNav.right() or myNav.fire()){ break;} 00156 else {} 00157 } 00158 uLCD.cls(); 00159 uLCD.printf("\n CONTROLS\n"); 00160 uLCD.printf("\nUse Left/Right to choose column \n"); 00161 uLCD.printf("-Red Circle = Source column\n"); 00162 uLCD.printf("-Yellow Cursor = Dest. column\n"); 00163 uLCD.printf("\nUse Center to select column.\n"); 00164 while(1){ //loop until user pushes left right or fire after reading tutorial 00165 if (myNav.left() or myNav.right() or myNav.fire()){ break;} 00166 else {} 00167 } 00168 game(); 00169 } 00170 void game() // main game function 00171 { 00172 uLCD.cls(); 00173 // Game init 00174 00175 uLCD.filled_circle(32, 110, 2, BLUE); 00176 uLCD.filled_circle(64, 110, 2, BLUE); 00177 uLCD.filled_circle(96, 110, 2, BLUE); 00178 uLCD.filled_rectangle(32-2*1, 35+12*1-1, 32+2*1, 35+12*1, RED); 00179 uLCD.filled_rectangle(32-2*2, 35+12*2-1, 32+2*2, 35+12*2, ORANGE); 00180 uLCD.filled_rectangle(32-2*3, 35+12*3-1, 32+2*3, 35+12*3, YELLOW); 00181 uLCD.filled_rectangle(32-2*4, 35+12*4-1, 32+2*4, 35+12*4, GREEN); 00182 00183 numRings = 4; 00184 col1.push(4); 00185 col1.push(3); 00186 col1.push(2); 00187 col1.push(1); 00188 00189 // draw game 00190 source = 1; 00191 destination = 2; 00192 cursor = 2; 00193 drawSourceSelect(); 00194 drawDestinationSelect(); 00195 uLCD.filled_rectangle(32-2*1, 35+12*1-1, 32+2*1, 35+12*1, RED); 00196 uLCD.filled_rectangle(32-2*2, 35+12*2-1, 32+2*2, 35+12*2, ORANGE); 00197 uLCD.filled_rectangle(32-2*3, 35+12*3-1, 32+2*3, 35+12*3, YELLOW); 00198 uLCD.filled_rectangle(32-2*4, 35+12*4-1, 32+2*4, 35+12*4, GREEN); 00199 00200 00201 00202 00203 uLCD.locate(0,0); 00204 uLCD.printf("# of Moves: %i\n",count); //update move count 00205 while (1) { // Game loop 00206 00207 if (checkVictory()) { // checks to see if the win condition has been met... will either reset, or go victory screen or something 00208 wait(1); 00209 uLCD.cls(); 00210 uLCD.locate(0,0); 00211 uLCD.printf("\n You won!\n"); 00212 uLCD.printf("\nMin. Moves: 15 \n"); 00213 uLCD.printf("\nYour # of moves : %i \n" , count ); 00214 //play intro wave file 00215 FILE *wave_file; 00216 //open file 00217 wave_file = fopen("/sd/wavfiles/outro.wav" ,"r"); 00218 if (wave_file == NULL) { 00219 error("Could not open file for read\n"); 00220 } 00221 //play file 00222 Speaker.period(1.0/400000.0); 00223 waver.play(wave_file); 00224 //close file 00225 fclose(wave_file); 00226 count = 0; //reset count 00227 break; 00228 } 00229 00230 00231 if ( myNav.left() ) { // moves either source or destination pointer to the left based on 00232 if (!select) { // the variable select 00233 if (source == 1) { 00234 source = 3; 00235 00236 } else { 00237 source = source - 1; 00238 00239 } 00240 drawSourceSelect(); 00241 } else { 00242 if (destination == 1) { 00243 destination = 3; 00244 00245 } else { 00246 destination = destination - 1; 00247 00248 } 00249 drawDestinationSelect(); 00250 } 00251 00252 } 00253 00254 else if ( myNav.right() ) { 00255 if (!select) { 00256 if (source == 3) { 00257 source = 1; 00258 00259 } else { 00260 source = source + 1; 00261 } 00262 drawSourceSelect(); 00263 } else { 00264 if (destination == 3) { 00265 destination = 1; 00266 } else { 00267 destination = destination + 1; 00268 } 00269 drawDestinationSelect(); 00270 } 00271 } 00272 00273 else if ( myNav.fire()) { 00274 if (!select) { // source chosen, toggle to choose destination 00275 select = !select; // toggles 00276 } else if (select) { // Destination chosen, move ring 00277 move(); 00278 count ++; 00279 uLCD.locate(0,0); 00280 uLCD.printf("# of Moves: %i\n",count); //update move count 00281 select = !select; // Go back to source selection regardless of the outcome of move 00282 } 00283 wait(.4); 00284 } 00285 00286 } 00287 if (col3.size() == numRings){ //if col3 has numRings, pop all rings 00288 for (int x = 0; x < 4 ; x++){ 00289 col3.pop(); 00290 } 00291 } 00292 else if (col2.size() == numRings){ //same with col 2 00293 for (int x = 0; x < 4 ; x++){ 00294 col2.pop(); 00295 } 00296 } 00297 game(); 00298 } 00299 void move() 00300 { 00301 int sourceSize, destSize, ringNum, top; 00302 00303 00304 00305 switch (source) { 00306 00307 case 1: 00308 sourceSize = col1.size(); // to figure out where on the Y axis to black out a ring 00309 if (sourceSize == 0) 00310 break; 00311 00312 if ( destination == 2) { 00313 if (col2.empty()) { 00314 top = col1.top(); 00315 col2.push(top); // move the ring over 00316 00317 col1.pop(); 00318 00319 destSize = col2.size(); // to figure out where on Y axis to draw new ring 00320 ringNum = top; 00321 //uLCD.printf("Ring Number: %i " , ringNum); 00322 drawMove(sourceSize, destSize, ringNum); 00323 } 00324 00325 00326 else if ( col1.top() < col2.top()) { // if the ring on column 1 is smaller than the ring in column 2 00327 top = col1.top(); 00328 col2.push(top); // move the ring over 00329 col1.pop(); 00330 destSize = col2.size(); // to figure out where on Y axis to draw new ring 00331 ringNum = top; 00332 drawMove(sourceSize, destSize, ringNum); 00333 00334 } 00335 00336 00337 } 00338 00339 else if ( destination == 3) { 00340 if (col3.empty()) { 00341 top = col1.top(); 00342 col3.push(top); // move the ring over 00343 col1.pop(); 00344 destSize = col3.size(); 00345 ringNum = top; 00346 drawMove(sourceSize, destSize, ringNum); 00347 } else if ( col1.top() < col3.top()) { // if the ring on column 1 is smaller than the ring in column 3 00348 top = col1.top(); 00349 col3.push(top); // move the ring over 00350 col1.pop(); 00351 destSize = col3.size(); 00352 ringNum = top; 00353 drawMove(sourceSize, destSize, ringNum); 00354 } 00355 } 00356 00357 00358 break; 00359 00360 00361 00362 00363 case 2: 00364 sourceSize = col2.size(); 00365 if (sourceSize == 0) 00366 break; 00367 if ( destination == 1) { 00368 if (col1.empty()) { 00369 col1.push(col2.top()); 00370 col2.pop(); 00371 destSize = col1.size(); 00372 ringNum = col1.top(); 00373 drawMove(sourceSize, destSize, ringNum); 00374 } else if ( col2.top() < col1.top()) { 00375 col1.push(col2.top()); 00376 col2.pop(); 00377 destSize = col1.size(); 00378 ringNum = col1.top(); 00379 drawMove(sourceSize, destSize, ringNum); 00380 } 00381 } 00382 00383 else if ( destination == 3) { 00384 if (col3.empty()) { 00385 col3.push(col2.top()); 00386 col2.pop(); 00387 destSize = col3.size(); 00388 ringNum = col3.top(); 00389 drawMove(sourceSize, destSize, ringNum); 00390 } else if ( col2.top() < col3.top()) { 00391 00392 col3.push(col2.top()); 00393 col2.pop(); 00394 destSize = col3.size(); 00395 ringNum = col3.top(); 00396 drawMove(sourceSize, destSize, ringNum); 00397 } 00398 } 00399 break; 00400 00401 case 3: 00402 sourceSize = col3.size(); 00403 if (sourceSize == 0) 00404 break; 00405 if ( destination == 1) { 00406 if ( col1.empty()) { 00407 col1.push(col3.top()); 00408 col3.pop(); 00409 destSize = col1.size(); 00410 ringNum = col1.top(); 00411 drawMove(sourceSize, destSize, ringNum); 00412 } else if ( col3.top() < col1.top()) { 00413 col1.push(col3.top()); 00414 col3.pop(); 00415 destSize = col1.size(); 00416 ringNum = col1.top(); 00417 drawMove(sourceSize, destSize, ringNum); 00418 } 00419 } 00420 00421 else if ( destination == 2) { 00422 if (col2.empty()) { 00423 col2.push(col3.top()); 00424 col3.pop(); 00425 destSize = col2.size(); 00426 ringNum = col2.top(); 00427 drawMove(sourceSize, destSize, ringNum); 00428 } 00429 00430 else if ( col3.top() < col2.top()) { 00431 col2.push(col3.top()); 00432 col3.pop(); 00433 destSize = col2.size(); 00434 ringNum = col2.top(); 00435 drawMove(sourceSize, destSize, ringNum); 00436 } 00437 } 00438 break; 00439 00440 00441 } 00442 00443 00444 00445 00446 00447 } 00448 00449 void drawMove( int sourceSize, int destSize, int numRing ) 00450 { 00451 00452 int x1Source = 32 * source - 2*numRing; 00453 int y1Source = 35 + 12*(5- sourceSize) - 1; 00454 int x2Source = 32 * source + 2*numRing; 00455 int y2Source = 35 + 12*(5- sourceSize); 00456 00457 int x1Dest = 32 * destination - 2*numRing; 00458 int y1Dest = 35 + 12*(5-destSize) - 1; 00459 int x2Dest = 32 * destination + 2*numRing; 00460 int y2Dest = 35 + 12*(5- destSize); 00461 00462 00463 switch (numRing) { 00464 case 1 : 00465 uLCD.filled_rectangle(x1Dest, y1Dest, x2Dest, y2Dest, RED); 00466 //uLCD.filled_rectangle(x1Dest, 35+12*4-1, x2Dest, 35+12*4, RED); 00467 break; 00468 case 2 : 00469 uLCD.filled_rectangle(x1Dest, y1Dest, x2Dest, y2Dest, ORANGE); 00470 break; 00471 case 3 : 00472 uLCD.filled_rectangle(x1Dest, y1Dest, x2Dest, y2Dest, YELLOW); 00473 break; 00474 case 4 : 00475 uLCD.filled_rectangle(x1Dest, y1Dest, x2Dest, y2Dest, GREEN); 00476 break; 00477 } 00478 00479 uLCD.filled_rectangle(x1Source, y1Source, x2Source, y2Source, BLACK); 00480 00481 } 00482 00483 00484 00485 00486 00487 00488 00489 bool checkVictory() 00490 { 00491 return (col3.size() == numRings or col2.size() == numRings); // if column 3 has all the rings game is done. This should only be possible if it's correct 00492 } 00493 00494 void drawCursor(int columnX, int color) //columnX = x-coordinate of column, color 00495 { 00496 //draws a 9 pixel triangle(5 on 1 row, 3 on row 2, 1 on row 3) 00497 uLCD.pixel(columnX,30,color); 00498 uLCD.pixel(columnX-1,29,color); 00499 uLCD.pixel(columnX,29,color); 00500 uLCD.pixel(columnX+1,29,color); 00501 uLCD.pixel(columnX-2,28,color); 00502 uLCD.pixel(columnX-1,28,color); 00503 uLCD.pixel(columnX,28,color); 00504 uLCD.pixel(columnX+1,28,color); 00505 uLCD.pixel(columnX+2,28,color); 00506 } 00507 00508 void drawSourceSelect() 00509 { 00510 uLCD.filled_circle(32, 110, 2, BLUE); 00511 uLCD.filled_circle(64, 110, 2, BLUE); 00512 uLCD.filled_circle(96, 110, 2, BLUE); 00513 if (source == 1 ) 00514 uLCD.filled_circle(32, 110, 2, RED); 00515 else if ( source == 2 ) 00516 uLCD.filled_circle(64, 110, 2, RED); 00517 else if (source == 3 ) 00518 uLCD.filled_circle(96, 110, 2, RED); 00519 wait(.3); 00520 } 00521 00522 void drawDestinationSelect() // also changes cursor global to new destination 00523 { 00524 drawCursor( cursor*32, BLACK); 00525 drawCursor( destination*32, YELLOW); 00526 cursor = destination; 00527 wait(.3); 00528 }
Generated on Sun Jul 17 2022 17:53:05 by 1.7.2