#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

static void problem1(void) {
  puts("\nProblem 1") ;
  char *myName = "ECE 209 final exam tester" ;
  printf("  %s\n", myName) ;
}

#define PRINTINT(m) {cnum = 100; clet = 'C', cthd = 33.3 ; cstr = "C#" ; printf("  %-20s is %3d\n", #m, m); }
#define PRINTDBL(m) {cnum = 100; clet = 'C', cthd = 33.3 ; cstr = "C#" ; printf("  %-20s is %6.2f\n", #m, m); }

static void problem2(void) {
  int    cnum = 100 ;
  char   clet = 'C' ;  /* ASCII code for 'C' is 67 */
  double cthd =  33.3 ;
  char  *cstr = "C#" ;
  puts("\nProblem 2") ;
  PRINTINT(++cnum) ;
  PRINTINT(cnum++) ;
  PRINTINT(cnum *= 2) ;
  PRINTINT(cnum = 5) ;
  PRINTINT(--clet) ;
  PRINTINT(cnum = clet) ;
  PRINTDBL(cthd = 5) ;
  PRINTINT(&cstr[1] - &cstr[0]) ;
  PRINTINT(cstr[1]) ;
  PRINTINT(cstr[2]) ;
  PRINTINT(*cstr) ;
  PRINTINT(*cstr+1) ;
  PRINTINT((*cstr)+1) ;
  PRINTINT(*(cstr+1)) ;
  PRINTINT(strlen(cstr)+1) ;
  PRINTINT(strlen(cstr+1)) ;
  PRINTINT(! strcmp("ab", "a")) ;
  PRINTINT(*&clet) ;
  PRINTINT((int) 3.16) ;
  PRINTINT(1 + 2 * 3) ;
  PRINTINT(1 * 2 + 3) ;
  PRINTINT(3 % 2) ;
  PRINTINT(3 % 5) ;
  PRINTDBL(100000 * 0.0) ;
  PRINTDBL(1 * 3.0 / 2) ;
  PRINTINT(1 * 3 / 2) ;
  PRINTINT(1 / 2 * 3) ;
  PRINTDBL((int) 3.3 + 2.5) ;
  PRINTDBL((double) 3 / 2) ;
  PRINTINT(5 + 3) ;
  PRINTINT(5 && 3) ;
  PRINTINT(5 & 3) ;
  PRINTINT(5 || 3) ;
  PRINTINT(5 | 3) ;
  PRINTINT(5 == 3) ;
  PRINTINT(! 5 + 3) ;
  PRINTINT(5 > 4 > 3) ;
  PRINTINT(5 > 4 == 4 > 3) ;
  PRINTINT((4+1) && (3+2)==5) ;
  PRINTINT(1 ? 3 : 5) ;
}

static void problem3(void) {
  int i, j ;
  double x ;
  int loopcount ;

  puts("\nProblem 3") ;

  puts("  Loop 1") ;
  for (x=3.5; x<5.0; x = x + 0.6) {
    printf("%4.1f\n", x) ;
  }

  puts("  Loop 2") ;
  loopcount = 0 ;
  i=3 ;
  while (i) {
    i = -i ;
    printf("%d\n", i) ;
    if (++loopcount > 3) break ;
  }

  puts("  Loop 3") ;
  for (i=1, j=0; i<10; j += i, i += 2) {
    printf("%d\n", j) ;
  }

  puts("  Loop 3") ;
  i = 4 ;
  x = 6.0 ;
  while (i<5.5 && x > 5.5) {
    ++i ;
    x = x - 0.6 ;
    printf("%d, %4.1f\n", i, x) ;
  }
}

static void problem4(void) {
  int v1 ;
  int *v2 ;
  int **v3 ;
  const int *v4 ;
  int v5[7] ;
  int v6[3][5] ;

  v1 = 5 ;
  v1 = *v2 ;
  v2 = &v1 ;
  /* v2 = &5 ;            error:   invalid lvalue for &                      */
  v2 = v4 ;            /* warning: assignment discards qualifiers            */
  v2 = v5 ;
  v2 = v6[1] ;
  v3 = v2 ;            /* warning: assignment from incompatible pointer type */
  v3 = v6 ;            /* warning: assignment from incompatible pointer type */
  v4 = v2 ;
  /* *v4 = 5 ;            error:   read-only location                        */
  /* v5 = &v1 ;           error:   incompatible types                        */
}

void printCharN(char c, int n) {
    int i ;
    for(i=0; i<n; ++i) {
        putchar(c) ;
    }
}

void printBigY(int N) {
    if (N > 5 && N%2==1) {
        int i ;
        for (i=0; i<N/2; ++i) {
            printCharN('.', i) ;
            putchar('*') ;
            printCharN('.',N-2-2*i) ;
            putchar('*') ;
            printCharN('.', i) ;
            putchar('\n') ;
        }
        for (; i<N; ++i) {
            printCharN('.', N/2) ;
            putchar('*') ;
            printCharN('.', N/2) ;
            putchar('\n') ;
        }
    }
}

static void Problem5(void) {
    puts("\nProblem 5") ;
    puts("Calling printBigY(23)") ;
    printBigY(23) ;
    puts("Calling printBigY(14)") ;
    printBigY(14) ;
    puts("Calling printBigY(7)") ;
    printBigY(7) ;
}

int uniqueValues(int *V, int N) {
    /* Dumb, but short */
    int uniqueCount = 0 ;
    int i, j ;
    for (i=0; i<N; ++i) {
        int foundsomeonelikemewhocameearlier = 0 ;
        for (j=0; j<i && !foundsomeonelikemewhocameearlier; ++j) {
            if (V[i] == V[j]) {
                foundsomeonelikemewhocameearlier = 1 ;
            }
        }
        if (!foundsomeonelikemewhocameearlier) {
            ++uniqueCount ;
        }
    }
    return uniqueCount ;
}

void Problem6function(int Dice[6]) {
    if (uniqueValues(Dice, 6) == 1 && Dice[0] >= 1 && Dice[0] <= 6) {
        puts("legit Yahtzee") ;
    }
}

static void Problem6(void) {
    int i ;
    int DiceSet[][6] = {
        {1, 1, 3, 3, 4, 4},
        {3, 3, 3, 3, 3, 3},
        {0, 0, 0, 0, 0, 0},
        {2, 2, 2, 3, 2, 2}
    } ;
    puts("\nProblem 6") ;
    for (i = 0; i < sizeof(DiceSet)/sizeof(DiceSet[0]); ++i) {
        int *d = DiceSet[i] ;
        printf("Testing with [%d,%d,%d,%d,%d,%d]\n",
                d[0], d[1], d[2], d[3], d[4], d[5]) ;
        Problem6function(d) ;
    }
}

/* Problem 7  */
int NumberSpaceyLines(FILE *inFile) {
    int spaceyCount = 0 ;
    int seenNonWhiteSpace = 0 ;
    int nextChar ;
    while ((nextChar=fgetc(inFile)) != EOF ) {
        if (nextChar == '\n') {
            if (! seenNonWhiteSpace) {
                ++spaceyCount ;
            }
            seenNonWhiteSpace = 0 ;
        }
        else if (! isspace(nextChar)) {
            seenNonWhiteSpace = 1 ;
        }
    }
    return spaceyCount ;
}

int pseudoMainProblem8(int argc, char **argv) {
    FILE *inFile ;
    if (argc != 2) {
        printf("Wrong number of arguments\n") ;
        return (EXIT_FAILURE) ;
    }
    if ((inFile = fopen(argv[1],  "r")) == NULL) {
        printf("Unable to open %s for reading\n", argv[1]) ;
        return (EXIT_FAILURE) ;
    }
    printf("There are %d blank lines in the file %s.\n",
            NumberSpaceyLines(inFile), argv[1]) ;
    fclose(inFile) ;
    return (EXIT_SUCCESS) ;
}

static void Problem8(void) {
  int i ;
  char *fileContents[] = {
    "\n should be two \n  \n", 
    "this is zero the next is three\n" ,
    "\n    \n  \n", 
    "  how \n  about   \n none \n" 
  } ;
  char *fileName = "PROB8.TXT" ;
  char *argv[] = {"problem8", fileName} ;
  puts("\nProblem 8") ;
  remove(fileName) ;
  puts("testing on missing file") ;
  pseudoMainProblem8(2, argv) ;
  for(i=0; i<sizeof(fileContents)/sizeof(fileContents[0]); ++i) {
    FILE *tFile = fopen(fileName, "w") ;
    fputs(fileContents[i], tFile) ;
    fclose(tFile) ;
    puts("\ntesting on input\n") ;    
    fputs(fileContents[i], stdout) ;
    pseudoMainProblem8(2, argv) ;
    remove(fileName) ;
  }
}

static void Problem9(void) {
    int V[75] ;
    int H[31] ;
    int i ;

    puts("\nProblem 9") ;
    /* Generate a random array -- not part of the problem */
    for (i=0; i<75; ++i) {
        V[i] = rand() % 31 ;
    }

    /* Create the histogram */
    for (i=0; i<31; ++i) {
        H[i] = 0 ;
    }
    for (i=0; i<75; ++i) {
        ++H[V[i]] ;
    }

    /* Print the stem and leaf */
    for (i=0; i<=30; i += 10) {
        int j, k ;
        printf("%2d: ", i) ;
        for (j=0; j<10 && (i+j)<=30; ++j) {
            for (k=0; k<H[i+j]; ++k) {
                printf("%2d", j) ;
            }
        }
        putchar('\n') ;
    }
}

struct LetterNode {
    char               value ;
    struct LetterNode *next ;
};
typedef struct LetterNode *LetterObj ;

/* Problem 10      */
LetterObj AllocateLetterNode(char L) {
    LetterObj LN = (LetterObj) malloc(sizeof(struct LetterNode)) ;
    if (LN == NULL) {
        return NULL ;
    }
    LN->value = L ;
    return LN ;
}

/* Problem 11     */
struct LetterLollipopNode {
    LetterObj startPoint ;
    LetterObj cycleEntry ;
};
typedef struct LetterLollipopNode *LetterLollipop ;

LetterLollipop Problem12(void) {
    LetterObj A = AllocateLetterNode('A') ;
    LetterObj E = AllocateLetterNode('E') ;
    LetterObj I = AllocateLetterNode('I') ;
    LetterObj O = AllocateLetterNode('O') ;
    LetterObj U = AllocateLetterNode('U') ;
    LetterLollipop lolli = malloc(sizeof(struct LetterLollipopNode)) ;
    if (A==NULL || E == NULL || I == NULL ||
            O == NULL || U == NULL || lolli == NULL) {
        return NULL ;
    }
    A->next = E ;
    E->next = I ;
    I->next = O ;
    O->next = U ;
    U->next = I ;
    lolli->startPoint = A ;
    lolli->cycleEntry = I ;
    return lolli ;
}

int CountNodes(LetterLollipop P) {
    int count = 0 ;
    LetterObj l = P->startPoint ;
    while(l != P->cycleEntry) {
        ++count ;
        l = l->next ;
    }
    l = l->next ;
    ++count ;
    while(l != P->cycleEntry) {
        ++count ;
        l = l->next ;
    }
    return count ;
}

static void Problem13(LetterLollipop l) {
    puts("\nProblem 13") ;
    printf("Size of the lollipop is %d\n", CountNodes(l)) ;
}

void final(void) {
  problem1() ;
  problem2() ;
  problem3() ;
  Problem5() ;
  Problem6() ;
  Problem8() ;
  Problem9() ;
  LetterLollipop p12 = Problem12() ;
  Problem13(p12) ;
}

int main(int argc, char *argv[]) {
  final() ;
  return (EXIT_SUCCESS) ;
}
