/* The Punnetizer, version 1.2.
** Copyright (c) 1998,2000 Flaming Custard International.
**
** This program is licensed to you under the terms of the
** GNU General Public License, version 2.0 or greater.
**
** The official version of this program is available at
** http://quadium.net/
**
** Contact vsync@quadium.net for more information.
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void getStarted(void);
void showPro(void);
void showParms(void);
void showAd(void);
void badThing(int, char *);
void makeHeaders(void);
void makeSquare(void);
void calcCell(unsigned long, unsigned long);
void printSet(unsigned long);
void addTally(unsigned long);
void printTallies(void);
void printGeno(unsigned long bits);
void printPheno(unsigned long bits);
void printRatio(int, int);
void chars(int, char);

struct arec {
  char theletter;
  char dominant[80];
  char recessive[80];
  int howtoM, howtoF;		/* What thingies do the parents have? */
				/* (see the input section for details) */
};

typedef struct arec aRec;

typedef int bRec;

aRec *it;
bRec *them, *pheno;
char title[80], dc;		/* 'dc' is the delimiting character */
				/* for tab- and comma-delimited files */
int howmany, outType;
unsigned long *top, *side;
FILE *of;

int main(void) {
  getStarted();
  showPro();
  showParms();
  makeHeaders();
  makeSquare();
  printTallies();
  showAd();
  fclose(of);
  return 0;
}

void getStarted(void) {
  int num = 10, i;
  char c, s[80];

  /* Print a stupid welcome message */

  printf("Welcome to The Punnetizer v1.1, brought to you by Flaming Custard International.\n\n");

  /* Get output type */
  do {
    printf("Please select the type of output you would like:\n");
    printf("\t0 - ASCII text\n");
    printf("\t1 - HTML\n");
    printf("\t2 - LaTeX\n");
    printf("\t3 - Tab-delimited\n");
    printf("   Your choice [0]? ");
    fgets(s, 79, stdin);
    outType = num = atoi(s);
    if (num == 4)
      dc = ',';
    else
      dc = '\t';
  } while (num < 0 || num > 3);
  putchar('\n');

  /* Get a file name? */
  do {
    printf("What file do you want the output in? ");
    fgets(s, 79, stdin);
    s[strlen(s) - 1] = 0;
  } while (*s == '\r' || *s == '\n');
  of = fopen(s, "w");
  if (of == NULL)
    badThing(10, "Error opening output file.");
  putchar('\n');

  /* What is the title? */
  do {
    printf("What is the title of this document? ");
    fgets(s, 79, stdin);
    s[strlen(s) - 1] = 0;
    strcpy(title, s);
  } while (*s == '\r' || *s == '\n');
  putchar('\n');

  /* Ask for how many traits */
  printf("How many traits would you like? This program can handle up to ");
  printf("13 traits,\ndepending on your operating system and free memory.\n");
  do {
    printf("Number of traits [1]? ");
    fgets(s, 79, stdin);
    num = atoi(s);
    if (*s == '\r' || *s == '\n')
      num = 1;
    if (!num) {
      printf("Zero is a stupid number; using one instead...\n");
      howmany = 1;
    } else
      howmany = num;
  } while (num > 13);

  /* Allocate our memory */

  it = calloc(sizeof(aRec), num);
  if (it == NULL)
    badThing(1, "Error allocating memory for trait database.");

  /* Note: The following is a worst-case memory allocation, grabbing */
  /* all the memory that might possibly be used.  It gets enough */
  /* memory for if each box produced a separate result, and all traits */
  /* are heterozygous for both parents.  While this doesn't matter much */
  /* for, say, a trihybrid cross, it starts to matter with more traits. */
  /* We should fix this someday. */
  
  them = calloc(sizeof(bRec), 1<<(num<<1));
  if (them == NULL)
    badThing(2, "Error allocating memory for tally database.");

  pheno = calloc(sizeof(bRec), 1<<(num<<1));
  if (pheno == NULL)
    badThing(2, "Error allocating memory for phenotype analysis.");
  
  /* Now we get the memory to keep track of the headings. */
  
  top = calloc(sizeof(unsigned long), 1<<num);
  side = calloc(sizeof(unsigned long), 1<<num);

  if (top == NULL || side == NULL)
    badThing(3, "Error allocating memory for headings.");
  
  /* Get the actual traits */
  printf("\nNow we are going to get information on each of the traits.\n");

  for (i = 0; i < howmany; i++) {
    do {
      printf("%d: Letter for trait? ", i+1);
      fgets(s, 3, stdin);
      c = tolower(*s);
      it[i].theletter = c;
    } while (*s == '\r' || *s == '\n');

    do {
      printf("%d: Dominant characteristic? ", i+1);
      fgets(s, 79, stdin);
      s[strlen(s) - 1] = 0;
      strcpy(it[i].dominant, s);
    } while (*s == '\r' || *s == '\n');

    do {
      printf("%d: Recessive characteristic? ", i+1);
      fgets(s, 79, stdin);
      s[strlen(s) - 1] = 0;
      strcpy(it[i].recessive, s);
    } while (*s == '\r' || *s == '\n');

    do {
      printf("%d: What does the male parent have?\n", i+1);
      printf("\t1 - Homozygous dominant\n");
      printf("\t2 - Homozygous recessive\n");
      printf("\t3 - Heterozygous\n");
      printf("   Your choice? ");
      fgets(s, 79, stdin);
      it[i].howtoM = num = atoi(s);
    } while (num < 1 || num > 3);
    
    do {
      printf("%d: What does the female parent have?\n", i+1);
      printf("\t1 - Homozygous dominant\n");
      printf("\t2 - Homozygous recessive\n");
      printf("\t3 - Heterozygous\n");
      printf("   Your choice? ");
      fgets(s, 79, stdin);
      it[i].howtoF = num = atoi(s);
    } while (num < 1 || num > 3);
    
    putchar('\n');
  }
}

void showPro(void) {
  int i;
  
  switch (outType) {
  case 0:			/* ASCII text */
    fprintf(of, "%s\n", title);
    for (i = 1; i <= strlen(title); i++)
      putc('-', of);
    fprintf(of, "\n\n");

    break;
  case 1:			/* HTML */
    fprintf(of,
	    "<html>\n<head><title>%s</title></head>\n<body>\n<h1>%s</h1>\n",
	    title, title);
    break;
  case 2:			/* LaTeX */
    fprintf(of, "\\documentclass{article}\n\\title{%s}\n", title);
    fprintf(of, "\\usepackage{fullpage}\n\\begin{document}\n\\maketitle\n\n");
    break;
  case 3:
  case 4:
    putc('\n', of);
    for (i = 1; i <= 3; i++)
      putc(dc, of);
    fprintf(of, "%s\n\n", title);
    break;
  }
}

void showParms(void) {
  int i;

  switch (outType) {
  case 0:			/* ASCII text */
    fprintf(of, "Trait Characteristics:\n\n");
    for (i = 0; i < howmany; i++) {
      fprintf(of, "%c%c:\t", toupper(it[i].theletter), it[i].theletter);
      fprintf(of, "%s/%s\n\t   ", it[i].dominant, it[i].recessive);
      switch(it[i].howtoM) {
      case 1: fprintf(of, "homozygous dominant male, ");
	break;
      case 2: fprintf(of, "homozygous recessive male, ");
	break;
      case 3: fprintf(of, "heterozygous male, ");
	break;
      }
      switch(it[i].howtoF) {
      case 1: fprintf(of, "homozygous dominant female\n");
	break;
      case 2: fprintf(of, "homozygous recessive female\n");
	break;
      case 3: fprintf(of, "heterozygous female\n");
	break;
      }
    }
    break;
  case 1:			/* HTML */
    fprintf(of, "<h2>Trait Characteristics</h2>\n");
    fprintf(of, "<table border=3 cellpadding=3 align=center>\n");
    for (i = 0; i < howmany; i++) {
      fprintf(of, "<tr><td>%c%c</td>", toupper(it[i].theletter),
	      it[i].theletter);
      fprintf(of, "<td>%s/%s</td><td>", it[i].dominant, it[i].recessive);
      switch(it[i].howtoM) {
      case 1: fprintf(of, "homozygous dominant male, ");
	break;
      case 2: fprintf(of, "homozygous recessive male, ");
	break;
      case 3: fprintf(of, "heterozygous male, ");
	break;
      }
      switch(it[i].howtoF) {
      case 1: fprintf(of, "homozygous dominant female");
	break;
      case 2: fprintf(of, "homozygous recessive female");
	break;
      case 3: fprintf(of, "heterozygous female");
	break;
      }
      fprintf(of, "</td></tr>\n");
    }
    fprintf(of, "</table>\n");
    break;
  case 2:			/* LaTeX */
    fprintf(of, "\\section*{Trait Characteristics}\n");
    fprintf(of, "\\hfil\\begin{tabular}{|l|l|l|}\n");
    for (i = 0; i < howmany; i++) {
      fprintf(of, "\\hline\n");
      fprintf(of, "%c%c & ", toupper(it[i].theletter), it[i].theletter);
      fprintf(of, "%s/%s & ", it[i].dominant, it[i].recessive);
      switch(it[i].howtoM) {
      case 1: fprintf(of, "homozygous dominant male, ");
	break;
      case 2: fprintf(of, "homozygous recessive male, ");
	break;
      case 3: fprintf(of, "heterozygous male, ");
	break;
      }
      switch(it[i].howtoF) {
      case 1: fprintf(of, "homozygous dominant female");
	break;
      case 2: fprintf(of, "homozygous recessive female");
	break;
      case 3: fprintf(of, "heterozygous female");
	break;
      }
      fprintf(of, "\\\\\n");
    }
    fprintf(of, "\\hline\n");
    fprintf(of, "\\end{tabular}\\medskip\n\n");
    break;
  case 3:
  case 4:
    fprintf(of, "Trait Characteristics:\n\n");
    for (i = 0; i < howmany; i++) {
      fprintf(of, "%c%c%c", toupper(it[i].theletter), it[i].theletter, dc);
      fprintf(of, "%s/%s%c", it[i].dominant, it[i].recessive, dc);
      switch(it[i].howtoM) {
      case 1: fprintf(of, "homozygous dominant male, ");
	break;
      case 2: fprintf(of, "homozygous recessive male, ");
	break;
      case 3: fprintf(of, "heterozygous male, ");
	break;
      }
      switch(it[i].howtoF) {
      case 1: fprintf(of, "homozygous dominant female\n");
	break;
      case 2: fprintf(of, "homozygous recessive female\n");
	break;
      case 3: fprintf(of, "heterozygous female\n");
	break;
      }
    }
    break;
  }
}

void showAd(void) {
  int i;
  
  switch (outType) {
  case 0:			/* ASCII text */
    putc('\n', of);
    for (i = 1; i <= 60; i++)
      putc('-', of);
    putc('\n', of);
    fprintf(of, "This document produced by The Punnetizer,\navailable at ");
    fprintf(of, "http://quadium.net/\n");
    break;
  case 1:			/* HTML */
    fprintf(of, "<p><hr>\n<address>\n");
    fprintf(of, "This document produced by ");
    fprintf(of, "<a href=\"http://quadium.net/\">");
    fprintf(of, "The Punnetizer</a>, created by ");
    fprintf(of, "Flaming Custard International.\n");
    fprintf(of, "</address></body></html>\n");
    break;
  case 2:			/* LaTeX */
    fprintf(of, "\n\n\\bigskip\\hrule\\medskip\n\n\\noindent ");
    fprintf(of, "\\emph{This document produced by The Punnetizer,\navailable");
    fprintf(of, " at \\underline{http://quadium.net/}}\n");
    fprintf(of, "\\end{document}\n");
    break;
  case 3:
  case 4:
    fprintf(of, "\n\n%s",
	    "This document produced by The Punnetizer, \navailable at ");
    fprintf(of, "http://quadium.net/");
    break;
  }
}

void badThing(int code, char *es) {
  fprintf(stderr, es);
  putc('\n', stderr);
  exit(code);
}

void makeHeaders(void) {

  int i, j, t, temp;
  
  /* We're gonna loop through and figure out what the top looks like. */

  t = 1<<howmany;
  for (i = 0; i < t; i++) {
    top[i] = t - (i + 1);
    for (j = 0; j < howmany; j++) {
      switch (it[j].howtoM) {
      case 1: top[i] |= 1<<j;
	break;
      case 2: top[i] &= ~(1<<j);
	break;
      }
    }
  }

  /* Now the side... */

  for (i = 0; i < t; i++) {
    side[i] = t - (i + 1);
    for (j = 0; j < howmany; j++) {
      switch (it[j].howtoF) {
      case 1: side[i] |= 1<<j;
	break;
      case 2: side[i] &= ~(1<<j);
	break;
      }
    }
  }
}

void makeSquare(void) {

  int i, j, k, t, temp, temp2;

  switch (outType) {
  case 0:			/* ASCII text */
    t = 1<<howmany;
    fprintf(of, "\nPunnet Square:\n\n");
    chars(howmany + 1, ' ');
    for (i = 0; i < t; i++) {
      fprintf(of, " | ");
      printSet(top[i]);
      chars(howmany, ' ');
    }
    fprintf(of, " |\n");

    chars(howmany + 2, '-');
    fputc('+', of);
    for (i = 0; i < t; i++) {
      chars((howmany*2)+2, '-');
      fputc('+', of);
    }
    fputc('\n', of);
    
    for (i = 0; i < t; i++) {
      fputc(' ', of);
      printSet(side[i]);
      fprintf(of, " |");
      for (j = 0; j < t; j++) {
	fprintf(of, " ");
	calcCell(top[j], side[i]);
	fprintf(of, " |");
      }
      fprintf(of, "\n");
      chars(howmany + 2, '-');
      fputc('+', of);
      for (k = 0; k < t; k++) {
	chars((howmany*2)+2, '-');
	fputc('+', of);
      }
      fputc('\n', of);
    }
    
    fputc('\n', of);
    break;
  case 1:			/* HTML */
    t = 1<<howmany;
    fprintf(of, "\n<h2>Punnet Square</h2>\n");
    fprintf(of,
	    "\n<p><table border=3 cellpadding=3 align=center>\n<tr><td></td>");
    for (i = 0; i < t; i++) {
      fprintf(of, "<td><strong><tt>");
      printSet(top[i]);
      fprintf(of, "</tt></strong></td>");
    }
    
    fprintf(of, "</tr>\n");
    
    for (i = 0; i < t; i++) {
      fprintf(of, "<tr><td><strong><tt>");
      printSet(side[i]);
      fprintf(of, "</tt></strong></td>");
      for (j = 0; j < t; j++) {
	fprintf(of, "<td><tt>");
	calcCell(top[j], side[i]);
	fprintf(of, "</tt></td>");
      }
      fprintf(of, "</tr>\n");
    }

    fprintf(of, "</table><p>\n\n");
    break;
  case 2:			/* LaTeX */
    t = 1<<howmany;
    fprintf(of, "\n\\section*{Punnet Square}\n");
    fprintf(of, "\n\\hfil\\begin{tabular}{|");
    for (i = 0; i <= t; i++)
      fprintf(of, "l|");
    fprintf(of, "}\n\\hline\n");
    for (i = 0; i < t; i++) {
      fprintf(of, " & \\bfseries ");
      printSet(top[i]);
    }
    
    fprintf(of, "\\\\\n");
    
    for (i = 0; i < t; i++) {
      fprintf(of, "\\hline\n");
      fprintf(of, "\\bfseries ");
      printSet(side[i]);
      for (j = 0; j < t; j++) {
	fprintf(of, " & \\ttfamily ");
	calcCell(top[j], side[i]);
      }
      fprintf(of, "\\\\\n");
    }
    fprintf(of, "\\hline\n");
    fprintf(of, "\\end{tabular}\n\n");
    break;
  case 3:
  case 4:
    t = 1<<howmany;
    fprintf(of, "\nPunnet Square:\n\n");
    for (i = 0; i < t; i++) {
      putc(dc, of);
      printSet(top[i]);
    }
    putc('\n', of);
    
    for (i = 0; i < t; i++) {
      printSet(side[i]);
      for (j = 0; j < t; j++) {
	putc(dc, of);
	calcCell(top[j], side[i]);
      }
      putc('\n', of);
    }
    
    putc('\n', of);
    break;
  }
}

void printSet(unsigned long bits) {
  int i, temp;

  for (i = 0; i < howmany; i++) {
    temp = bits & (1<<i);
    if (temp)
      putc(toupper(it[i].theletter), of);
    else
      putc(it[i].theletter, of);
  }
}

void calcCell(unsigned long a, unsigned long b) {
  int i, t1, t2, p;
  unsigned long current;

  current = 0;
  for (i = 0; i < howmany; i++) {
    p = 1<<i;
    t1 = a & p;
    t2 = b & p;
    if (t1 && t2) {
      putc(toupper(it[i].theletter), of);
      putc(toupper(it[i].theletter), of);
      current |= (3 << (2 * i));
    } else if (!t1 && !t2) {
      putc(it[i].theletter, of);
      putc(it[i].theletter, of);
      current |= (0 << (2 * i));
    } else {
      putc(toupper(it[i].theletter), of);
      putc(it[i].theletter, of);
      current |= (2 << (2 * i));
    }
  }
  addTally(current);
}

void addTally(unsigned long x) {
  int i;
  unsigned long t, q;
  
  them[x]++;

  q = 0;
  for (i = 0; i < howmany; i++) {
    t = x & (3 << (2*i));
    if (t)
      q |= 1 << i;
  }
  pheno[q]++;
}

void printTallies(void) {
  long i, tp;
  int q;

  switch (outType) {
  case 0:
    tp = 1<<(howmany<<1);
    fprintf(of, "Genotype Analysis:\n\n");
    
    fprintf(of, "  Genotype\tTotal\t\tRatio\t\t%%\n");
    fprintf(of, "  --------\t-----\t\t-----\t\t-\n");
    for (i = tp - 1; i >= 0; i--) {
      if (them[i]) {
	fprintf(of, "  ");
	printGeno(i);
	if (howmany < 3)
	  putc('\t', of);
	fprintf(of, "\t%d / %ld", them[i], tp);
	fprintf(of, "\t\t1 : %u",
		(unsigned long) (1.00 / ((float) them[i] / tp)));
	fprintf(of, "\t\t%3.2f%%\n", ((float) them[i] / tp) * (float) 100);
      }
    }
    fprintf(of, "\n");

    fprintf(of, "Phenotype Analysis:\n\n");
    for (i = tp - 1; i >= 0; i--) {
      if (pheno[i]) {
	fprintf(of, "  ");
	printPheno(i);
	fprintf(of, "\n  \t\t%d / %ld", pheno[i], tp);
	fprintf(of, "\t\t");
	printRatio(pheno[i], tp);
	fprintf(of, "\t\t%3.2f%%\n", ((float) pheno[i] / tp) * (float) 100);
      }
    }
    fprintf(of, "\n");
    
    fprintf(of, "Phenotype ratio:   ");
    
    q = 0;
    for (i = tp - 1; i >= 0; i--) {
      if (pheno[i])
	if (q)
	  fprintf(of, " : %d", pheno[i]);
	else {
	  fprintf(of, "%d", pheno[i]);
	  q = 1;
	}
    }
    fprintf(of, "\n");
    
    break;
  case 1:
    tp = 1<<(howmany<<1);
    fprintf(of, "<h2>Genotype Analysis</h2>\n");
    fprintf(of, "<table border=3 cellpadding=3 align=center>\n");
    fprintf(of, "<tr><td><strong>Genotype</strong></td>");
    fprintf(of,
	    "<td><strong>Total</strong></td><td><strong>Ratio</strong></td>");
    fprintf(of, "<td><strong>%%</strong></td></tr>\n");
    for (i = tp - 1; i >= 0; i--) {
      if (them[i]) {
	fprintf(of, "<tr><td>");
	printGeno(i);
	fprintf(of, "</td><td>%d / %ld</td>", them[i], tp);
	fprintf(of, "<td>1 : %u</td>",
		(unsigned long) (1.00 / ((float) them[i] / tp)));
	fprintf(of, "<td align=right>%3.2f%%</td></tr>\n",
		((float) them[i] / tp) * (float) 100);
      }
    }
    fprintf(of, "</table><p>\n\n");
    
    fprintf(of, "<h2>Phenotype Analysis</h2>\n");
    fprintf(of, "<table border=3 cellpadding=3 align=center>\n");
    fprintf(of, "<tr><td><strong>Phenotype</strong></td>");
    fprintf(of,
	    "<td><strong>Total</strong></td><td><strong>Ratio</strong></td>");
    fprintf(of, "<td><strong>%%</strong></td></tr>\n");
    for (i = tp - 1; i >= 0; i--) {
      if (pheno[i]) {
	fprintf(of, "<tr><td>");
	printPheno(i);
	fprintf(of, "</td><td>%d / %ld</td>", pheno[i], tp);
	fprintf(of, "<td>");
	printRatio(pheno[i], tp);
	fprintf(of, "</td>");
	fprintf(of, "<td align=right>%3.2f%%</td></tr>\n",
		((float) pheno[i] / tp) * (float) 100);
      }
    }
    fprintf(of, "</table><p>\n");
    
    fprintf(of, "<strong>Phenotype ratio: </strong>");
    
    q = 0;
    for (i = tp - 1; i >= 0; i--) {
      if (pheno[i])
	if (q)
	  fprintf(of, " : %d", pheno[i]);
	else {
	  fprintf(of, "%d", pheno[i]);
	  q = 1;
	}
    }
    fprintf(of, "<p>\n\n");
    break;
  case 2:
    tp = 1<<(howmany<<1);
    fprintf(of, "\\section*{Genotype Analysis}\n");
    fprintf(of, "\\hfil\\begin{tabular}{|l|l|l|r|}\n\\hline\n");
    fprintf(of, "\\bf Genotype");
    fprintf(of, " & \\bf Total & \\bf Ratio");
    fprintf(of, " & \\bf\\%%\\hfil\\hfil\\\\\n\\hline\n");
    for (i = tp - 1; i >= 0; i--) {
      if (them[i]) {
	printGeno(i);
	fprintf(of, " & %d / %ld", them[i], tp);
	fprintf(of, " & 1 : %u",
		(unsigned long) (1.00 / ((float) them[i] / tp)));
	fprintf(of, " & %3.2f\\%%\\\\\n",
		((float) them[i] / tp) * (float) 100);
	fprintf(of, "\\hline\n");
      }
    }
    fprintf(of, "\\end{tabular}\n\n");
    
    fprintf(of, "\\section*{Phenotype Analysis}\n");
    fprintf(of, "\\hfil\\begin{tabular}{|l|l|l|r|}\n\\hline\n");
    fprintf(of, "\\bf Phenotype");
    fprintf(of, " & \\bf Total & \\bf Ratio");
    fprintf(of, " & \\bf\\%%\\hfil\\hfil\\\\\n\\hline\n");
    for (i = tp - 1; i >= 0; i--) {
      if (pheno[i]) {
	printPheno(i);
	fprintf(of, " & %d / %ld", pheno[i], tp);
	fprintf(of, " & ");
	printRatio(pheno[i], tp);
	fprintf(of, " & %3.2f\\%%\\\\\n",
		((float) pheno[i] / tp) * (float) 100);
	fprintf(of, "\\hline\n");
      }
    }
    fprintf(of, "\\end{tabular}\\medskip\n\n");
    
    fprintf(of, "{\\bf Phenotype ratio:} ");
    
    q = 0;
    for (i = tp - 1; i >= 0; i--) {
      if (pheno[i])
	if (q)
	  fprintf(of, " : %d", pheno[i]);
	else {
	  fprintf(of, "%d", pheno[i]);
	  q = 1;
	}
    }
    fprintf(of, "\n\n");
    break;
  case 3:
  case 4:
    tp = 1<<(howmany<<1);
    fprintf(of, "Genotype Analysis:\n\n");
    fprintf(of, "Genotype%cTotal%cRatio%c%%\n", dc, dc, dc);
    for (i = tp - 1; i >= 0; i--) {
      if (them[i]) {
	printGeno(i);
	fprintf(of, "%c%d / %ld", dc, them[i], tp);
	fprintf(of, "%c1 : %u", dc,
		(unsigned long) (1.00 / ((float) them[i] / tp)));
	fprintf(of, "%c%3.2f%%\n", dc,
		((float) them[i] / tp) * (float) 100);
      }
    }
    putc('\n', of);
    
    fprintf(of, "Phenotype Analysis:\n\n");
    fprintf(of, "Phenotype%cTotal%cRatio%c%%\n", dc, dc, dc);
    for (i = tp - 1; i >= 0; i--) {
      if (pheno[i]) {
	printPheno(i);
	fprintf(of, "%c%d / %ld%c", dc, pheno[i], tp, dc);
	printRatio(pheno[i], tp);
	fprintf(of, "%c%3.2f%%\n", dc,
		((float) pheno[i] / tp) * (float) 100);
      }
    }
    putc('\n', of);
    
    fprintf(of, "Phenotype ratio: ");
    
    q = 0;
    for (i = tp - 1; i >= 0; i--) {
      if (pheno[i])
	if (q)
	  fprintf(of, " : %d", pheno[i]);
	else {
	  fprintf(of, "%d", pheno[i]);
	  q = 1;
	}
    }
    fprintf(of, "\n");
    break;
  }
}

void printGeno(unsigned long bits) {
  int i;
  unsigned long t;

  for (i = 0; i < howmany; i++) {
    t = bits & (3 << (2*i));
    t = t >> 2 * i;
    switch (t) {
    case 0:
      putc(it[i].theletter, of);
      putc(it[i].theletter, of);
      break;
    case 1:
    case 2:
      putc(toupper(it[i].theletter), of);
      putc(it[i].theletter, of);
      break;
    case 3:
      putc(toupper(it[i].theletter), of);
      putc(toupper(it[i].theletter), of);
      break;
    }
  }
}

void printPheno(unsigned long bits) {
  int i;

  for (i = 0; i < howmany; i++) {
    if (i)
      fprintf(of, ", ");
    if (bits & (1 << i)) {
      fprintf(of, it[i].dominant);
    } else
      fprintf(of, it[i].recessive);
  }
}

void printRatio(int x, int y) {
  int i;

  for (i = y/2; i >= 1; i--) {
    if (y % i == 0 && x % i == 0)
      break;
  }
  
  fprintf(of, "%d : %d", x / i, y / i);
}

void chars(int x, char c) {
  int i;

  for (i = 0; i < x; i++)
    putc(c, of);
}
