#include "iteach1.h" /*These are the routines common to the IBM versions of MT 1,2 & 3*/ /* A routine for Mac compatibility to print warning messages */ char *command[ ] = {"RESET","OPEN","OVERWRITE","EXIT","RECOGNIZE","RECALL", "AFFIXES","PRIMITIVES","RUNG1","RUNG2","RUNG3","TOP","ERRORBOX", "SELECT","REVIEW","TEST","SHUFFLE","LOOKUP","STATS","DRILL", "TIMESUP","CLOSE","HELP","SAVEAS","BRUSHUP","QUIT","BYE"}; char *shorts[ ] = {"RS","O","OW","X","COG","CAL","AF","P","1","2","3", "TOP","E","S","R","T","SH","L","ST","D","A","C","?","SA","B","Q", "BYE"}; /* short version of commands */ char *rstring[] = {"Illegal","Rung: 1","Rung: 2","Rung: 3","Top","Error Box"}; char *mess[MAXMESS]; /*error messages*/ void alert(short n,short m) /* A routine for compatibility with the Mac version which prints warning messages. On entry n is the type of alert and m the message to print */ { mess[0] = "Reading or writing file."; mess[1] = "Cannot allocate flasharray."; mess[5] = "Not a MacTeach 2 or 3 file."; mess[4] = "Close the open file first."; mess[8] = "Empty the error box first!"; printf("%s\n",mess[m]); if (!n) exit(0); } void cmdMes(void) /* This message is printed whenever a command is expected */ { puts("\n\nType s to start or select, or"); puts ("Enter command [upper or lower case], or \nType ? for help.\n"); } void commands(void) /* If help is requested, this is the list of commands printed */ { clrscr(); gotoxy(33,1); puts ("COMMAND PAGE 1\n"); puts ("Commands [Short forms]: Actions performed.\n"); puts ("Select [S]: Select cards from deck for study."); puts ("Review [R]: Review cards on current rung."); puts ("Test [T]: Test cards on current rung."); puts ("Bye [Bye]: Quit without saving; learning ladder will be\ restored."); puts ("Exit/Quit [X][Q]: End the current action or the session."); #ifdef TONE puts ("Recognition [Cog]: Make English responses to Loglan stimuli."); puts ("Recall [Cal]: Make Loglan responses to English stimuli."); #endif puts ("Rung1 [1] Rung2 [2] Rung3 [3]: Change rungs."); puts ("Top [Top] Errorbox [E]: Go to Top or Error-Box."); #ifdef TTHREE if (prog !='2') { puts ("Recognition [Cog]: Make English responses to Loglan stimuli."); puts ("Recall [Cal]: Make Loglan responses to English stimuli."); } puts ("Lookup [L]: Lookup a word or affix."); #endif puts ("Stats [St]: Display the session statistics."); puts ("Drill-number [D]: Set the number of repeats to escape error-box."); puts ("Time-allowance [A]: Set trigger for 'Time's up!' penalty."); puts ("Re-Start [Rs]: Restore all cards to deck."); puts ("Brushup [B]: Put all cards on Rung 3 and shuffle them."); puts ("Shuffle [Sh]: Toggle the shuffle flag."); puts ("\nPress space for Command Page 2."); puts ("Press return for Ladder Page."); if ((cmd = getche()) == ' ') { clrscr(); gotoxy(33,1); puts ("COMMAND PAGE 2\n"); puts ("Commands [Short forms]: Actions performed.\n"); #ifdef TTHREE puts ("Affixes [Af]: Preset for study of affixes."); puts ("Primitives [P]: Preset for study of primitives."); #endif puts ("Open [O]: Open a study file."); puts ("Close [C]: Close the current file."); puts ("Overwrite [Ow]: Overwrite study file of same name."); puts ("Saveas [SA]: Save the study file with a new name."); /* puts ("\nTo combine Review with Rung change, use Ctl with F keys");*/ puts ("\nTo start testing immediately after moving, use F keys to move:"); puts ("F1-3: Rungs 1-3. F4: Top. F10: Error Box."); puts ("\nPress any key for Ladder Page."); getche(); } display(); } void demote(short n) /* After an error response, show card n, sound an alarm, and place the card in the error box */ { if (!reviewflag) { /*demote only on testing*/ #ifdef TTHREE gotoxy(15,18); #else gotoxy(10,16); #endif if (!strcmp(instring,"TIME'S UP!")); /*No error mess on overtime*/ else printf("Incorrect.\n"); SysBeep(PAR); flasharray[n].flag[curflag] = '5'; /*Put in error box*/ #ifdef TONE /*In case it was a typing error to be corrected, save the old level, else reset it so the whole set of reponses for a given level must be repeated.*/ oldlevel = flasharray[n].flag[rrflag-'1'+2]; flasharray[n].flag[rrflag -'1'+2] = '0'; #endif } } void display(void) /* Display the current file, configuration, distribution of cards,and statistics of the latest test, if any */ { clrscr(); countflag(); /* Obtain the card distribution */ gotoxy(35,2); #ifdef TONE curflag = rrflag-'1'; #endif printf ("LADDER PAGE \n"); #ifdef TTHREE gotoxy(22,4); if (prog =='2' || prog == '4') puts("MacTeach 3: Learning Loglan affixes."); else puts("MacTeach 2: Learning Loglan primitives."); #else gotoxy(21,4); puts("Macteach 1: Forming Loglan Utterances."); #endif if (affixflag=='1') { gotoxy(18,6); printf("Mode: %s Drill number: %d", (rrflag=='1') ? "Recognize affixes" : "Recall affix sets",drillflg); } else { gotoxy(21,6); printf("Mode: %s Drill number: %d",(rrflag=='1') ? "Recognition " : "Recall ", drillflg); } gotoxy(26,7); printf("Response time allowance: %d.%d", threshld/factor,((threshld%factor)*10)/factor); gotoxy(27,8); printf("You're in/on %s\n",rstring[rungflag-'0']); gotoxy(31,10); printf("%3d On top\n",r[4]); gotoxy(31,11); printf("%3d On rung 3\n",r[3]); gotoxy(31,12); printf("%3d On rung 2\n",r[2]); gotoxy(31,13); printf("%3d On rung 1\n",r[1]); gotoxy(31,14); printf("%3d Still in deck\n",r[0]); gotoxy(31,15); printf("%3d In error box\n",r[5]); if (tested) { gotoxy(25,17); printf("Tested: %d Correct: %d (%d%%)\n", tested, right, (100*right)/tested); showStat(); /*Max and min times, standard deviation and timeouts*/ } } void doTeach(short argc,char **argv) /* Read in a command and take the appropriate action.*/ { while (TRUE) { /*Do forever (until quit command) */ cmdMes(); cmd = getCommand(); switch (cmd) { case BYE: dirty = 0; quitDo(); break; case OPEN: openDo(argc,argv); break; case OVERWRITE: saveDo(); break; case SAVEAS: saveAsDo(); break; case QUIT: case EXIT: writeStat(); quitDo(); break; case RECOGNIZE: writeStat(); rrflag = '1'; display(); break; case RECALL: writeStat(); rrflag = '2'; display(); break; #ifdef TTHREE case AFFIXES: writeStat(); affixflag = '1'; display(); break; case PRIMITIVES: writeStat(); affixflag = '2'; display(); break; #endif case RUNG1: rungflag = '1'; display(); break; case RUNG2: rungflag = '2'; display(); break; case RUNG3: rungflag = '3'; display(); break; case TOP: rungflag = '4'; display(); break; case ERRORBOX: rungflag = '5'; display(); break; case SELECT: if (!testIn()) break; doselect(); display(); break; case REVIEW: reviewflag = 1; if (!testIn()) break; dotest(); break; case TEST: reviewflag = 0; if (!testIn()) break; dotest(); break; case SHUFFLE: shufflag ^= TRUE; (shufflag) ? puts("Shuffle enabled") : puts ("Shuffle disabled."); break; #ifdef TTHREE case LOOKUP: doSeek(); break; #endif case STATS: sessions(); break; case DRILL: getDrill(); break; case TIMESUP: getTimeOut(); break; case CLOSE: if (inpfile) { if (dirty) { puts("Save this file? [Y,N, or (C)ancel]."); switch (toupper(getche())) { case 'Y': saveDo(); dirty = FALSE; case 'N': break; case 'C': return; } } fclose(in); #ifdef TONE fclose(cmt); #endif } inpfile = 0; break; case RESET: restore(); display(); break; case BRUSHUP: brush(); break; case HELP: commands(); break; case 0xbb: /*Function keys for combined rung + test*/ case 0xbc: case 0xbd: case 0xbe: case 0xbf: case 0xc4: if (cmd == 0xc4) cmd = 0xbf; rungflag = cmd - 0x8a; reviewflag = 0; if (!testIn()) break; dotest(); break; case 0xde: /*Function keys for combined rung and review*/ case 0xdf: case 0xe0: case 0xe1: case 0xe2: case 0xe7: if (cmd == 0xe7) cmd = 0xe2; rungflag = cmd - 0xad; reviewflag = 1; if (!testIn()) break; dotest(); break; default: break; } } } short doTime(void) /* Obtain time to first keystroke. System dependent, Returns time in ticks*/ { int c; char *ptr; short temp; ticks = clock(); while (!kbhit()) { // was scr_poll() which does not exist in ANSI C. Explore alternate timers. temp = clock() - ticks; /* and the response time */ if (temp<0) temp +=6000; if (temp >threshld) { /* And flag timeouts */ ticks = threshld; strcpy(instring,"TIME'S UP!"); #ifdef TTHREE gotoxy(15,17); #else gotoxy(5,15); #endif puts(instring); return -1; } } ticks = temp; return TRUE; } short getCommand(void) /* Obtain and parse a command. Each command has a long and short form */ { short i; // while (-1 == -1); // Was (i = scr_poll()) which doesn't exist. Explore alternatives. // if (i > 127) { // getche(); // return i; // } gets(instring); upstring(instring); /*Put it in upper case for matching */ for (i=0; i ", drillflg); ch = getchar(); if (ch==NL) return; else ungetc(ch,stdin); scanf ("%d",&ch); drillflg = ch; // getchar(); } void getTimeOut(void) /* This is IBM specific for obtaining the maximum time permitted for response. It is measured in 100ths second. It may have to be adjusted for other systems */ { char thno[10]; printf("\nEnter seconds until timeup (%1d.%1d)--> ",threshld/factor, ((threshld%factor)*10)/factor); gets(thno); if (isdigit(thno[0])) { switch(strlen(thno)) { case 3: if (thno[1] != '.' || !isdigit(thno[2])) break; thno[1] = thno[2]; thno[2] = '\0'; ind1 = ((atoi(thno) * factor))/10; break; case 1: ind1 = atoi(thno) * factor; break; default: ind1 = threshld; break; } } if (ind1>1 && ind1<(93 * factor)/10) threshld = ind1; } void iOpen(char *fname) /* This routine opens file fname for reading and writing, and warns if unsuccessful */ { if (!(in = fopen(fname,"r+"))) { printf("\nCannot open %s",fname); } } void myWrite(char *string) /* Display a string string, removing control punctuation */ { char *sptr,ch; #ifdef MAC short lin; #endif short col,copy,flg; flg = 0; sptr = string; copy = TRUE; while (ch = *sptr++) { switch(ch) { case '\\': /*Save the next character without checking*/ putchar (*(sptr++)); break; /* If copy is in effect, these characters are converted to a space, or a return if we are too close to the end of a line. If a comment it is indented */ case '-': case '=': case '+': case ' ': #ifdef MAC cgetxy( (int *)&col, (int *)&lin, stdin); #else col = wherex(); #endif if (copy) { if (col>68) { printf("\n "); clreol(); if (flg) printf(" "); } else putchar(SP); } break; /* This character is displayed if copy is in effect. A check is made for wrapping or for indenting comments. The return precedes the character */ case '(': #ifdef MAC cgetxy( (int *)&col, (int *)&lin, stdin); #else col = wherex(); #endif if (copy) { if (col>68) { printf("\n "); if (flg) printf(" "); putchar(ch); } else putchar(ch); } break; /*As above, but in these cases the wrap follows the character*/ case ')': case '/': #ifdef MAC cgetxy( (int *)&col, (int *)&lin, stdin); #else col = wherex(); #endif if (copy) { if (col>68) { putchar(ch); printf("\n "); if (flg) printf(" "); } else putchar(ch); } break; /*Double space before beginning a comment, and indent this and subsequent lines*/ case '|': printf("\n\n "); flg = 1; break; /*Normally the next two characters are not displayed, except in comments*/ case ':': if (flg) putchar(ch); case '&': break; /*All other characters are displayed*/ default: if (copy) putchar(ch); } } putchar(SP); } void openDo(short argc,char **argv) /* Check if a file name was given on opening, and open it; else request the name; then read it into memory */ { if (argc == 2) { strcpy(filename,argv[1]); } else { puts("Enter filename to open."); gets(filename); } iOpen(filename); readfile(); /*Read the file */ if (argc != 2) display(); } void quitDo(void) /* This is the windup routine. Remind the user if da has not saved the file, close the input file, file and print the session statistics */ { if (dirty) { puts("\nSaving current ladder data...\n"); saveDo(); dirty = FALSE; } if (inpfile) fclose(in); exit(0); } void saveAsDo(void) /* Save the file under a new name (which is requested) */ { short i; dirty = TRUE; if (fclose(in)) puts ("File could not be closed."); puts("Enter output file name."); gets(instring); if (!(in = fopen(instring,"w"))){ printf ("Cannot create %s",instring); } else { writefile(in); } } short screenchr(void) /* A character input without necessity of a CR */ { short temp; temp = toupper(getche()); switch(temp) { case 13: case 10: case 'Y': return NEXTF; case 'Q': case 'X': return STOPF; case 'C': return CANERR; default: return PASSF; } } #ifdef MAC void clrscr(void) /* A screen clearing routine that can be customized if needed */ { cgotoxy(1,1,stdin); ccleos(stdin); } char getche(void) { char chr; csetmode(C_CBREAK,stdin); chr =getchar(); csetmode(C_ECHO,stdin); return chr; } #endif void sessions(void) /* Calculate and display the session statistics */ { if (!testtotl) { puts ("No test results yet."); return; } setstat(); getend(); printf ("\n\tSESSION STATISTICS\n"); printf ("\nOn %d/%d/%d from %d:%02d to %d:%02d",startime->tm_mon+1, startime->tm_mday,startime->tm_year,shour,smin,etime->tm_hour, etime->tm_min); printf ("\nTested %d, Correct %d, %d%%",testtotl,righttot,percent); printf ("\nAverage time %d.%d +/- %d.%ds, Overtime %d\n\n",average/factor, ((average%factor)*10)/factor,sdevn/factor,((sdevn%factor)*10)/factor,tmouts); } void setRung(short n) /* Set rungflag to n. Needed because of common code with Mac */ { rungflag = n; } /* Display the statistics for a single test */ void showStat(void) { long temp; testav = ticktotl/tested; temp = testav - moment; tsd = isqrt(labs(temp*temp - square/tested)); gotoxy(26,18); printf ("Average time: %d.%d +/- %d.%ds\n",testav/factor,((testav%factor)*10)/factor,tsd/factor, ((tsd%factor)*10)/factor); gotoxy(26,19); printf ("Response range: %d.%d - %d.%d",minimum/factor,((minimum%factor)*10)/factor, maximum/factor,((maximum%factor)*10)/factor); gotoxy(29,20); printf ("Number of overtimes: %d",tmouts); } Boolean testIn(void) /*Returns a BOOLEAN if a file is not open*/ { if (!inpfile) { puts("Open a file first."); return FALSE; } return TRUE; } void writeStat(void) /* Write the statistics to the statistics log file, and also to the screen */ { #ifdef TTHREE if (rrflag == '1' && affixflag == '1') if (!(stats = fopen("Stats3.paf","a"))) puts("Cannot open statslog file"); if (rrflag == '1' && affixflag == '2') if (!(stats = fopen("Stats2.le","a"))) puts("Cannot open statslog file"); if (rrflag == '2' && affixflag == '1') if (!(stats = fopen("Stats3.afp","a"))) puts("Cannot open statslog file"); if (rrflag == '2' && affixflag == '2') if (!(stats = fopen("Stats2.el","a"))) puts("Cannot open statslog file"); #else if (rrflag == '1') { if (!(stats = fopen("Stats1.le","a"))) puts("Cannot open statslog file"); } else if (!(stats = fopen("Stats1.el","a"))) puts("Cannot open statslog file"); #endif if (testtotl) { sessions(); statline(); testtotl = tested = righttot = maximum = 0; sqtotal = ticktotl = timetotl = 0L; minimum = 10000; fclose(stats); } } #ifdef IBM void SysBeep(PAR) /* Sound the bell or beep */ { putchar(0x07); } #else Boolean kbhit(void) { EventRecord myEvent; return EventAvail(8,&myEvent); } #endif