Oblig 4 (INF1000 - H?st 2011)

Filmregister  -  PDF utgave

[ Nye presiseringer er markert med gr?nn tekst. ]

M?l: I denne oppgaven vil du l?re hvordan man kan behandle en st?rre mengde data p? en objektorientert m?te, og f? trening i hele pensum. Oppgaven kombinerer alle programmerings-elementer vi har sett tidligere i kurset, i tillegg til HashMap.

Leveringsfrist

Fredag 11. nov kl. 16.00. Leveres i Joly. Viktig! Det blir sv?rt begrensede muligheter for ? levere nye fors?k i Oblig 4 eller ? f? mye utsetttelse. Kandidatlista til eksamen b?r v?re klar 14 dager f?r eksamen, dvs. 18. nov (bare én uke etter den vanlige fristen). Alle som skal ta eksamen b?r f? obligen sin godkjent f?r dette. Hvis det du leverer innen fristen ikke er ferdig m? du fortsette ? jobbe med obligen og levere ferdig utgave s? fort som mulig.

Leveringskrav

Som for tidligere oppgaver gjelder det at Oblig 4 skal leveres individuelt - to studenter kan alts? ikke levere felles eller kopier av samme l?sning. Kravene til innleverte oppgaver ved Ifi finner du her: www.mn.uio.no/ifi/studier/admin/obliger/. Retningslinjer for obligatoriske oppgaver finner du her: www.mn.uio.no/ifi/studier/admin/obliger/oblig-retningslinjer.html

L?sningen skal v?re objektorientert. Det betyr at programmet skal bruke objekter av klasser du selv definerer, og interaksjon mellom disse for ? l?se de forskjellige deloppgavene. Besvarelsen m? bruke minst 3 klasser og 2 HashMap-er, men du kan godt utvide dette med flere klasser, HashMap-er, og andre datastrukturer etter ?nske. Det skal leveres to ting: Hvis du har sp?rsm?l om obligen kan du skrive disse p? kurs-bloggen. Der vil det bli lagt ut svar og evt. andre tips og presiseringer til obligen. Du kan ogs? f? hjelp p? gruppen din, under orakeltjenesten (8. - 10. nov), p? ekstragruppen (rom Modula, fredager kl. 14.15 - 18), eller fra Studieoraklene (rom 3102 i 3. etg. OJD). Hvis du fortsatt savner opplysninger for noen deloppgaver kan du legge til grunn egne forutsetninger s? lenge de ikke bryter med oppgavens "?nd". Skriv i s? fall disse i kommentaren din ?verst i programmet.

Oppgave

I denne obligen skal du lage et kommandostyrt system som behandler informasjon om filmer. Programmet skal lese inn data fra f?lgende to datafiler, og gi brukeren mulighet til ? utf?re kommandoer som finner og viser frem forskjellig type informasjon om filmene. Programmet trenger ikke skrive til fil eller endre datafilene, og du skal ikke levere disse filene.
NB! Datafilene skulle bli oppdatert men er ikke blitt det enda. Utgavene som er lagt ut er ok men de mangler nyere filmer.

Filen filmdata.txt

Denne filen inneholder informasjon om filmer, med én linje for hver film. Hver linje har 6 eller flere felt, som er adskilt vha. et tabulator-tegn (dette skilletegnet angis som "\t" i Java):
kode  tittel  ?r  regiss?r  skuespillere;...   sjangre   [evt.tillegg]...
Noen filmer mangler data i felt 3-6 (regiss?r, skuespillere, eller sjangre), da st?r det "-" i feltet.

Filen persondata.txt

Denne filen har data p? to felt, adskilt med tabulator-tegn: kode, og fullt navn til en person. Her st?r navnene til alle regiss?rer og skuespillere som var angitt i den andre datafilen ved hjelp av kode.

Tips: Disse kodene hopper ikke over noen tall, f.eks. hvis det finnes ole9, s? vil ogs? ole1 til ole8 finnes. Dette kan du bruke til ? kunne s?ke raskere etter personer (eller filmkoder, som f?lger samme prinsipp) n?r bruker taster 3 bokstaver og ?nsker en liste over matchende personer eller filmer.

Kommandoene

Oppgaven din blir ? lage et program som kan lese inn disse to filene, og svare p? f?lgende typer kommandoer som bruker kan gi. Du kan velge hvordan du vil sette opp menyen, men det anbefales f?lgende meny:
Eksempler p? kommandoer du kan taste inn:
m      = Vis denne menyen
s      = Vis statistikk
Aaa1   = Vis info om en film
Aaa    = Finn film
tom1   = Vis info om en person
tom    = Finn person
2000s  = Vis info om et ti?r
2010   = [ Ekstraoppgave: Vis info om et ?r ]
:a     = [ Ekstraoppgave: Vis info om en sjanger ]
q      = Avslutt

Kommando ('m' = meny): _

Idéen her er at bruker kan taste inn en hvilken som helst av disse typer kommandoer, og programmet finner hva slags kommando ble gitt ut fra antall tegn i kommandoen og om disse tegn er sifre, bokstaver, eller andre tegn.

  1. Vis statistikk: Skal skrive ut totalt antall filmer, og antall filmer i hvert av ti?rene 1990-1999, 2000-2009, og 2010-2019.

  2. Vis info om en film: Skal la brukeren angi en film, og skriver deretter ut f?lgende informasjon om filmen: tittel, ?r, fullt navn til regiss?r, og fullt navn til skuespillerne. Du kan ogs? gi enda mer informasjon om filmen, f.eks. sjangre eller evt. serie som filmen tilh?rer. Til denne kommandoen skal brukeren angi film ved koden til en av filmene (f.eks. "Ava1" for Avatar).

  3. Finn film: Skriver ut informasjon om en film p? samme m?te som kommendoen over (Vis info om en film), men lar brukeren s?ke etter en film:

    • (a) s?k: Hvis bruker bare tastet inn tre bokstaver, og den f?rste er en stor bokstav, s? skal programmet skrive ut en liste med filmene hvor film-koden (og dermed ogs? tittelen) begynner med disse bokstavene, og brukeren skal kunne velge ?nsket film fra listen. Du kan bruke de unike film-kodene i datafilen til dette, disse ser bort fra "The " og "A " i begynnelsen av filmnavn.
    • (b) [ Ekstraoppgave: navn ]: Hvis du ?nsker det kan du ogs? implementere andre m?ter ? angi filmer p?, f.eks. med full tittel til filmen, eller med noen bokstaver fra begynnelsen av filmtittelen (f.eks. "Avat" eller "Avata" for Avatar).

  4. Vis info om en person, og Finn person: Skal fungere omtrent som kommandoene ovenfor, med de samme m?tene ? angi ?nsket person p? (men med sm? bokstaver i stedet). Informasjonen som vises skal inneholde filmene som personen regisserte og de som hun spilte i, med tittel og ?r.

  5. Vis info om et ti?r: Hvis brukeren taster inn fire tallsifre etterfulgt av bokstaven s (f.eks. 1990s), og siste tallsiffer er 0, s? skal programmet vise f?lgende: (a) ?Beste filmer?: Filmene som st?r i 2 eller flere av filmlistene 1-5 i det ti?ret. Filmlistene er angitt med kodene 1-5 i felt nr. 6 for hver film, f.eks. kode ?2? st?r p? filmer som har f?tt Oscar. (b) [ Ekstraoppgave: ?Mest aktiv regiss?r?: ] Skriv ut regiss?ren som lagde flest filmer det ti?ret.

  6. [ Ekstraoppgave: Vis info om et ?r: ] Hvis brukeren taster inn et ?rstall mellom 1900 og 2010 s? skal programmet vise f?lgende to ting om det ?ret: (a) ??rets film?: Hvilken film st?r i flest ?reslister (1-5) det ?ret; og (b) ??rets sjanger? blant comedy, fantasy, horror, eller science-fiction: her skal programmet finne hvilken av disse 4 sjangrene forekommer i flest filmer det ?ret, basert p? sjanger-kodene c, f, h, s. Skriv ogs? ut antall filmer resultatet er baserert p?.

  7. [ Ekstraoppgave: Vis info om en sjanger: ] Taster bruker kolon etterfulgt av en av bokstavene a, E, H, x (som st?r for a=action, E=eventyrfilm, H=superhero, x=disaster), s? skal programmet vise f?lgende to ting om valgt sjanger: (a) Skuespilleren som spilte i flest filmer i sjangeren; og (b) Navnene p? filmseriene som har minst en film innen sjangeren.

  8. [ Ekstra-ekstraoppgave: Filmliste: ] NB! Dette er en oppgave som gir deg mulighet til ? lage tilleggsfunksjonalitet som gj?r programmet mer nyttig for eget bruk - dersom du ?nsker for eksempel ? holde rede p? hvilke filmer du selv har, eller hvilke filmer du har sett, eller dine vurderinger av filmer du har sett. Legg til mulighet for brukeren til ? lage en liste av filmer. Du velger hvilke muligheter programmet gir brukeren, og hvordan du programmerer det, men legg til et menyvalg som forklarer funksjonalitet og fremgangsm?te til bruker. Listen som lages b?r lagres p? en egen datafil, f.eks. n?r programmet avsluttes, og hentes inn igjen n?r programmet starter.


Hint

Disse hint er ment for de som ?nsker litt ekstra-hjelp. Du trenger ikke lese dette avsnittet for ? l?se obligen, og det anbefales sterkt at du lager ditt eget forslag til datastruktur og gjerne skisserer dette i UML f?r du ser p? forslaget til programskall nedenfor. Da f?r du samtidig gjort deg godt kjent med oppgaveteksten. Dette vil du ha mye igjen for senere, selv om du skulle ende med ? bruke den ferdiglagede koden. Du kan ogs? sp?rre om og finne flere hint i bloggen. Det kan v?re lurt ? l?se litt enklere oppgaver f?r du g?r l?s p? deloppgavene i denne obligen, s?rlig Ukeoppgaver 9 om HashMap (som er hovedtemaet i obligen). Oppgavesettet har l?sningsforslag.
  1. Programskall:  Her er et eksempel p? et mulig skall for programmet, men du vil l?re mer med obligen hvis du setter opp programstrukturen din p? egen h?nd f?r du studerer dette eksemplet!

    /* Skriv en kommentar om din besvarelse her.
     * ...
     *
     * Leveringsm?te for UML-klassediagram: ...
     */
    import easyIO.*;
    import java.util.HashMap;
    
    class Oblig4 {
        public static void main(String[] args) {
            new Filmregister().ordrelokke();
        }
    }
    
    class Person {
        String kode;
        String navn;
    
        String filmerRegissert; // Filmkoder adskilt f.eks. med semikolon.
        String filmerSpilt; // Filmkoder adskilt f.eks. med semikolon.
    
        // filmerRegissert og filmerSpilt kan ogs? overf?res til arrayer av
        // Film[]-pekere n?r alle filmer er lagt inn; eller du kan lagre de
        // i sm? HashMap-er.  Se hint 3 for flere tips.
    
        // Evt. metoder for ? behandle en person.
    }
    
    class Film {
        // Variabler for dataene som gjelder for en film.
        // ...
    
        // Evt. metoder for ? behandle en film.
    }
    
    class TiAar {
        // Variabler for dataene som gjelder for et ti?r.
        // ...
    
        // Evt. metoder for ? behandle et ti?r.
    }
    
    class Filmregister {
        In tast = new In();
        Out skjerm = new Out();
    
        HashMap<String,Person> personer = new HashMap<String,Person>();
        HashMap<String,Film> filmer = new HashMap<String,Film>();
        TiAar[] tiaar = new TiAar[14]; // [0]=1880-1889, ..., [13]=2010-2019
    
        /**
          * Konstrukt?r: Leser datafilene, lagrer innholdet i objekter av
          * klassene Person, Film, (og evt. TiAar), og putter Person- og
          * Film-objektene i HashMap-ene ?personer? og ?filmer?.
          */
        Filmregister() {
            // Leser datafilen "persondata.txt":
            In fil = new In("persondata.txt");
            fil.inLine(); // Hopp over f?rste linje, som ikke har data.
            while (! fil.endOfFile()) {
                // Les en linje fra datafilen:
                String kode = fil.inWord();
                String navn = fil.inLine();
    
                // Opprett Person-objekt, og lagre det i HashMap-en ?personer?.
                // ...
    
                //skjerm.out(kode.charAt(0)); // Testutskrift.
            }
            fil.close();
    
            // Leser datafilen "filmdata.txt":
            fil = new In("filmdata.txt");
            fil.inLine(); // Hopp over f?rste linje, som ikke har data.
            while (! fil.endOfFile()) {
                // F?lgende setning leser inn en hel linje fra datafilen og
                // oppretter en array med de forskjellige feltene i linjen.
                // felt[0] vil da inneholde filmkoden, felt[1] tittel, osv.
                String linje = fil.inLine();
                String[] felt = linje.split("\t");
    
                // Opprett Film-objekt med de innleste felt-datane, og evt.
                // TiAar-objekt hvis det ikke finnes allerede, og lagre
                // filmobjektet i HashMap-en ?filmer?.
                // ...
    
                // For ? teste om det var flere enn 6 felt i linjen kan
                // du bruke if-setningen: if (felt.length > 6).
    
                skjerm.out(felt[0].charAt(0)); // Testutskrift.
            }
            fil.close();
        }
    
        /** Ordrel?kke: */
        void ordrelokke() {
            String ordre = ""; // Kommandoen som bruker taster inn.
            char char0 = 'm'; // F?rste tegn i kommandoen.
    
            visMeny();
    
            while (! ordre.equals("q")) {
    
                // Skriv ut ledetekst og les inn en ordre fra tastatur.
                skjerm.out("Kommando ('m' = meny): ");
                ordre = tast.readLine();
    
                int ordreLengde = ordre.trim().length();
                if (ordreLengde > 0) {
                    char0 = ordre.charAt(0);
                }
    
                if (ordreLengde == 1 && char0 == 'm') {
                    visMeny();
    
                } else if (ordreLengde >= 3 && char0 >= 'A' && char0 <= 'Z') {
                    visInfoOmFilm(ordre);
    
                } // else if ...osv...
    
                // Skriv en else-if gren for hver ordretype.
            }
        }
    
        void visMeny() {
            // Legg til de andre linjene av menyen her.
            skjerm.outln("\nMeny:");
            skjerm.outln("m      = Vis meny");
            skjerm.outln("q      = Avslutt");
        }
    
        void visInfoOmFilm(String kode) {
            // Vis info om filmen som har angitt kode (inn-parameter).
        }
    
        // Lag en metode for hver ordre her.  Disse metodene kan
        // kalle p? metoder i de andre klassene.
    }
    


  2. UML-klassediagram:  Se eksempel p? side 236 i l?reboka. Du kan bruke nesten et hvilket som helst tegneprogram for ? lage diagrammet p? datamaskin (hvis du vil levere det via innleveringssystemet eller mail), eller du kan scanne inn en papir-tegning. Det er scanner ved ekspedisjonen i 4. etg. OJD og p? Abel-stua (kjelleren i Matematikk-bygningen). Hvis du velger elektronisk levering, skal du bruke en av disse filtypene: .pdf, .jpg, .png, .gif, (eller .txt). UML-klassediagrammer ble gjennomg?tt i Ukeoppgaver 7.

  3. String contains og split:  For ? teste om en film tilh?rer en sjanger kan du bruke den forh?ndsdefinerte metoden ?contains? for tekster, f.eks. hvis ?sjangre? er en String-variabel med det som sto i felt 6 for filmen ?film?, s? vil f?lgende if-setning teste om filmen er en action-film:
    if (film.sjangre.contains("a")) { // ...
    
    Tilsvarende kan du teste for koder p? mer enn ett tegn, men det fungerer best hvis du legger til et skilletegn p? slutten av teksten man skal lete i, f.eks. hvis du har valgt ? lagre skuespillerlista til en film i en String-variabel ?stars?, og plusset p? skilletegn bak (stars = stars + ";";), s? kan du teste om Sandra Bullock spiller i filmen slik:
    if (film.stars.contains("san1;")) { // ...
    
    Dette gjelder hvis du lagrer skuespillerlisten til en film i en String-variabel. To andre m?ter ? lagre slike sm? lister p? er som en array (som kan opprettes vha. stars.split(";")) eller i en liten HashMap. Du kan se et eksempel p? split i koden ovenfor. NB! Tekst-verdien du bruker split p? skal ikke inneholde skilletegnet helt foran, s? hvis teksten har ";" som f?rste tegn b?r dette fjernes (f.eks. vha. substring) f?r man utf?rer split(";"), hvis ikke kan man f? en tom streng som f?rste resultat av split.

  4. keySet og substring:  Du vil f? bruk for metodene for manipulasjon av HashMap-er og String-er, disse kan du lese mer om i kapittel 6 og 9 i l?reboka, les bl.a. om substring, indexOf, startsWith, parseInt, og split p? side 105-114 om tekster; og om put, get, keySet, values, size, og containsKey p? side 181-192 om HashMap-er.

  5. Store og sm? bokstaver:  Det er mange m?ter ? teste om et tegn i ordren som brukeren tastet inn er stor eller liten bokstav. Her er tre mulige m?ter, velg en av dem:
    if (tegn >= 'A' && tegn <= 'Z') { // ...
    if (Character.isUpperCase(tegn)) { // ...
    if (ordre.toLowerCase().equals(ordre)) { // ...
    
    Den f?rste m?ten er ogs? vist i siste else-if i koden ovenfor og g?r ut p? ? teste om et gitt tegn er mellom 'A' og 'Z', i s? fall vet vi at det er en stor bokstav. Bruk 'a' og 'z' for ? teste for sm? bokstaver. Neste if-setning viser bruk av den forh?ndsdefinerte metoden isUpperCase(tegn) til klassen Character, denne klassen er alltid tilgjengelig i Java, p? samme m?te som String. Bruk isLowerCase(tegn) for ? teste for sm? bokstaver. Siste alternativ viser hvordan du kan teste om alle bokstaver i en ordre er sm? bokstaver.

  6. Tall eller bokstav:  Det er ogs? mange m?ter ? finne ut om et gitt tegn er et tallsiffer:
    if (tegn >= '0' && tegn <= '9') { // ...
    if (Character.isDigit(tegn)) { // ...
    if (ordre.matches("[0-9]+")) { // ...
    
    Siste alternativet tester om hele ordren best?r av bare tallsifre ("[0-9]" matcher et hvilket som helst tall, og "+"-tegnet betyr ?en eller flere forekomster?). Det fins ogs? Character.isLetter(tegn) for ? teste om et tegn er en bokstav.

  7. Er ordren et ti?r? (NB: F?lgende er ikke pensum). Du kan ogs? bruke f?lgende til ? teste om bruker ga ordren om ti?r:
    if (ordre.matches("[0-9][0-9][0-9]0s")) { // ...
    
    Spesielt interesserte kan lese mer om dette i Java API-en under String.matches(regex) og regular expression (se ogs? side 114 i l?reboka).

  8. Lesing av 6 eller flere felt:  Linjene i datafilen "filmdata.txt" kan inneholde 6 eller flere felt adskilt med tabulator-tegnet. En enkel m?te ? lese datafilen p? som tar h?yde for dette er vist i koden ovenfor der det st?r split("\t"). Og for ? sjekke om 7. felt er serienavn kan du bruke if (felt[6].startsWith("s=")).

  9. String til int og tilbake:  Man kan konvertere fra String til int ved hjelp av parseInt slik:
    int tall = Integer.parseInt(tekstVerdi);
    
    Her skal tekstVerdi v?re en String som bare inneholder tallsifre. Bruk tekstVerdi.substring(f_o_m, til) for ? plukke ut ?nsket del-streng hvis tallsifrene er blandet med andre tegn i tekstVerdi. Du kan lese mer om substring p? side 105-106 i l?reboka, eller i Java API-en under String.

    Det omvendte, konvertering fra int til String, kan ordnes ved ? plusse p? den tomme strengen:
    String tekst = "" + intVerdi;
    

  10. Info om innlevering:  Joly krever at f?rste fil som legges inn i en innlevering er en .java-fil, derfor kan du ikke levere UML-diagrammet alene i Joly. Hvis du valgte leveringsm?te (a) for diagrammet (dvs. sammen med .java-filen), s? legger du inn begge filene i samme levering i Joly: F?rst legger du inn Oblig4.java, og s? legger du inn UML-diagrammet ditt som tilleggsfil.

    Du kan diskutere med andre studenter hvordan dere skal l?se oppgaven, men det er ikke lov ? kopiere noe Java-kode fra dem, selv om du endrer p? koden etterp?; og det er heller ikke lov ? hente programbiter fra andre besvarelser, for eksempel fra Internet. Hvis du diskuterer mye med en annen student skriv hvem det gjelder i kommentaren din ?verst i programmet (da unng?r du mistanke om at du pr?vde ? skjule dette, n?r vi oppdager det i likhets-kontrollen vi foretar med innleveringene).

Kilder

Alle dataene som st?r i datafilene er tatt fra Wikipedia og TMDb (disse er valgt fordi de er ?pne og krever ikke lisens for bruk). Filmlisten er tatt fra de alfabetiske listene over "filmer som har egen Wikipedia-side".

Hvis du har sp?rsm?l, kommentarer, eller rettelser til obligen kan du skrive de i kurs-bloggen eller maile de til meg, josek [at] ifi.uio.no..