Landolt-C Game

Description

This is an mBed implementation of the Landolt-C vision test. The main purpose of this game is to achieve the best score possible. This is done by successfully completing each level. In each level, the player is shown a Landolt-C for a short amount of time, oriented randomly upwards, downwards, leftwards or rightwards. The player is then prompted to input the orientation of the Landolt-C using the pushbuttons. If the user does this correctly, he or she is awarded one point. The game repeats this process at a higher difficulty each time by reducing the size of the Landolt-C and the time it is displayed. If the player cannot guess the orientation of the Landolt-C correctly, the game ends and the player’s score is recorded on a high-score table.

The game features a main menu from which the player can select three different options. First, the player can choose to play the game. Second, the player can choose to view the list of high scores. Lastly, the player can view details about the creators of the game.

The approach taken to implement the game is the following: we used phase variables inside the infinite while loop to display each stage of the game. Images and audio were loaded onto two different micro SD cards, and are used in the different phases. The images were used to display the Landolt-Cs, the watermark, the main menu, the instructions, and the correct/incorrect indicators. The high-scores table was implemented using a bubble-sort algorithm, which is efficient for sorted data.

/media/uploads/orodriguez8/fullsizerender_-1-.jpg

Pin-out Connections

SD Card Connections

mBedSD
p5d0
p6SCK
p7DI
p8CS
GNDGND
VoutVcc

uLCD Connections

mBeduLCD
Vu5V
GndGnd
Tx=p9RX
Rx=p10TX
P11Reset

Up Pushbutton Connections

mBedUp Pushbutton
P19P1
GndP2

Down Pushbutton Connections

mBedUp Pushbutton
P12P1
GndP2

Left Pushbutton Connections

mBedUp Pushbutton
P15P1
GndP2

Right Pushbutton Connections

mBedUp Pushbutton
P9P1
GndP2

Audio Amplifier and Speaker Connections

mBedAudio AmplifierSpeaker
p18in+
Gndin-
out++
out--
GndPwr-
VccPwr+

Demo

Program

main.cpp

#include "mbed.h"
#include "SDFileSystem.h"
#include "uLCD_4DGL.h"
#include <algorithm>
#include "wave_player.h"

void bubbleSort(int arr[], int n) {
      bool swapped = true;
      int j = 0;
      int tmp;
      while (swapped) {
            swapped = false;
            j++;
            for (int i = 0; i < n - j; i++) {
                  if (arr[i] > arr[i + 1]) {
                        tmp = arr[i];
                        arr[i] = arr[i + 1];
                        arr[i + 1] = tmp;
                        swapped = true;
                  }
            }
      }
}

uLCD_4DGL uLCD(p13, p14, p11); // serial tx, serial rx, reset pin;
SDFileSystem sd(p5, p6, p7, p8, "sd"); //SD card
DigitalIn pbUp(p19);
DigitalIn pbLeft(p15);
DigitalIn pbDown(p12);
DigitalIn pbRight(p9);

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

AnalogOut DACout(p18);

//Global Variables
wave_player waver(&DACout);

int phase = 0;
int level = 1;
int score = 0;
int correctAns = -1;
int ans = -1;
bool isCorrect = false;
bool lost = false;
float waitTime = 1.0;
int homepage = 0;
int instruction = 0;
int highScores [10];
int flag = 0;


int main() {
    //Initialize Sound Variables
    FILE *sound_start;
  
    
    for (int i = 0; i < 10; i++){
        highScores[i] = 0;
    }
    
    pbUp.mode(PullUp);
    pbLeft.mode(PullUp);
    pbRight.mode(PullUp);
    pbDown.mode(PullUp);
    while(1) {
        sound_start=fopen("/sd/mydir/start.wav","r");
        if (phase == 0) {
            //Display Watermark
            uLCD.cls();
            uLCD.media_init();
            uLCD.set_sector_address(0x003B, 0x86DB);
            uLCD.display_image(0,0);
            
            waver.play(sound_start);
            
                              
            wait(1.0);
            uLCD.cls();
            phase = 1;
        } else if (phase == 1) {
            //Homepage
            if(homepage == 0){
                uLCD.media_init();
                uLCD.set_sector_address(0x003B, 0x8618);
                uLCD.display_image(0,0);
                if (pbUp < 0.5) {
                    homepage = 2;
                }
                else if (pbDown < 0.5) {
                    homepage = 1;
                }
                else if (pbRight < 0.5) {
                    phase = 2;
                    uLCD.cls();
                }
                            
            }
            if(homepage == 1){
                uLCD.media_init();
                uLCD.set_sector_address(0x003B, 0x8659);
                uLCD.display_image(0,0);
                if (pbUp < 0.5) {
                    homepage = 0;
                }
                else if (pbDown < 0.5) {
                    homepage = 2;
                }
                else if (pbRight < 0.5) {
                    phase = 7;
                    uLCD.cls();
                    
                }
                
            }
            if(homepage == 2){
                uLCD.media_init();
                uLCD.set_sector_address(0x003B, 0x869A);
                uLCD.display_image(0,0);
                
                if (pbUp < 0.5) {
                    homepage = 1;
                }
                else if (pbDown < 0.5) {
                    homepage = 0;
                }
                else if (pbRight < 0.5) {
                    phase = 8;                    
                }
            }
            
        } else if (phase == 2) {
            
            if(instruction == 0){
                uLCD.media_init();
                uLCD.set_sector_address(0x003B, 0x8596);
                uLCD.display_image(0,0);
            }
            else if(instruction == 1){
                uLCD.media_init();
                uLCD.set_sector_address(0x003B, 0x85D7);
                uLCD.display_image(0,0);
            }
            
            else if (instruction == 2){
                uLCD.cls();
                uLCD.printf("\n\n\n\n\n\n\n     Get Ready    ");
                wait(1.0);
                uLCD.cls();
                uLCD.printf("\n\n\n\n\n\n\n         3");
                wait(1.0);
                uLCD.cls();
                uLCD.printf("\n\n\n\n\n\n\n         2");
                wait(1.0);
                uLCD.cls();
                uLCD.printf("\n\n\n\n\n\n\n         1");
                wait(1.0);
                uLCD.cls();
                phase = 3;
            }
            if (pbRight < 0.5){ 
                instruction++;
            }
            if(instruction > 0){
                if (pbLeft < 0.5){ 
                    instruction--;
                }
            }
        } else if (phase == 3) {
            waitTime = waitTime / level;
            correctAns = rand() % 4 + 1;
            if(level < 5){
                switch(correctAns) {
                    case 1 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x83CF);
                    uLCD.display_image(0,0);
                                break; 
                    case 2 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8145);
                    uLCD.display_image(0,0);
                                break; 
                    case 3 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8000);
                    uLCD.display_image(0,0);
                                break; 
                    case 4 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x828A);
                    uLCD.display_image(0,0);
                                break; 
                }
            }
            else if(level > 4 && level < 9){
                switch(correctAns) {
                    case 1 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8410);
                    uLCD.display_image(0,0);
                                break; 
                    case 2 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8186);
                    uLCD.display_image(0,0);
                                break; 
                    case 3 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8041);
                    uLCD.display_image(0,0);
                                break; 
                    case 4 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x82CB);
                    uLCD.display_image(0,0);
                                break; 
                }
            }
            else if(level > 8 && level < 13){
                switch(correctAns) {
                    case 1 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8451);
                    uLCD.display_image(0,0);
                                break; 
                    case 2 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x81C7);
                    uLCD.display_image(0,0);
                                break; 
                    case 3 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8082);
                    uLCD.display_image(0,0);
                                break; 
                    case 4 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x830C);
                    uLCD.display_image(0,0);
                                break; 
                }
            }
            else if(level > 12 && level < 17){
                switch(correctAns) {
                    case 1 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8492);
                    uLCD.display_image(0,0);
                                break; 
                    case 2 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8208);
                    uLCD.display_image(0,0);
                                break; 
                    case 3 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x80C3);
                    uLCD.display_image(0,0);
                                break; 
                    case 4 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x834D);
                    uLCD.display_image(0,0);
                                break; 
                }
            }
            else if(level > 16){
                switch(correctAns) {
                    case 1 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x84D3);
                    uLCD.display_image(0,0);
                                break; 
                    case 2 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8249);
                    uLCD.display_image(0,0);
                                break; 
                    case 3 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x8104);
                    uLCD.display_image(0,0);
                                break; 
                    case 4 : uLCD.media_init();
                    uLCD.set_sector_address(0x003B, 0x838E);
                    uLCD.display_image(0,0);
                                break; 
                }
            }
            wait(waitTime);
            uLCD.cls();
            phase = 4;
        } else if (phase == 4) {
            //Display guess
            uLCD.printf("\n\n\n\n\n\n\n Take your guess. \n\n\n\n\n\n\n\n");
            if (pbUp < 0.5) {
                ans = 1;
            } else if (pbLeft < 0.5) {
                ans = 2;
            } else if (pbDown < 0.5) {
                ans = 3;
            } else if (pbRight < 0.5) {
                ans = 4;
            }
            if (ans > 0) {
                if (ans == correctAns) {
                    isCorrect = true;
                } else {
                    isCorrect = false;
                }
                phase = 5;
            }
            
        } else if (phase == 5) {
            uLCD.cls();
            ans = -1;
            if (isCorrect) {
                //Display correct check mark
                uLCD.cls();
                uLCD.media_init();
                uLCD.set_sector_address(0x003B, 0x8514);
                uLCD.display_image(0,0);
                
                waver.play(sound_start);
                
                wait(1.0);
                uLCD.cls();
                
            } else {
                //Display incorrect x
                uLCD.cls();
                uLCD.media_init();
                uLCD.set_sector_address(0x003B, 0x8555);
                uLCD.display_image(0,0);
                wait(2.0);
                uLCD.cls();
                lost = true;
            }
            score = level - 1;
            level++;
            ans = -1;
            correctAns = -1;
            if (lost) {
                phase = 6;
            } else {
                phase = 2;
            }
        } else if (phase == 6) {
            if(score > highScores[0]){
                highScores[0] = score;
                bubbleSort(highScores,10);
            }
            if(score >= highScores[9]){
                uLCD.cls();
                uLCD.printf("\n\n\n\n\n\n\n New record of %D! ", score);
            }
            else{
                uLCD.cls();
                uLCD.printf("\n\n\n\n\n\n\n    Score: %D    ", score);
            }
            wait(5.0);
            level = 1;
            phase = 1;
            score = 0;
            lost = false;
            waitTime = 1.0;
            instruction = 0;
            homepage = 0;
        } else if (phase == 7){
            if(flag == 0){
                uLCD.printf("\n   High  Scores   \n");
                for(int i = 9; i > -1; i--){
                    uLCD.printf("%2d. %2d\n",(10-i),highScores[i]); 
                } 
                flag = 1;
            }
            if((pbUp < 0.5) || (pbDown < 0.5) || (pbLeft < 0.5) || (pbRight < 0.5)){
                phase = 1;
                homepage = 0;
                flag = 0;    
            }  
        } else if (phase == 8){
            uLCD.media_init();
            uLCD.set_sector_address(0x003B, 0x871C);
            uLCD.display_image(0,0);
            if((pbUp < 0.5) || (pbDown < 0.5) || (pbLeft < 0.5) || (pbRight < 0.5)){
                phase = 1;
                homepage = 0;    
            } 
        }
    fclose(sound_start);
    }
}

Import programlandolt

mBed implementation of the Landolt-C vision test. The main purpose of this game is to achieve the best score possible. This is done by successfully completing each level. In each level, the player is shown a Landolt-C for a short amount of time, oriented randomly upwards, downwards, leftwards or rightwards. The player is then prompted to input the orientation of the Landolt-C using the pushbuttons. If the user does this correctly, he or she is awarded one point. The game repeats this process at a higher difficulty each time by reducing the size of the Landolt-C and the time it is displayed.


Please log in to post comments.