ECE 4180 - Lab 4 Tower of Hanoi

Dependencies:   4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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 }