/*=======================
  *    Franz Kohnle     *
  *      Racer2007      *
  *                     *
  *      16.03.2007     *
  ======================*/
#include <stdio.h>
#include <stdlib.h>

struct Highscore{
    int Punkte;
    char Name[20];
};

void Ueberschrift();
char Menue();
void RandAusgeben(int Breite);
void StrasseAusgeben(int Breite);
int Spiel();
void Information();
void LeitplankeAusgaben(int Richtung);
void Pause();
void SpielEnde(int Zaehler,struct Highscore* liste);
void HighScoresAnzeigen(struct Highscore* liste);
void warten(int Zeit);

int main(){
    char Taste;
    int Zaehler;
    int i;
    struct Highscore liste[5];
    FILE* pDatei;
    char Dateipfad[]="c:\\RacerHighScores.racer";


    // ***** Zufallsgenerator mischen *****
    srand(time(0));

    // Highscoreliste laden
    pDatei = fopen(Dateipfad,"r");
    if(pDatei!=NULL){
        fread(liste, sizeof(struct Highscore), 5, pDatei);
        fclose(pDatei);
    }
    else{
        // Highscores auf 0, Namen auf ---
        for(i=0; i<=4; i++){
            liste[i].Punkte=0;
            strcpy(liste[i].Name,"---");
        }
    }

    do{
        Taste=Menue();
        switch(Taste){
            case 'i':
                Ueberschrift();
                Information();
                break;
            case 'h':
                // Highscoreliste anzeigen
                HighScoresAnzeigen(liste);
                break;
            case 's':
                // neues Spiel
                Zaehler = Spiel();
                // Spiel beendet ( crash / 'e')
                // Highscoreliste anzeigen
                SpielEnde(Zaehler,liste);
                HighScoresAnzeigen(liste);
                break;
            case 'e':
                // Programm beenden
                // Highscoreliste speichern
                pDatei = fopen(Dateipfad,"w");
                if(pDatei!=NULL){
                    fwrite(liste, sizeof(struct Highscore), 5, pDatei);
                    fclose(pDatei);
                }
                else{
                    printf("Leider konnten die Highscores nicht gespeichert werden.");
                    getch();
                }
                break;
        }
    }while(Taste!='e');
    return 0;
}

void Ueberschrift(){
    system("cls");
    printf("\n\t**************************************\n");
    printf("\t*          R A C E R  2 0 0 7        *\n");
    printf("\t**************************************\n");
}

void RandAusgeben(int Breite){
    int i;
    for(i=1; i<=Breite;i++)
        printf("*");
}

void StrasseAusgeben(int Breite){
    int i;
    for(i=1; i<=Breite;i++)
        printf(" ");
}

int Spiel(){
    // **** Variablendeklaration *****
    char Taste='a';
    int ende = 0; // 1: Ende
    int i,j;
    int Zufall;
    int Level=0;
    int Richtung=0; // -1 Strasse nach links, 0: gerade, 1: nach rechts

    int Zaehler=0; // Anzahl der Zeilen

    int Gesamtbreite = 50; // Gesamt Spielfeld
    int Strassenbreite = 25; // Breite der Straße
    int linkerStrasse; // linke Straßenseite
    int rechterStrasse; // rechte Straßenseite
    int linkerRand=12; // linkerer Straßenrand
    int rechterRand; // rechter Straßenrand
    int Autoposition=25; // Abstand des Auto von linken Spielfeldrand

    // ***** Variablen neu berechnen *****
    rechterRand = Gesamtbreite - Strassenbreite - linkerRand;
    linkerStrasse = Autoposition - linkerRand;
    rechterStrasse = Strassenbreite - linkerStrasse - 1;

    do{
        // Zeilenzaehler hochzaehlen
        Zaehler++;

        // neues Level alle 100 Zeilen
        Level = Zaehler/50+1;

        // Strassenbreite je nach Level ändern
        Strassenbreite = 26 - Level;

        // *** Ausgabe einer Zeile ***
        // Zeilenumbruch
        printf("\n");
        // linker Rand
        RandAusgeben(linkerRand);
        // linke Leitplanke
        LeitplankeAusgaben(Richtung);
        // linke  Strassenteil
        StrasseAusgeben(linkerStrasse);
        // Auto
        printf("%c",1);
        // rechte  Strassenteil
        StrasseAusgeben(rechterStrasse);
        // rechte Leitplanke
        LeitplankeAusgaben(Richtung);
        // rechter Rand
        RandAusgeben(rechterRand);
        // Zeilenzaehler + Level
        printf(" Level: %d, Score: %d",Level,Zaehler);

        // *** Warten ***
        switch(Level){
            case 1:
                warten(15000);
                break;
            case 2:
                warten(10000);
                break;
            case 3:
                warten(9000);
                break;
            case 4:
                warten(8000);
                break;
            case 5:
                warten(7000);
                break;
            default:
                warten(5000);
        }

        // **** Tastatur einlesen ****
        if(kbhit()){ // Nur, Falls Taste gedrueckt
            Taste=getch();
            // Autoposition neu berechnen
            switch(Taste)
            {
                case 'a': // Auto nach links
                    Autoposition--;
                    break;
                case 'd': // Auto nach rechts
                    Autoposition++;
                    break;
                case 'p': // Pause
                    Pause();
                    break;
                case 'e': // Ende
                    ende=1;
            }
        }

        // **** Strasse neu berechnen ****
        // ca. jedes 5.mal Richtung aendern
         Zufall = rand()%5;
        if(Zufall==0)
        {
            // Richtung aendern
            Richtung = rand()%3-1;
        }
        //linke Rand neu berechnen
        linkerRand += Richtung;
        // Strasse linke angestossen ???
        if(linkerRand<1)
        {
            Richtung=0;
            linkerRand=1;
        }
        // Strasse rechts angestossen ???
        rechterRand = Gesamtbreite - Strassenbreite - linkerRand;
        if(rechterRand<1)
        {
            Richtung=0;
            rechterRand=1;
            linkerRand = Gesamtbreite -Strassenbreite - rechterRand;
        }

        // ***** Variablen neu berechnen *****
        rechterRand = Gesamtbreite - Strassenbreite - linkerRand;
        linkerStrasse = Autoposition - linkerRand;
        rechterStrasse = Strassenbreite - linkerStrasse - 1;

        // ***** CRASH ? *****
        if(rechterStrasse<0 || linkerStrasse<0)
        {
            // Ende
            ende=1;
        }
    }while(ende==0); // Ende einer Zeilenausgabe
    // Zeilenzaehler zurueckgeben
    return Zaehler;
}

char Menue(){
    char Taste;

    // *** Bildschirmloeschen und Menue ausgeben ***
    Ueberschrift();
    printf("\n");
    printf("\t(i) Information\n");
    printf("\t(h) Highscoreliste anzeigen\n");
    printf("\t(s) Spiel starten\n");
    printf("\t(e) Spiel beenden\n");

    // *** Taste einlesen ****
    do{
        Taste = getch();
    }while(Taste!='i' && Taste!='h' && Taste!='s' && Taste!='e');

    return Taste;
}

void Information(){
    printf("\n\tSteuerung mit 'a' und 'd'");
    printf("\n\n\tMit beliebiger Taste zurueck in's Menue.");
    getch();
}

void LeitplankeAusgaben(int Richtung){
    switch(Richtung)
    {
        case -1:
            printf("/");
            break;
        case 0:
            printf("|");
            break;
        case 1:
            printf("\\");
            break;
    }
}

void Pause(){
    char Taste;
    // Ausgabe der Pausenmeldung
    printf("\n\n\t++++++++++++++++++++\n");
    printf("\t+    P A U S E     +\n");
    printf("\t+  Weiter mit 'p'  +\n");
    printf("\t++++++++++++++++++++\n");
    // Warten, bis 'p' gedrueckt
    do{
        Taste=getch();
    }while(Taste!='p');
    system("cls");
}

void SpielEnde(int Zaehler, struct Highscore* liste){
    // Zaehler: aktueller Score
    // liste: Liste mit 5 Highscores und Namen

    char Taste;
    int i,j;
    int highnichtgeschafft=1; // 1=nicht geschafft, 0=geschafft

    // Ausgabe
    system("cls");
    printf("\n\n\t********************");
    printf("\n\t* G A M E  O V E R *");
    printf("\n\t********************");
    // aktuellen Score einssortieren
    for(i=0; i<=4; i++){
        if(Zaehler>liste[i].Punkte){
            // in die Highscoreliste geschafft
            highnichtgeschafft=0;

            // Rest nach unten rutschen
            for(j=3; j>=i; j--){
                // Scores
                liste[j+1].Punkte = liste[j].Punkte;
                // Namen
                strcpy(liste[j+1].Name, liste[j].Name);
            }
            // Zaehler einsortieren
            liste[i].Punkte = Zaehler;
            // Score ausgeben
            printf("\n\n\tHerzlichen Glueckwunsch, Sie haben %d Punkte erreicht.", Zaehler);
            printf("\n\tDamit haben Sie es in die Top-5 geschafft!");
            // Auf Enter-Taste warten
            printf("\n\tBitte 'Enter' druecken.");
            do{
                Taste=getch();
            }while(Taste!=13);
            // Name einlesen
            printf("\n\n\tBitte geben Sie Ihren Namen ein: ");
            gets(liste[i].Name);

            // aus aeusserer for-Schleife springen
            break;
        }
    }

    if(highnichtgeschafft==1){
        printf(" \n\n\tDas war schwach. Sie haben nur %d Punkte erreicht.", Zaehler);
        printf(" \n\tDas ist leider zu wenig fuer die Top-5. Lusche!");
    }
}

void HighScoresAnzeigen(struct Highscore* liste){
    int i;
    char Taste;

    // Ausgabe
    printf("\n\n\tHighscores");
    printf("\n\t==========");
    for(i=0; i<=4; i++)
        printf("\n\t%d. %s Score: %d Level: %d",
           i+1,liste[i].Name,liste[i].Punkte,liste[i].Punkte/50+1);

    // Auf Tastendruck warten
    printf("\n\n\tMit 'Enter' zurueck in's Menue.");
    do{
        Taste=getch();
    }while(Taste!=13);
}

void warten(int Zeit){
    int i,j;
    for (i=1;i<=Zeit;i++)
        for (j=1;j<=10000;j++)
            ;
}



























