/* TABLES.C Written by DavidW Started on 21/1/92 */ #include #include #include #include #include GLREF_D UWORD DatLocked; LOCAL_D TEXT *cmds[]= { "rReset score", "lLimits", "mMode", "tTiming", "xExit", NULL }; #define TABLES_ITEMS 5 LOCAL_D H_MENU_DATA mdata[]= { "Tables",TABLES_ITEMS, NULL }; GLDEF_D TEXT ** _cmds=(&cmds[0]); GLDEF_D H_MENU_DATA * _mdata=(&mdata[0]); LOCAL_D UINT MainWid; typedef struct { UWORD TableEnd; UWORD MaxTable; UWORD Tested; UWORD Correct; UWORD Timing; UWORD Mode; } TSTATE; LOCAL_D TSTATE state={12,12,0,0,5,1}; LOCAL_D TEXT *EnvName="TABLES"; #define ENV_NAME_LEN 6 LOCAL_D ULONG seed; LOCAL_D VOID *timH; LOCAL_D WORD timactive; LOCAL_D WORD timstat; LOCAL_D ULONG timint; LOCAL_D WORD timcount; LOCAL_D WORD timtotcnt; LOCAL_C VOID DrawLine(INT j,TEXT *pb) { P_RECT box; box.tl.x=4; box.br.x=189-4; box.tl.y=4+9*j; box.br.y=box.tl.y+9; gPrintBoxText(&box,8,G_TEXT_ALIGN_CENTRE,0,pb,p_slen(pb)); } LOCAL_C VOID DisplayScores(VOID) { TEXT buf[40]; p_atos(&buf[0],"Score: %u correct out of %u",state.Correct,state.Tested); DrawLine(0,&buf[0]); } LOCAL_C VOID DisplayMode(VOID) { TEXT *pb; TEXT buf[40]; if (state.Mode==1) pb="Testing all tables"; else { p_atos(&buf[0],"Testing %d times table",state.Mode); pb=(&buf[0]); } DrawLine(1,pb); } LOCAL_C VOID DisplayLimits(VOID) { TEXT buf[40]; p_atos(&buf[0],"(up to %d times %d)", (state.Mode==1? state.MaxTable: state.Mode),state.TableEnd); DrawLine(2,&buf[0]); } LOCAL_C VOID DrawButton(INT state) { P_RECT box; box.tl.x=34+36; box.br.x=34+36+38; box.tl.y=47; box.br.y=47+14; wDrawButton(&box,"Enter",state); } LOCAL_C VOID DisplayPressButton(VOID) { gPrintText(34,56,"Press",5); DrawButton(FALSE); gPrintText(34+36+38+6,56,"to test",7); } LOCAL_C VOID Display(VOID) { DisplayScores(); DisplayMode(); DisplayLimits(); DisplayPressButton(); } LOCAL_C VOID ResetScore(VOID) { if (!state.Tested) { wInfoMsg("No score to reset"); return; } if (uOpenDialog("Reset score to zero")) return; if (uAddButtonList("No",-'n',"Yes",'y',NULL)) return; if (uRunDialog()=='y') { state.Tested=0; state.Correct=0; DisplayScores(); } } LOCAL_C VOID ChangeLimits(VOID) { LONG lTableEnd; LONG lMaxTable; H_DI_NUMBER end; H_DI_NUMBER last; lTableEnd=state.TableEnd; lMaxTable=state.MaxTable; if (uOpenDialog("Limits for testing")) return; end.value=(&lTableEnd); end.low=10; end.high=99; if (uAddDialogItem(H_DIALOG_NUMBER,"Tables end at",&end)) return; last.value=(&lMaxTable); last.low=2; last.high=99; if (uAddDialogItem(H_DIALOG_NUMBER,"Highest table",&last)) return; if (uRunDialog()<=0) return; state.TableEnd=lTableEnd; state.MaxTable=lMaxTable; if (state.Mode>state.MaxTable) state.Mode=state.MaxTable; DisplayMode(); DisplayLimits(); } LOCAL_C VOID ChangeTiming(VOID) { LONG lTiming; H_DI_NUMBER tim; lTiming=state.Timing; if (uOpenDialog("Timing")) return; tim.value=(&lTiming); tim.low=1; tim.high=20; if (uAddDialogItem(H_DIALOG_NUMBER,"Number of seconds allowed",&tim)) return; if (uRunDialog()<=0) return; state.Timing=lTiming; } LOCAL_C VOID ChangeMode(VOID) { H_DI_CHOICE ch; INT j; TEXT buf[20]; if (uOpenDialog("Mode")) return; if (uBeginDCL(&ch)) return; if (uGrowDCL(&ch,"All tables")) return; for (j=2; j<=state.MaxTable; j++) { p_atos(&buf[0],"%d times table",j); if (uGrowDCL(&ch,&buf[0])) return; } if (uAddDCL("Test which tables",&state.Mode,&ch)) return; if (uRunDialog()<=0) return; DisplayMode(); DisplayLimits(); } LOCAL_C VOID ExitApplication(VOID) { uErrorValue(p_setenviron(EnvName,ENV_NAME_LEN,&state,sizeof(TSTATE))); p_exit(0); } LOCAL_C VOID ManageCommand(INT index) { switch (index) { case 0: ResetScore(); break; case 1: ChangeLimits(); break; case 2: ChangeMode(); break; case 3: ChangeTiming(); break; case 4: ExitApplication(); } } LOCAL_C VOID TryExecuteCommand(INT keycode) { keycode=uLocateCommand(keycode); if (keycode>=0) ManageCommand(keycode); } LOCAL_C INT FindRandom(INT low,INT high) { INT range; range=high-low+1; return(low+(INT)(p_randl(&seed)%range)); } LOCAL_C VOID FindFactors(WORD *pa,WORD *pb) { *pa=(state.Mode==1? FindRandom(2,state.MaxTable): state.Mode); *pb=FindRandom(2,state.TableEnd); } LOCAL_C VOID SwitchStyle(INT style) { G_GC gc; gc.style=style; gSetGC(0,G_GC_MASK_STYLE,&gc); } LOCAL_C VOID *CreateEditor(VOID) { H_EDIT_BOX heb; heb.maxchars=4; heb.vulen=30; heb.pos.x=113; heb.pos.y=38; heb.win=MainWid; heb.font=WS_FONT_BASE; heb.style=G_STY_DOUBLE; return(hEBOpen(H_EDIT_BOX_FONT,&heb)); } LOCAL_C VOID ClearBottomArea(VOID) { P_RECT box; box.tl.x=4; box.br.x=189-4; box.tl.y=4+3*9; box.br.y=80-4; gClrRect(&box,G_TRMODE_CLR); } LOCAL_C VOID Beep(VOID) { p_sound(-5,320); } LOCAL_C VOID SelectAll(VOID *ebH) { hEBSetSelect(ebH,0,p_slen(hEBSenseText(ebH))); } LOCAL_C INT SenseNumberTyped(VOID *ebH) { TEXT *pb; WORD num; pb=hEBSenseText(ebH); if (!*pb) return(0); p_stoi(&pb,&num); return(num); } LOCAL_C INT AddTextItem(TEXT *pmt,TEXT *pbod) { H_DI_TEXT txt; TEXT buf[20]; txt.type=H_DTEXT_ALIGN_CENTRE; uZTStoBCS(txt.str=(&buf[0]),pbod); return(uAddDialogItem(H_DIALOG_TEXT,pmt,&txt)); } LOCAL_C INT Complain(INT a,INT b,INT c) { TEXT buf[20]; if (uOpenDialog("Incorrect")) return(-1); p_atos(&buf[0],"%d \236 %d",a,b); if (AddTextItem("The question",&buf[0])) return(-1); buf[p_itob(&buf[0],c)]=0; if (AddTextItem("Your answer",&buf[0])) return(-1); if (uAddButtonList("Help",W_KEY_ESCAPE,"Retry",W_KEY_RETURN,NULL)) return(-1); if (uRunDialog()==W_KEY_RETURN) return(0); p_atos(&buf[0],"%d \236 %d = %d",a,b,a*b); if (uOpenDialog(&buf[0])) return(-1); if (uAddButtonList("Continue",W_KEY_RETURN,NULL)) return(-1); uRunDialog(); return(-1); } LOCAL_C INT BadKey(INT k) { return(k<256 && p_isprint(k) && !p_isdigit(k)); } LOCAL_C VOID CancelTimer(VOID) { if (timactive) { p_iow2(timH,P_FCANCEL); p_waitstat(&timstat); } timactive=FALSE; } LOCAL_C VOID QueueTimer(VOID) { CancelTimer(); p_ioa4(timH,P_FRELATIVE,&timstat,&timint); timactive=TRUE; } LOCAL_C VOID InitialiseTimer(VOID) { if (state.Timing<=4) { timint=5; timcount=2*state.Timing; } else { timint=10; timcount=state.Timing; } timtotcnt=timcount; QueueTimer(); } LOCAL_C VOID GetBarChartRect(P_RECT *pbox) { pbox->tl.x=9; pbox->br.x=180; pbox->tl.y=62; pbox->br.y=68; } LOCAL_C VOID IncrementBarChart(VOID) { P_RECT box; timcount--; GetBarChartRect(&box); box.br.x=9+171*(timtotcnt-timcount)/timtotcnt; gFillPattern(&box,WS_BITMAP_GREY,G_TRMODE_REPL); } LOCAL_C VOID ClearBarChart(VOID) { P_RECT box; GetBarChartRect(&box); gClrRect(&box,G_TRMODE_CLR); } LOCAL_C VOID DisplayQuestion(VOID) { TEXT buf[30]; WMSG_KEY key; WORD keyactive; WORD keystat; P_RECT box; VOID *ebH; WORD a; WORD b; WORD c; WORD ans; ebH=CreateEditor(); if (!ebH) return; ClearBottomArea(); hEBEmphasise(ebH,TRUE); FindFactors(&a,&b); ans=a*b; p_atos(&buf[0],"%d \236 %d = ",a,b); box.tl.x=53; box.br.x=113; box.tl.y=38; box.br.y=38+17; SwitchStyle(G_STY_DOUBLE); gPrintBoxText(&box,15,G_TEXT_ALIGN_RIGHT,0,&buf[0],p_slen(&buf[0])); SwitchStyle(G_STY_NORMAL); box.tl.x=8; box.br.x=189-8; box.tl.y=61; box.br.y=61+8; gBorderRect(&box,W_BORD_CORNER_1); DatLocked=TRUE; state.Tested++; keyactive=FALSE; InitialiseTimer(); FOREVER { if (keyactive) wFlush(); else { uGetKeyA(&keystat,&key); keyactive=TRUE; } p_iowait(); if (keystat==E_FILE_PENDING) { timactive=FALSE; IncrementBarChart(); if (!timcount) { wFlush(); p_sleep(2); goto CheckAnswer; } QueueTimer(); continue; } keyactive=FALSE; if (BadKey(key.keycode)) Beep(); else if (key.keycode!=W_KEY_RETURN) hEBHandleKey(ebH,key.keycode,key.modifiers); else { CheckAnswer: c=SenseNumberTyped(ebH); if (c==ans) { state.Correct++; break; } Beep(); hEBEmphasise(ebH,FALSE); if (Complain(a,b,c)) break; DisplayScores(); state.Tested++; hEBEmphasise(ebH,TRUE); SelectAll(ebH); ClearBarChart(); InitialiseTimer(); } } DatLocked=FALSE; hEBClose(ebH); ClearBottomArea(); DisplayPressButton(); CancelTimer(); } LOCAL_C VOID MakeButtonDance(VOID) { DrawButton(TRUE); wFlush(); p_sleep(2); DrawButton(FALSE); wFlush(); p_sleep(2); } LOCAL_C VOID DoTest(VOID) { MakeButtonDance(); DisplayQuestion(); DisplayScores(); } LOCAL_C VOID MainLoop(VOID) { INT ret; WMSG_KEY key; FOREVER { uGetKey(&key); if (key.keycode&W_EVENT_KEY) { if (key.keycode==CONS_EVENT_COMMAND) ExitApplication(); } else if (key.keycode&W_SPECIAL_KEY) TryExecuteCommand(key.keycode&(~W_SPECIAL_KEY)); else if (key.keycode==W_KEY_MENU && !(key.modifiers&W_CTRL_MODIFIER)) { ret=uPresentMenus(); if (ret>0) TryExecuteCommand(ret); } else if (key.keycode==W_KEY_RETURN) DoTest(); } } LOCAL_C VOID ReadState(VOID) { INT len; UBYTE buf[P_ENVMAX]; len=p_getenviron(EnvName,ENV_NAME_LEN,&buf[0]); if (len<0 || len!=sizeof(TSTATE)) return; p_bcpy(&state,&buf[0],sizeof(TSTATE)); } LOCAL_C VOID InitSeed(VOID) { seed=p_date(); } LOCAL_C VOID ReduceScreenSize(VOID) { W_WINDATA wd; wd.extent.tl.x=wd.extent.tl.y=0; wd.extent.width=189; wd.extent.height=80; wSetWindow(MainWid,W_WIN_EXTENT,&wd); if (uErrorValue(wCheckPoint())) p_exit(0); } LOCAL_C VOID CreateGC(VOID) { INT hgc; hgc=gCreateGC0(uFindMainWid()); if (hgc<0) p_exit(hgc); } LOCAL_C VOID SpecificInit(VOID) { uEscape(FALSE); hCrackCommandLine(); MainWid=uFindMainWid(); ReduceScreenSize(); CreateGC(); gBorder(W_BORD_CORNER_4); wsEnable(); ReadState(); Display(); InitSeed(); p_open(&timH,"TIM:",-1); } GLDEF_C VOID main(VOID) { uCommonInit(); SpecificInit(); MainLoop(); }