// mondlandung_life.cc
// Gibt dem Spieler n sec Zeit, die Treibstoffmenge einzugeben
// Aufruf: ./a.out n    mit (1 <= n <= 9)
// Compilation: g++ mondlandung_life.cc -lncurses

#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <ncurses.h>
using namespace std;
#include <iostream>

#define A 1.62      /*   m/qsec Fallbeschleunigung Mond   */
#define G 9.81      /*   m/qsec Fallbeschleunigung Erde   */

class state {
  double v, h, f, a; 
         // Geschwindigkeit, Hoehe, Treibstoff-Vorrat, Beschleunigung
public:

  // Einzige Konstruktor-Funktion:
  state (double vv, double hh, double ff) {
    v = vv; h = hh; f = (ff >= 0) ? ff : -ff; a = 0.0;
  }

  // Einige Member-Funktionen:
  double height() { return h; }
  double fuel()   { return f; }

  state decel(double ff) {
    ff = (ff >= 0) ? ff : -ff ; // negativer Treibstoff-Verbrauch?? 
    if ( ff >= f ) ff = f;      // Vorrat verbraucht!
    f = f - ff;  a = ff - A;  h = h + v + a/2;  v = v + a;
    return *this;
  }

  void print() {
    if ( h > 0.0 )
      printw("%8.2lf %8.2lf %8.2lf %8.2lfg   ::  ", v, h, f, a/G);
    else {
      double v0 = -sqrt(v*v - 2*a*h); // Geschwindigkeit beim Aufprall
      if ( v0 <= -2.0 )	printw("\nCrash:\n");
      else 	        printw("\nLandung:\n");
      printw("%8.2lf %8.2lf %8.2lf %8.2lfg   ::  \n", v0, 0.0, f, a/G);
      printw("Aufprall entspricht einem Sturz aus %2.2lf m \
Hoehe auf die Erde.\n", v0*v0/(2*G) );
    }
  }
};  

double get_fuel(int);  // siehe unten

int main(int argc, char *argv[]) {
  double ff;
  int n = 1;  // Default-Verzoegerung

  state s = state(-106.0, 533.0, 140.0);

  // Initialisieren des "Screens":
  initscr(); 
  noecho(); 

  if (argc==2) 
    n = argv[1][0]-48;

  printw("Delay = %d sec\n", n);
  printw(" v (m/sec)   h (m)   f (l)       a     :: Treibstoff ?\n");

  while ( s.height() > 0.0 ) {
    ff = 0.0; 
    if ( s.fuel() > 0.0 ) {
      s.print();
      ff = get_fuel(n);
      printw("%7.2lf\n", ff);
    }
    s.decel(ff);
  }
  s.print();

  // Beenden des "Screens":
  printw("\nBeenden mit `Enter`.\n");
  printw("Aufruf mit n sec Verzoegerung fuer jede Eingabe:\n\t %s n \t (1 <= n <= 9)\n\n", argv[0]);
  refresh();
  nocbreak();
  getch();
  endwin();
  return 0;
}

// Die Eingabekontrolle geschieht mit der "ncurses"-Bibliothek.
// siehe `man ncurses`
// Die Funktionen halfdelay und getch leisten das Benoetigte, 
// siehe `man getch` und `man halfdelay`
// neben einigen anderen Funktionen:
// initscr, noecho, printw, refresh, nocbreak, endwin
//

// Die Funktion double get_fuel(int n)
// liest die "Treibstoffmenge" = zweistellige Dezimalzahl
// von der Tastatur und gibt sie als double zurueck
// wenn diese innerhalb von n sec eingegeben wird
// sonst wird 0.0 zureuckgegeben.

double get_fuel(int n) {  // n = Verzoegerung in sec
  double ff=0.0;
  char ch;
  halfdelay(10*n);
  // halfdelay(10*n) laesst getch() n Sekunden auf Eingabe
  // eines char warten und es ansonsten -1 zurueckgeben:
  // Hier werden zwei Dezimalziffern erwartet
  ch = getch();
  if (48 <= ch && ch <= 57) { // Liegt Dezimalziffer vor?
    ch -= 48;                 // Zahlenwert der Ziffer
    ff = (double) ch;         // nach double   
    halfdelay(5);             // Zweite Dezimale sofort eingeben!
    ch = getch();
    if (48 <= ch && ch <= 57) { // Liegt Dezimalziffer vor?
      ch -= 48;              // Zahlenwert der Ziffer
      ff = ff*10 + ch;       // zahlenwert der Eingabe
    }
  }
  return ff;
}
