Blame onefile/history-dates-test.c

261920
261920
#include <helianthus.h></helianthus.h>
261920
#include <string.h></string.h>
261920
#include <stdio.h></stdio.h>
261920
261920
261920
#define MAXREC     1000
261920
#define ANSWERS       4
261920
261920
#define MAXQUESTS    10
261920
261920
261920
typedef struct {
261920
  char text[128];
261920
} Date;
261920
261920
typedef struct {
261920
  char text[1024];
261920
} Text;
261920
261920
typedef struct {
261920
  char text[128];
261920
} Part;
261920
261920
261920
typedef struct {
261920
  Date date;
261920
  Text text;
261920
  Part part;
261920
} BaseRecord;
261920
261920
typedef struct {
261920
  Date *date;
261920
  Text *text;
261920
  Part *part;
261920
  int error;
261920
} Record;
261920
261920
typedef struct {
261920
  Date *date;
261920
  int error;
261920
} Answer;
261920
261920
261920
BaseRecord recordsSrc[MAXREC];
261920
Record records[MAXREC];
261920
Part *parts[MAXREC];
261920
Date *dates[MAXREC];
261920
int partCount;
261920
int dateCount;
261920
int recCount;
261920
261920
261920
int mode;
261920
int errorCount;
261920
int curError;
261920
int curRec;
261920
double questionFade;
261920
Answer answers[ANSWERS];
261920
261920
261920
void load(const char *filename) {
261920
  recCount = 0;
261920
  partCount = 0;
261920
  dateCount = 0;
261920
  memset(recordsSrc, 0, sizeof(recordsSrc));
261920
  memset(records, 0, sizeof(records));
261920
  memset(parts, 0, sizeof(parts));
261920
  memset(dates, 0, sizeof(dates));
261920
261920
  FILE *f = fopen(filename, "r");
261920
  if (!f) {
261920
    printf("cannot open file for read: %s\n", filename);
261920
    return;
261920
  }
261920
261920
  int mode = 0;
261920
  BaseRecord *rs = recordsSrc;
261920
  char *p = rs->date.text;
261920
  char *e = p + sizeof(rs->date.text);
261920
  while(1) {
261920
    int c = fgetc(f);
261920
    if (c <= 0 || c >= 256) break;
261920
    if (c == '\t') {
261920
      if (mode == 0) {
261920
        mode = 1; p = rs->text.text; e = p + sizeof(rs->text.text);
261920
      } else
261920
      if (mode == 1) {
261920
        mode = 2; p = rs->part.text; e = p + sizeof(rs->part.text);
261920
      } else
261920
      if (mode == 2) {
261920
        mode = 3;
261920
      }
261920
    } else
261920
    if (c == '\n') {
261920
        if (rs->date.text[0] || rs->text.text[0] || rs->part.text[0]) {
261920
          ++recCount; ++rs;
261920
          if (recCount >= MAXREC) break;
261920
        }
261920
        mode = 0; p = rs->date.text; e = p + sizeof(rs->date.text);
261920
    } else
261920
    if (c != '\r' && p+1 < e) {
261920
      *p++ = c;
261920
    }
261920
  }
261920
  fclose(f);
261920
261920
  if (recCount < MAXREC)
261920
    if (rs->date.text[0] || rs->text.text[0] || rs->part.text[0])
261920
      ++recCount;
261920
261920
  for(int i = 0; i < recCount; ++i) {
261920
    Record *r = &records[i];
261920
    BaseRecord *rs = &recordsSrc[i];
261920
    for(int j = 0; j <= i; ++j) {
261920
      BaseRecord *rrs = &recordsSrc[j];
261920
      if (!r->date && !strcmp(rs->date.text, rrs->date.text)) r->date = &rrs->date;
261920
      if (!r->text && !strcmp(rs->text.text, rrs->text.text)) r->text = &rrs->text;
261920
      if (!r->part && !strcmp(rs->part.text, rrs->part.text)) r->part = &rrs->part;
261920
    }
261920
    if (r->part == &rs->part)
261920
      parts[partCount++] = r->part;
261920
    if (r->date == &rs->date)
261920
      dates[dateCount++] = r->date;
261920
  }
261920
6d1715
  for(int i = 0; i < 2*recCount; ++i) {
6d1715
    int a = randomNumber(0, recCount - 1);
6d1715
    int b = randomNumber(0, recCount - 1);
6d1715
    if (a == b) continue;
6d1715
    Record r;
6d1715
    memcpy(&r, &records[a], sizeof(r));
6d1715
    memcpy(&records[a], &records[b], sizeof(r));
6d1715
    memcpy(&records[b], &r, sizeof(r));
6d1715
  }
261920
  if (recCount > MAXQUESTS)
261920
    recCount = MAXQUESTS;
261920
}
261920
261920
261920
void nextQuestion() {
261920
  if (mode != 2) return;
261920
  if (!curError) ++curRec;
261920
  if (curRec >= recCount)
261920
    { mode = 3; return; }
261920
261920
  curError = 0;
261920
  mode = 1;
261920
261920
  int q = randomNumber(curRec, recCount-1);
261920
  if (q != curRec) {
261920
    Record r;
261920
    memcpy(&r, &records[curRec], sizeof(r));
261920
    memcpy(&records[curRec], &records[q], sizeof(r));
261920
    memcpy(&records[q], &r, sizeof(r));
261920
  }
261920
261920
  for(int i = 0; i < ANSWERS; ++i) {
261920
    for(int j = 0; j < 100; ++j) {
261920
      answers[i].date = dates[randomNumber(0, dateCount-1)];
261920
      if (answers[i].date != records[curRec].date) break;
261920
    }
261920
    answers[i].error = 0;
261920
  }
261920
  answers[randomNumber(0, ANSWERS-1)].date = records[curRec].date;
261920
}
261920
261920
261920
void startTest() {
261920
  mode = 2;
261920
  curRec = -1;
261920
  curError = 0;
261920
  errorCount = 0;
261920
  for(int i = 0; i < recCount; ++i)
261920
    records[i].error = 0;
261920
  nextQuestion();
261920
}
261920
261920
261920
void giveAnswer(int i) {
261920
  if (mode != 1) return;
261920
  if (answers[i].date == records[curRec].date) {
261920
    mode = 2;
261920
  } else {
261920
    curError = 1;
261920
    if (!records[curRec].error) {
261920
      records[curRec].error = 1;
261920
      ++errorCount;
261920
    }
261920
    for(int j = 0; j < ANSWERS; ++j)
261920
      if (answers[j].date != records[curRec].date)
261920
        answers[j].error = 1;
261920
  }
261920
}
261920
261920
261920
void init() {
261920
  load("data/history/ancient-dates.txt");
261920
  startTest();
261920
}
261920
261920
261920
void draw() {
261920
  saveState();
261920
  double w = windowGetWidth();
261920
  double h = windowGetHeight();
261920
  translate(w/2, h/2);
261920
261920
  double my = mouseTransformedY();
261920
261920
  saveState();
261920
  if (mode == 1 || mode == 2) {
261920
    noFill();
261920
    strokeWidth(2);
261920
    stroke(COLOR_BLACK);
261920
    textAlign(HALIGN_CENTER, VALIGN_CENTER);
261920
    textf(0, -200, "%d / %d", curRec+1, recCount);
261920
    textSize(32);
261920
    text(0, -100, records[curRec].text->text);
261920
    textSize(24);
261920
    textAlign(HALIGN_LEFT, VALIGN_TOP);
261920
    line(-150, -65, 150, -65);
261920
    double y = -40, dy = 40;
261920
    int hover = -1;
261920
    for(int i = 0; i < ANSWERS; ++i) {
261920
      if (answers[i].error) {
261920
        stroke(COLOR_RED);
261920
      } else
261920
      if (mode == 2) {
261920
        if (answers[i].date == records[curRec].date) {
261920
          circle(-130, y+i*dy+20, 10);
261920
          stroke(COLOR_BLUE);
261920
          fill(COLOR_BLUE);
261920
          circle(-130, y+i*dy+20, 5);
261920
          noFill();
261920
        }
261920
      } else {
261920
        circle(-130, y+i*dy+20, 10);
261920
        if (my > y+i*dy && my < y+(i+1)*dy) {
261920
          hover = i;
261920
          stroke(COLOR_BLUE);
261920
          fill(COLOR_BLUE);
261920
          circle(-130, y+i*dy+20, 5);
261920
          noFill();
261920
        }
261920
      }
261920
      text(-100, y + i*dy, answers[i].date->text);
261920
      stroke(COLOR_BLACK);
261920
    }
261920
261920
    if (mode == 1) {
261920
      questionFade += windowGetFrameTime();
261920
      if (questionFade > 1) questionFade = 1;
261920
      if (hover >= 0 && mouseWentDown("left"))
261920
        giveAnswer(hover);
261920
    } else {
261920
      questionFade -= windowGetFrameTime();
261920
      if (questionFade < 0) {
261920
        questionFade = 0;
261920
        nextQuestion();
261920
      }
261920
    }
261920
  } else
261920
  if (mode == 3) {
261920
    textSize(64);
261920
    textAlign(HALIGN_CENTER, HALIGN_CENTER);
261920
    textf(0, 0, "%d / %d", recCount - errorCount, recCount);
261920
    questionFade += windowGetFrameTime();
261920
    if (questionFade > 1) questionFade = 1;
261920
  }
261920
  restoreState();
261920
261920
  noStroke();
261920
  fill(colorByRGBA(1, 1, 1, 1-questionFade));
261920
  rect(-w/2, -h/2, w, h);
261920
261920
  restoreState();
261920
}
261920
261920
261920
int main() {
261920
  windowSetSize(800, 600);
261920
  windowSetResizable(TRUE);
261920
  windowSetVariableFrameRate();
261920
  windowSetInit(&init);
261920
  windowSetDraw(&draw);
261920
  windowRun();
261920
  return 0;
261920
}
261920