/***************************************************************************/ /* ** HARJOITUS.C ** ** ** Ohjelman avulla voidaan harjoitella kielioppirakenteita. Ohjelma lukee ** lauseet ja harjoiteltavat kielioppirakenteet tiedostoista. ** ** ** Ohjelman k„„nt„mist„ varten tarvitaan seuraavat tiedostot: ** ** ANSI C:n mukaiset kirjastot ** mjonot.h (ja mjonot.c tai mjonot.obj) ** ** ** ** Tekij„t: Anne Kankaanp„„ ** Ohjelmointikurssi 1992 ** Tehty: ** Muutettu: ** Mit„ muutettu: ** */ #include #include #include #include "mjonot.h" /***************************************************************************/ /* ** HARJOITUS.H ** ** ** Tiedosto sis„lt„„ harjoitus-ohjelman tarvitsemat yleiset ** vakiot ** tietotyypit ** globaalit vakiotyyliset muuttujat ** makrot ** aliohjelmien otsikot ** ** */ /***************************************************************************/ /* ** Vakiot */ #define MAX_LAUSEITA 10 /* Harjoituksen lauseiden maksimim„„r„ */ #define TARKENNIN ".DAT" /* Tiedostonimen tarkennin */ #define TYHJA_ARVO -1 /* Arvo joka kuvastaa tyhj„„ num. kentt„„ */ #define VAIN_ISOT 1 /* Muutetaan isot ja pienet isoiksi */ /***************************************************************************/ /* ** Tietotyypit ** ** Tietorakenteen kuva ks. harjrak.c */ typedef struct{ /* Yhden lauseen tyyppi: */ char lause[300]; /* Lause esim. muodossa: Why did you arrive? */ int vastaus; /* Vastaus kokonaislukumuodossa: 5 */ char ilmaus[40]; /* Ilmaus= harjoiteltava rakenne: so late */ } Lause_tyyppi; /* */ typedef struct { /* Harjoituksen yleiset tiedot: */ char harjoituksen_nimi[30]; /* Harjoituksen t„ydellinen nimi */ char tiedoston_nimi[30]; /* Nimi talletuksessa */ char otsikko[30]; /* Harjoituksen otsikko esim.aika-adverbit */ char termi[30]; /* Harjoiteltava rakenne esim. adverbi */ int max_lauseita; /* Maksimi lausem„„r„ */ int lauseita; /* Lauseita t„ll„ hetkell„ */ Lause_tyyppi **lauseet; /* Osoitin lauseosoitintaulukon alkuun */ } Harjoitus_tyyppi; /* */ /***************************************************************************/ /* ** Globaalit (vakio!) muuttujat */ /***************************************************************************/ /* ** Makrot */ /***************************************************************************/ /* ** Aliohjelmat ** ** Aliohjelmia on seuraavissa tiedostoissa: ** harjali.c - yleisi„ aliohjelmia harjoitusta varten ** lue_merkki - lukee yhden merkin n„pp„imist”lt„ ** (laiteriippuva) ** odota_nappain - odottaa yhden sallitussa joukossa olevan ** n„pp„imen painamista ** jono_intiksi - muuttaa jonon kokonaisluvuksi ** kylla_vastaus - odottaa K tai E n„pp„imen painallusta ** ei_toimi - tulostaa "Ei toimi" ** ** harjrak.c - harjoituksen rakennetta k„ytt„vi„ aliohjelmia ** luo_lausetaulukko - luo lauseosoitintaulukon ** lisaa_lause - lis„„ uuden lauseen rakenteeseen ** tulosta_oikea - tulostaa oikean lauseen ** kysy_lause - kysyy harjoiteltavan kielioppikohdan ** oikeaa paikkaa lauseessa. Palauttaa ** tiedon kuinka monta kertaa piti yritt„„ ** ennne kuin lause tuli oikein ** numeroi_lause - lause numeroidaan harjoittelua varten ** etsi_oikean_paikka - etsit„„n oikea paikka(numero) lauseessa ** johon ilmaus sijoitetaan ** tulosta_lause - tulostaa lauseen valittuun tiedostoon ** harjoittele - kielioppikohdan varsinainen harjoittelu ** vapauta_lause - vapauttaa lauseosoitintaulukon ** ** harjtal.c - harjoituksen lukeminen tiedostosta ** lisaa_lause_rivi - lisaa uuden lauseen ** kysy_harjoitus - kysyy harjoituksen nimen ja lukee tiedot ** levylt„ */ /***************************************************************************/ /* ** HARJALI.C ** ** Harjoitus- ohjelman yleisi„ aliohjelmia. ** ** Aliohjelmat: ** lue_merkki - lukee yhden merkin n„pp„imist”lt„ ** odota_nappain - odottaa yhden vain sallitussa joukossa ** olevan n„pp„imen painallusta ** kylla_vastaus - odottaa K tai E n„pp„imen painallusta ** ei_toimi - tulostaa viestin "Ei toimi" ** jono_intiksi - merkkijono kokonaisluvuksi */ /***************************************************************************/ char lue_merkki(void) /* N„pp„imist”lt„ luettu merkki. */ /* ** Funktiolla luetaan n„pp„imist”lt„ yksi merkki. Mik„li ohjelmassa ** ei ole m„„ritelty vakiota GETCH, vaaditaan RET-n„pp„imen painallus. ** Globaalit: GETCH - m„„ritys ** Sy”tt”: N„pp„imist” ---------------------------------------------------------------------------*/ { /* Seuraava toimii mm. Turbo c:ss„: */ #ifdef GETCH return getch(); #else /* Seuraava on standardin mukainen: */ char s[50]; fgets(s,50,stdin); return s[0]; #endif } /***************************************************************************/ char /* */ odota_nappain( /* = p„„tteelt„ luettu merkki */ char *kelpaavat, /* s Ne merkit, jotka hyv„ksyt„„n. */ char oletus, /* s Merkki joka pal. mik„li pain. RET */ int isot /* s Jos !=0 niin isot ja pienet samaistetaan. */ ) /* ** P„„tteelt„ luetaan merkki. Jos isot ja pienet kirjaimet halutaan ** samaistaa (isot!=0), niin muutetaan luettu merkki isoksi. ** Jos oletus ei ole 0-merkki ja ollaan tilanteessa rivinvaihto ** tai return- n„pp„imen painallus palautetaan oletus. ** T„m„ toistuu kunnes ollaan luettu merkki joka kuuluu ** sallittuun joukkoon (kelpaavat). ** Jos sallittu joukko on NULL niin kaikki painetut kelpaavat ---------------------------------------------------------------------------*/ { char painettu; do{ painettu=lue_merkki(); if (isot) painettu = isoksi (painettu); if (oletus && ((painettu=='\n') || (painettu=='\r')) ) return oletus; } while ( kelpaavat && !strchr(kelpaavat,painettu) ); return painettu; } /***************************************************************************/ int /* */ jono_intiksi( /* */ char *jono, /* Kokonaisluvuksi muutettava mjono */ char *formaatti /* Formaatti jota muunnoksessa k„yt. */ ) /* ** Funktiolla muutetaan merkkijono kokonaisluvuksi. Mik„li jono on tyhj„ ** palautetaan TYHJA_ARVO ** ---------------------------------------------------------------------------*/ { int i=TYHJA_ARVO; sscanf(jono,formaatti,&i); return i; } /***************************************************************************/ int kylla_vastaus(void) /* 1 jos painettiin K tai RET ja 0 jos E */ /* ** Funktiolla odotetaan kunnes painetaan K tai E tai RET ** Tulostus: N„yt”lle rivin vaihto. ---------------------------------------------------------------------------*/ { int palautus; palautus = (odota_nappain ("KE",'K',VAIN_ISOT)=='K'); printf("\n"); return palautus; } /***************************************************************************/ void ei_toimi( /* */ Harjoitus_tyyppi *harjoitus /* s Ei valitusta k„ytt„m„tt”myydest„ */ ) /* ** Funktiolla tulostetaan teksti ei toimi. ---------------------------------------------------------------------------*/ { printf("\nEi toimi viel„!\n \n "); if (harjoitus->lauseita==0); } /***************************************************************************/ void selitys(void) /* ** Funtiolla tulostetaan mit„ ohjelmalla voidaan tehd„. ** Tulostus: N„ytt””n ---------------------------------------------------------------------------*/ { printf("\n\n"); printf("HEI!\n"); printf("TŽMŽN OHJELMAN AVULLA VOIT HARJOITELLA KIELIOPPIRAKENTEITA.\n"); } /***************************************************************************/ void ohje( /* */ Harjoitus_tyyppi *harjoitus /* s,t Harjoitus jota k„sitell„„n */ ) /* ** Funktiolla tulostetaan miten pit„„ toimia. ** Tulostus: N„ytt””n ---------------------------------------------------------------------------*/ { printf("\n\n"); printf("%s\n",harjoitus->otsikko); printf("=============\n \n"); printf("ASETA %s OIKEAAN PAIKKAAN LAUSEESSA ANTAMALLA KEHOITTEEN \n",harjoitus->termi); printf("PERŽŽN MIELESTŽSI OIKEA NUMERO.\n"); } /***************************************************************************/ /* ** HARJRAK.C ** ** Harjoituksen rakenteeseen oleellisesti liittyvi„ aliohjelmia ** ** Aliohjelmat: ** tulosta_lause -tulostaa lauseen valittuun tiedostoon ** vastaa_lause -vastaa yhden lauseen (testej„ varten) ** lisaa_lause -lis„„ uuden lauseen rakenteeseen ** luo_lausetaulukko -luo lauseosoitintaulukon ** kysy_lause -kysyy ilmauksen paikkaa ** numeroi_lause -numeroi lauseen harjoittelua varten ** etsi_oikean_paikkaa -etsii oikeaa paikkaa osoittavan numeron ** tulosta_oikea -tulostaa oikean lauseen, ilmaus oikealla ** paikalla ** harjoittele -tekee varsinaisen kielioppiharjoittelun ** vapauta_lause -vapauttaa lauseosoitintaulukon ** ** ** Yleinen tietorakenne: ** ** ** Harjoitustyyppi Lausetyyppi ** ------ ------- ** | | | | ** | 3 | |---->| | ------- ** | 2 | lauseet | | | | | ** | |------->|-----| | ------- ------->| | ** ------ | o--|-------| | | | ** |-----| | ------- ** | o--|-------------------------| ** |-----| ** | o--|---------? ** |-----| ** ** ** */ char *EI_VOI_LUODA = "Lauseille ei saada varattua tilaa muistista!"; /***************************************************************************/ char /* NULL =onnistui */ *luo_lausetaulukko( /* muut = virheilmoitus merkkijonona */ Harjoitus_tyyppi *harjoitus, /* t K„sitelt„v„ harjoitus */ int koko /* s Harjoituksen maxlausem„„r„ */ ) /* Funktiolla luodaan harjoitukseen tyhj„ osoitintaulukko lauseisiin. ** Mik„li lausetaulukkoa ei voida luoda, palautetaan virheilmoitus. ** Mik„li saadaan luotua, alustetaan se NULL-osoittimilla. ---------------------------------------------------------------------------*/ { int i; harjoitus->lauseet=malloc( koko * (sizeof(Lause_tyyppi*)) ); harjoitus->max_lauseita=koko; harjoitus->lauseita=0; if (!harjoitus->lauseet) return EI_VOI_LUODA; for (i=0;ilauseet[i]=NULL; return NULL; } /***************************************************************************/ int /* */ lisaa_lause( /* 0=onnistui 1=ei onnistu */ Harjoitus_tyyppi *harjoitus, /* s,t K„sitelt„v„ harjoitus */ Lause_tyyppi *lause /* s Lis„tt„v„ lause */ ) /* ** Funktiolla lis„t„„n harjoitukseen uusi lause. ---------------------------------------------------------------------------*/ { Lause_tyyppi *uusi_lause; if (harjoitus->lauseita >= harjoitus->max_lauseita) return 1; uusi_lause = malloc (sizeof (Lause_tyyppi)); if ( uusi_lause==NULL ) return 1; memcpy(uusi_lause,lause,sizeof(Lause_tyyppi)); harjoitus->lauseet[harjoitus->lauseita]=uusi_lause; harjoitus->lauseita++; return 0; } /***************************************************************************/ int /* */ kysy_lause( /* 0= vikoja en. kuin 1, 1= vikoja 0 */ Lause_tyyppi *lause /* s,t Lause jota k„sitell„„n */ ) /* ** Funktiolla tulostetaan ilmaus n„ytt””n ja odotetaan sen j„lkeen ** vastausta (eli jonkun hyv„ksytt„v„n n„pp„imen painamista). ** Jos n„pp„in v„„rin niin virheest„ ilmoitetaan, ilmaus annetaan uudelleen ** ja odotetaan j„lleen vastausta. Silmukkaa toistetaan niin kauan kunnes ** kaikki lauseet on k„yty l„pi. Lopuksi palautetaan tieto siit„ kuinka ** monta yrityskertaa tarvittiin oikeaan vastaukseen. ---------------------------------------------------------------------------*/ { int vastaus; int vikoja=0; do{ printf(" %s > ",lause->ilmaus); vastaus=odota_nappain(NULL,'u',VAIN_ISOT)-'0' ; if (vastaus=='u'-'0') continue; if (vastaus!= lause->vastaus){ printf(" LAUSE ON VŽŽRIN,YRITŽ UUDELLEEN.\n"); vikoja++; } }while(vastaus != lause->vastaus); if (vikoja==0) return 1; return 0; } /***************************************************************************/ void numeroi_lause( /* */ char *jono /* Parametri, johon lause luetaan */ ) /* ** Funktiolla numeroidaan tiedostosta luettu lause parametriin jono. ** Esim. lause 1. Why did you arrive? tulostetaan muotoon: ** 1 2 3 4 5 ** 1. Why did you arrive? ** Lauseen j„rjestysnumero katsotaan v„lily”nniksi. Ensimm„isen v„lin koh- ** dalle tulee nro 1. Jonoa menn„„n eteenp„in, jos jonossa merkkej„, niin ** silloin tulostetaan v„lily”nti, v„lily”nnin kohdalla jonossa tulostetaan ** seuraava numero. Jos on jo v„lily”nti, niin silloin tulostetaan numero. ** V„limerkit lasketaan v„lily”nneiksi. ** Lopetusmerkin kohdalle tulee viimeinen numero, kuten esimerkiss„ Why... ** Jos lauseessa ei ole lopetusmerkki„, niin silloin viimeinen numero tulos- ** tetaan viimeisen merkin j„lkeen esim. ** 1 2 3 4 ** You do it ** Ohjelmassa tulostetaan it sanan j„lkeen v„lily”nti, joten siihen tuloste- ** taan numero. Jos lause on esimerkiksi muotoa ..... , ..... niin v„li- ** merkin kummallekin puolelle tulostetaan numero. ---------------------------------------------------------------------------*/ { int nro=1; int on_vali=1; int i=0; int viim=strlen(jono)-1; while (ilause); } /***************************************************************************/ int etsi_oikean_paikka( /* */ char *jono, /* Parametri, johon lause luetaan */ int oikea /* osoittaa ilmauksen oik. paikkaa laus.*/ ) /* ** Funktiolla etsit„„n lauseesta se numero (v„li), johon harjoiteltava kie- ** lioppikohta tulee sijoittaa. Funktiota k„ytet„„n apuna tulosta_oikeaa ** varten. ---------------------------------------------------------------------------*/ { int nro=1; int on_vali=1; int i=0; int viim=strlen(jono)-1; while (ilause,lause->vastaus); varasto=lause->lause[paikka]; lause->lause[paikka]=0; printf("%s ", lause->lause); lause->lause[paikka] = varasto; printf("%s ", lause->ilmaus); if (lause->lause[paikka]==' ') printf(" "); printf("%s \n",lause->lause+paikka); } void vastaa_lause(Lause_tyyppi *lause) /*Tietorakenteen testausta varten*/ { strcpy(lause->lause, "Why did you arrive"); strcpy(lause->ilmaus, "so late" ); lause->vastaus= 5 ; } /***************************************************************************/ void harjoittele( /* */ Harjoitus_tyyppi *harjoitus /* s,t K„sitelt„v„ harjoitus */ ) /* ** Funktio tekee varsinaisen kieliopin "harjoittelun". Kaikki harjoituksen ** lauseet k„yd„„n l„pi. Yrityskerrat (ennen kuin vastaus on oikein) ** rekister”id„„n. Oikea lause tulostetaan, harjoiteltava termi on ** lauseessa oikealla paikallaan. Tulostetaan kuinka monta lausetta ** saatiin oikein heti ensimm„isell„ yritt„misell„. ---------------------------------------------------------------------------*/ { int i; int oikeita=0; printf("\n\n\n"); printf("------------------------------------------------------\n"); for (i=0; ilauseita; i++) { tulosta_lause(harjoitus->lauseet[i]); oikeita+=kysy_lause(harjoitus->lauseet[i]); tulosta_oikea(harjoitus->lauseet[i]); printf("------------------------------------------------------\n"); } printf("\n\n\n"); printf("SAIT HETI OIKEIN %d LAUSETTA.\n", oikeita); } /**************************************************************************/ void vapauta_lause( /* */ Harjoitus_tyyppi *harjoitus /* K„sitelt„v„ harjoitus */ ) /* **Funktiolla vapautetaan lausetaulukon varaama tila. --------------------------------------------------------------------------*/ { int i=0; for (i=0; ilauseita; i++){ free (harjoitus->lauseet[i]); } free(harjoitus->lauseet); } /**************************************************************************/ /* ** HARJTAL.C ** ** Harjoituksen tietojen levylt„ lukeminen. ** ** Aliohjelmat: ** lisaa_lause_rivi -lisaa uuden lauseen ** kysy_harjoitus -kysyy harjoituksen nimen ja ** lukee tiedot tiedostosta ** */ /**************************************************************************/ int /* */ lisaa_lause_rivi( /* 0 = lis„ys onnistui, 1 = lis„ys ep„on.*/ Harjoitus_tyyppi *harjoitus, /* s,t Harjoitus johon rivi lis„t„„n */ char *rivi /* s Rivi joka sis„lt„„ lis„tt„v„n laus. */ ) /*------------------------------------------------------------------------*/ { int j; char st[80]; Lause_tyyppi lause; kopioi_jono(lause.lause,(sizeof(lause.lause)),poista_tyhjat(palanen(rivi,"|",&j))); kopioi_jono(lause.ilmaus,(sizeof(lause.ilmaus)), poista_tyhjat(palanen(NULL,"|",&j))); kopioi_jono(st,(sizeof(st)),poista_tyhjat(palanen(NULL,"|",&j))); lause.vastaus = jono_intiksi(st,"%d"); return lisaa_lause(harjoitus,&lause); } static char *TIEDOSTO_VAARIN = "Tiedosto on v„„r„„ muotoa!"; static char *NIMEA_EI_ANNETTU = "Harjoituksen nime„ ei annettu!"; /***************************************************************************/ char /* NULL =onnistui */ *kysy_harjoitus( /* muut =virheilmoitus merkkijonona */ Harjoitus_tyyppi *harjoitus /* s,t harjoitus johon luetaan */ ) /* ** Funktiolla luetaan harjoituksen nimi. Mik„li tiedosto l”ytyy, luetaan ** tiedosto. ** ---------------------------------------------------------------------------*/ { #define PALAUTA(sanoma) {paluu_viesti = sanoma; goto sulje;} FILE *f; char jono[400],apu[50],*viesti,*paluu_viesti = NULL; int vikoja=0; int j; do{ /* Kunnes tiedosto on k„yty l„pi */ printf("\n\n"); printf("ANNA HARJOITUKSEN NIMI>"); if ( lue_jono(N_S(harjoitus->tiedoston_nimi)) <= OLETUS ) return NIMEA_EI_ANNETTU; kopioi_jono(N_S(jono),harjoitus->tiedoston_nimi); liita_jono (N_S(jono),TARKENNIN); if ( ! (f=fopen(jono,"rt")) ) { printf("KYSEISTŽ HARJOITUSTA EI L™YDY!\n"); } } while (!f); if ( f_lue_jono(f,N_S(jono))otsikko,(sizeof(harjoitus->otsikko)), poista_tyhjat(palanen(jono,"|",&j))); kopioi_jono(harjoitus->termi,(sizeof(harjoitus->termi)), poista_tyhjat(palanen(NULL,"|",&j))); while ( !feof(f) ) { if ( f_lue_jono(f,N_S(jono)) <= OLETUS ) continue; if ( jono[0] == ';' ) continue; kopioi_jono(N_S(apu),jono); if (lisaa_lause_rivi(harjoitus,jono)) { printf("*** Ei saada lis„tty„: %s ***+n",apu); vikoja++; } } sulje: fclose(f); if (vikoja) { printf("%d Lausetta j„i lis„„m„tt„!\n",vikoja); } return paluu_viesti; #undef PALAUTA; } /***************************************************************************/ void kiitos(void) /* Funktiolla tulostetaan kiitos ohjelman k„yt”st„. ** Tulostus: N„ytt””n ---------------------------------------------------------------------------*/ { printf("\n\n"); printf("KIITOS KŽYT™STŽ JA ONNEA OPISKELUUSI!\n"); } int main(void) { Harjoitus_tyyppi harjoitus; selitys(); do { kysy_harjoitus(&harjoitus); ohje(&harjoitus); harjoittele(&harjoitus); printf("\n\n"); printf("HALUATKO JATKAA?(K/E)>"); vapauta_lause(&harjoitus); } while(kylla_vastaus()); kiitos(); return 0; }