// Lösungen zu "Richard Kaiser: C++ mit dem Borland C++Builder 2007", ISBN: 978-3-540-69575-2
// Copyright Richard Kaiser, 2007. http://www.rkaiser.de. All rights reserved.
// Diese Quelltexte dürfen in eigenen Programmen verwendet werden, wenn sie einen Hinweis auf die Quelle (die ersten beiden Zeilen) enthalten. In keinem Fall wird eine Haftung für direkte, indirekte, zufällige oder Folgeschäden übernommen, die sich aus der Nutzung ergeben.
// It is permitted to use this source text in programs of your own, provided that it contains a reference to the source (the first two lines above). All liabilities for use of the code are disclaimed.

//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop

#include "StringU.h"
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

#include "..\..\CppUtils\TestUtils.h"

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
#ifdef _DEBUG
bool test_All(); // Prototyp
initTestUtils();
testUtilsSummary(Memo1, test_All());
#endif
}



// --------------- Aufgaben 3.13 ---------------------------

// --------------- Aufgabe 1 -------------------------------

// Die folgenden Funktionen sind nur als Übung gedacht.
// Für praktische Anwendungen wird auf die zahlreichen Funktionen
// verwiesen, die man in des 'SysUtils' Unit findet.

// a)

struct Date_t {
  int day, month, year;
};
// Date instead of Date_t is ambigous (Sysutils::Date)

Date_t StringToDate(AnsiString date)
{
int p1=date.Pos('.');
AnsiString dstr  = date.SubString(1,p1-1);
date.Delete(1,p1);
int p2 = date.Pos('.');
AnsiString mstr  = date.SubString(1,p2-1);
AnsiString ystr  = date.SubString(p2+1,date.Length()-p2+1);
Date_t d;
d.day=StrToIntDef(dstr,-1);
d.month=StrToIntDef(mstr,-1);
d.year=StrToIntDef(ystr,-1);
if ((d.day==-1) || (d.month==-1) || (d.year==-1))
  {
    d.day=-1;
    d.month=-1;
    d.year=-1;
  }
return d;
}

bool assertEqual(Date_t f, Date_t s, AnsiString msg,
                                            TCustomMemo* Memo=Form1->Memo1)
{
return assertTrue((f.day==s.day) && (f.month==s.month) && (f.year==s.year),
                  msg, Memo);
}

bool test_one_date(AnsiString s, int day, int month, int year)
{
Date_t d1=StringToDate(s);
Date_t d2={day,month,year};
return assertEqual(d1,d2,"test_one_date: "+s);
}

bool test_StringToDate()
{
bool result = true;
Date_t t1;
// teste alle üblichen Kombinationen
// Jahr zweistellig, Tag und Monat einstellig und zweistellig
if (!test_one_date("1.2.07",1,2,7)) result=false;
if (!test_one_date("12.3.07",12,3,7)) result=false;
if (!test_one_date("1.12.07",1,12,7)) result=false;
if (!test_one_date("17.18.07",17,18,7)) result=false;

// Jahr vierstellig, Tag und Monat einstellig und zweistellig
if (!test_one_date("1.2.1920",1,2,1920)) result=false;
if (!test_one_date("12.3.1920",12,3,1920)) result=false;
if (!test_one_date("1.12.1920",1,12,1920)) result=false;
if (!test_one_date("17.18.1920",17,18,1920)) result=false;

// Teste unzulässige Formate. Das Programm sollte nicht abstürzen
//                            und -1 zurückgeben:
if (!test_one_date("",   -1,-1,-1)) result=false;
if (!test_one_date(".",  -1,-1,-1)) result=false;
if (!test_one_date("1",  -1,-1,-1)) result=false;
if (!test_one_date("1.", -1,-1,-1)) result=false;
if (!test_one_date("1.2",-1,-1,-1)) result=false;
if (!test_one_date("..", -1,-1,-1)) result=false;
if (!test_one_date("...",-1,-1,-1)) result=false;
if (!test_one_date("abc",-1,-1,-1)) result=false;
if (!test_one_date("1. Dezember ",-1,-1,-1)) result=false;
return result;
}

void __fastcall TForm1::Button_3_13_1Click(TObject *Sender)
{
Date_t d=StringToDate(Edit1->Text);
Form1->Memo1->Lines->Add(Edit1->Text+": Tag="+IntToStr(d.day)
          +", Monat="+IntToStr(d.month)+", Jahr="+IntToStr(d.year));
}


// --------------- Aufgabe 2 -------------------------------

// Die Lösung zu dieser Aufgabe 2 ist das Projekt tel


// --------------- Aufgabe 3 -------------------------------

void __fastcall TForm1::Button_3_13_3Click(TObject *Sender)
{
Memo1->Font->Name="Courier";
double K=100;
// Currency K=StrToCurr(Form1->Edit1->Text); // bzw. K=100
for (int p=5; p<=15; p++)
  {
    // Currency z = K*p/100;
    double z = K*p/100;
    AnsiString s=Format("K=%8.2f p=%2d%% z=%7.2f",OPENARRAY(TVarRec,(K,p,z)));
    Memo1->Lines->Add(s);
  };
}


// --------------- Aufgabe 4 -------------------------------

AnsiString uintToBinaryAnsiString(unsigned int n)
{
AnsiString s;
for (int i=1; i<=8*sizeof(n); i++)
  {
    if (n%2==1) s = "1"+s;
    else s = "0"+s;
    n = n/2;
    //  Mit den folgenden Anweisungen funktioniert das auch für negative int-Argumente:
    // if (n&1==1) s = "1"+s;
    // else s = "0"+s;
    // n = n>>1;
  }
return s;
}

bool test_uintToBinaryAnsiString()
{
bool result = true;

if (!assertEqual(uintToBinaryAnsiString(0),
       "00000000000000000000000000000000","toBinAStr 0")) result=false;
if (!assertEqual(uintToBinaryAnsiString(1),
       "00000000000000000000000000000001", "toBinAStr 1")) result=false;
if (!assertEqual(uintToBinaryAnsiString(2),
       "00000000000000000000000000000010", "toBinAStr 2")) result=false;
if (!assertEqual(uintToBinaryAnsiString(3),
       "00000000000000000000000000000011", "toBinAStr 3")) result=false;
if (!assertEqual(uintToBinaryAnsiString(-1),
       "11111111111111111111111111111111", "toBinAStr -1")) result=false;
return result;
}

void __fastcall TForm1::Button_3_13_4Click(TObject *Sender)
{
for (int i=0; i<=8; i++)
  Memo1->Lines->Add(uintToBinaryAnsiString(i));
}


// --------------- Aufgabe 5 -------------------------------

int Max(int a, int b)
{
if (a>b) return a;
else return b;
}

AnsiString BigIntAdd(AnsiString a, AnsiString b)
{
AnsiString s;
int m=Max(a.Length(),b.Length());
int ue=0;
for (int i=1; i<=m; i++)
  {
    int ai,bi;
    if (i<=a.Length()) ai=a[a.Length()-i+1]-'0';
    else ai=0;
    if (i<=b.Length()) bi=b[b.Length()-i+1]-'0';
    else bi=0;
    int r=(ai+bi+ue)%10;
    ue=(ai+bi+ue)/10;
    AnsiString ziffer[10]={"0","1","2","3","4","5","6","7","8","9"};
    s=ziffer[r]+s;
  }
if (ue>0) s="1"+s;
return s;
}

bool test_BigIntAdd()
{
bool result=true;
if (!assertEqual(BigIntAdd("0", "0"),"0", "BigIntAdd: 0+0==0"))
  result=false;
if (!assertEqual(BigIntAdd("1", "1"),"2", "BigIntAdd: 1+1==2"))
  result=false;
if (!assertEqual(BigIntAdd("1", "2"),"3", "BigIntAdd: 1+2==3"))
  result=false;
if (!assertEqual(BigIntAdd("1", "9"),"10","BigIntAdd: 1+9==10"))
  result=false;
// Check random numbers:
for (int i=0; i<100; i++)
  {
    int op1=rand();
    int op2=rand();
    AnsiString op1s=IntToStr(op1);
    AnsiString op2s=IntToStr(op2);
    AnsiString s=IntToStr(op1+op2);
    if (!assertEqual(BigIntAdd(op1s,op2s),s,
      "BigIntAdd: "+op1s+"+"+op2s+"="+s)) result=false;
  }
return result;
}

void __fastcall TForm1::Button_3_13_5Click(TObject *Sender)
{
AnsiString b="1";
for (int i=1; i<=100; i++)
  {
    b=BigIntAdd(b,b);
    Memo1->Lines->Add(AnsiString("2^")+IntToStr(i)+"="+b);
  }
}


// --------------- Aufgabe 6 -------------------------------

AnsiString BigIntShiftLeft(AnsiString a)
{
return a+"0";
}

AnsiString BigIntShiftRight(AnsiString a)
{
return a.Delete(a.Length(),1);
}

bool BigIntNull(AnsiString a)
{ // setzt voraus, dass 0 nicht durch "00" o. ä. dargestellt wird
return (a=="0")||(a=="");
}

int LastDigit(AnsiString a)
{ // ergibt die letzte Ziffer eines Strings als Zahl
return a[a.Length()]-'0';
}

AnsiString ziffer[10]={"0","1","2","3","4","5","6","7","8","9"};

AnsiString BigIntMultByDigit(AnsiString a, int n)
{ // Multipliziert die String-Zahl a mit der int-Zahl n
AnsiString s;
int ue=0;
for (int i=1; i<=a.Length(); i++)
  {
    int ai=a[a.Length()-i+1]-'0';
    int r=(ai*n + ue)%10;
    ue=(ai*n + ue)/10;
    s=ziffer[r]+s;
  }
if (ue>0) s=ziffer[ue]+s;
return s;
}

AnsiString BigIntMult(AnsiString u, AnsiString v)
{
AnsiString z=""; // Null
AnsiString x=u,y=v;
// assert(z+x*y==u*v);
while (!BigIntNull(x)) // (x != 0)
  {
    // if (x&1) z = z + y;
    z=BigIntAdd(z,BigIntMultByDigit(y,LastDigit(x)));
    y=BigIntShiftLeft(y);  // y = y*2;
    x=BigIntShiftRight(x); // x = x/2;
  }
// assert(z+x*y==u*v && x==0)
if (z=="") z="0";
return z;
}

AnsiString fakultaet(int n)
{
AnsiString result="1";
for (int i=2; i<=n; i++)
  result=BigIntMult(result,IntToStr(i));
return result;
}

double double_fakultaet(int n)
{
double result=1;
for (int i=2; i<=n; i++)
  result=result*i;
return result;
}

bool test_BigIntMult()
{
bool result=true;
if (!assertEqual(BigIntMult("0", "0"),"0", "BigIntMult: 0*0==0"))
  result=false;
if (!assertEqual(BigIntMult("1", "1"),"1", "BigIntMult: 1*1==2"))
  result=false;
if (!assertEqual(BigIntMult("1", "2"),"2", "BigIntMult: 1*2==2"))
  result=false;
if (!assertEqual(BigIntMult("11", "11"),"121","BigIntMult: 11*11==121"))
  result=false;
// Check random numbers:
for (int i=0; i<100; i++)
  {
    int op1=rand();
    int op2=rand();
    AnsiString op1s=IntToStr(op1);
    AnsiString op2s=IntToStr(op2);
    AnsiString s=IntToStr(op1*op2);
    if (!assertEqual(BigIntMult(op1s,op2s),s,
      "BigIntMult: "+op1s+"+"+op2s+"="+s)) result=false;
  }
return result;
}

void __fastcall TForm1::Button_3_13_6Click(TObject *Sender)
{
for (int i=1; i<=45; i++)
  {
    Memo1->Lines->Add(IntToStr(i)+"!="+fakultaet(i));
    Memo1->Lines->Add(IntToStr(i)+"!="+double_fakultaet(i));
  }
}

// --------------- Aufgabe 7 -------------------------------

bool test_All()
{
bool result=true;
if (!test_StringToDate()) result=false;
if (!test_uintToBinaryAnsiString()) result=false;
if (!test_BigIntAdd()) result=false;
if (!test_BigIntMult()) result=false;
return result;
}


