Oblig 4 (INF1000 - Vår 2010)
FilmregisterMå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, og innfører datastrukturen "HashMap".
Leveringsfrist
Fredag 7. mai kl. 16.00. Leveres via Joly-systemet. (Joly kan brukes hjemmefra vha. VPN eller lignende.)Leveringskrav
Løsningen du lager 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.- Oblig4.java:
Denne filen skal inneholde det ferdige Java-programmet ditt (all Java-kode
skal ligge i én fil). Før du leverer lag en kommentar øverst
i Oblig4.java der du skriver noe om besvarelsen din generelt,
f.eks. om du ikke klarte å bli ferdig med en deloppgave, eller at
du fullførte alle deloppgavene. Skriv også hvilken leveringsmåte du
valgte for UML-klassediagrammet (se neste punkt).
- UML-klassediagram: Du skal levere et UML-klassediagram over systemet ditt. Diagrammet skal inneholde navnene på klassene, og de viktigste koblingene mellom disse, illustrert som forhold (linjer) mellom klassene. Gi navn på forholdene, og angi antall på begge sider av disse. Du skal velge en av følgende 3 måter å levere diagrammet på. Skriv hvilken du valgte øverst i Oblig4.java: på papir, elektronisk via Joly, eller via mail. Se hint 2 nedenfor for tips om UML-klassediagrammer. For elektronisk levering bruk en av disse filtypene: .pdf, .png, .gif, .jpg, .txt. For å levere på papir gå på gruppetimen.
- filmdata.txt:
Tekstbasert datafil med informasjon om filmer. Filen er lagt
ut i to forskjellige tegnsett, velg et av dem:
- filmdata.txt: (ASCII-enkoding, passer alle plattformer men tar ikke vare på aksenter).
- filmdata.utf8.txt: (UTF-8, tar vare på utenlandske bokstaver og lignende).
- persondata.txt: (ASCII).
- persondata.utf8.txt: (UTF-8).
Oppgaven skal løses individuelt. Det forutsettes at du har lest
og forstått kravene til innleverte oppgaver ved Ifi:
Oppgave
I denne obligen skal du lage et kommandostyrt system som behandler informasjon om filmer. Programmet ditt skal lese inn to datafiler, og gi mulighet til brukeren for å utføre kommandoer som finner og viser frem forskjellig type informasjon om filmdataene som ble lest inn. Programmet ditt trenger ikke skrive til fil eller endre datafilene.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):Noen av de siste feltene kan mangle data, og da står det "-" i feltet.kode tittel år regissør skuespillere;... sjangre [evt.tillegg]...
- kode er en unik kode for hver film, og består av tre store bokstaver etterfulgt av et tall (som går fra 1 og oppover).
- tittel og år er navn på filmen og året den kom.
- regissør er en kode som angir regissøren til filmen, og består av tre små bokstaver etterfulgt av et tall (som går fra 1 og oppover).
- skuespillere er en rekke med koder som angir skuespillere, disse angis på samme måte som regissør, men kan være flere og er da adskilt med semikolon (";").
- sjangre er en sammenhengende tekststreng som angir sjangre
for filmen, i form av enkelt-bokstav-koder og enkelt-sifre.
Tallsifrene angir om filmen forekommer i forskjellige lister.
Vi skal bare bruke noen få av disse kodene i oppgaven, men her er
hele listen:
a=action A=animation b=biographical c=comedy C=children D=documentary d=drama e=epic E=adventure f=fantasy g=computer_animation(datagrafikk) h=horror H=superhero k=crime m=musical n=film_noir r=romantic_comedy R=romance s=science_fiction S=sports t=thriller w=war W=western x=disaster
1=Står i listen Films considered the greatest ever fra Wikipedia
2=Står i listen List of Academy Award-winning films (filmer som fikk Oscar)
3=Står i listen Palme d'Or (filmer som vant i Cannes)
4=Står i listen Sight & Sound (liste omtalt i link 1= ovenfor).
5=Står i listen AFI's 100 Years... 100 Movies (10th Anniversary Edition) - [evt.tillegg]: For noen av filmene er det mer enn 6 felt i linjen. Vi skal bare bruke felt 7, som heter s=Serienavn, dette står på filmer som er del av en serie, f.eks. i James Bond-filmene står det "s=James Bond".
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 med bare 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.P.S. Det er litt feil og mangler i datafilene, men disse påvirker ikke en løsning av obligen. Du trenger altså ikke laste ned evt. senere utgaver av datafilene for å løse obligen (men spesielt interesserte kan se om rettelser er lagt ut ved å se på fildatoene).
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:(*): Kommandoene markert med stjerne er valgfrie ekstra-oppgaver, men det anbefales å løse disse også.Eksempler på kommandoer du kan taste inn: . = Vis statistikk AAA1 = Vis info om en film AAA = Finn film tom1 = Vis info om en person tom = Finn person 90 = Vis info om et tiår 2009 = Vis info om et år (*) a = Vis info om en sjanger (*) ? = Vis meny q = Avslutt Kommando ('?' = 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 punktum. Men hvis du foretrekker det kan du også bruke to-stegs kommandoer som i oblig 2 og 3 (menyvalg etterfulgt av spørsmål til bruker).
- Vis statistikk: Skal skrive ut totalt antall filmer,
og antall filmer i hvert av tiårene 1980-1989, 1990-1999, og 2000-2009.
- Vis info om en film, og Finn 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.
Brukeren skal kunne angi film på minst 2 forskjellige måter:
- kode: Hvis det som brukeren tastet inn var koden til en av filmene (f.eks. "AVA1" for Avatar), skal info om den filmen skrives ut.
- søk: Hvis bruker bare tastet inn tre bokstaver, og det første (eller flere) er store bokstaver, så skal programmet skrive ut en liste med filmene hvor tittelen (film-koden) 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.
- navn (valgfri ekstra-oppgave) (*): Hvis du ønsker det kan du også implementere andre måter å angi filmer på, f.eks. med full tittel til filmen eller full tittel etterfulgt av år. Du kan også gi enda mer informasjon om filmen, f.eks. sjangre eller evt. serie som filmen tilhører.
- Vis info om en person, og Finn person: Skal fungere
omtrent som kommandoen ovenfor, med de samme 2 eller 3 måter å 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.
- Vis info om et tiår: Hvis brukeren taster inn to tallsifre,
og det siste er 0, skal programmet vise følgende to ting:
(a) «Mest aktiv regissør»: Regissøren som lagde flest filmer det tiåret, og
(b) 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.
- 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 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å; og (b) Hvilken film står i flest
æreslister (1-5) det året (uten hensyn til sjanger).
- Vis info om en sjanger (*): Taster bruker bare 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.
Hint
Disse hint er bare for de som ønsker litt ekstra-hjelp. Det kan også bli lagt ut flere ekstra-hint senere, men obligen kan altså godt løses uten å lese noen av hintene.-
Programskall: Her er et eksempel på et mulig skall for programmet,
men du kan lære mer med obligen hvis du setter opp programstrukturen din
på egen hånd før du ser på dette eksemplet!
/* Skriv en kommentar om din besvarelse her. * ... * * Leveringsmåte for UML-diagram: ... */ import easyIO.*; import java.util.HashMap; class Oblig4 { public static void main(String[] args) { new Filmregister().ordreløkke(); } } class Person { String kode; String navn; boolean erRegissør; boolean erSkuespiller; String filmerRegissert; // Filmkoder adskilt f.eks. med semikolon. String filmerSpilt; // Filmkoder adskilt f.eks. med semikolon. // filmerRegissert og filmerSpilt kan også deklareres som HashMap-er // eller f.eks. overføres til arrayer av Film[]-pekere når alle filmer // er lagt inn. Se hint 3 for flere tips. // Evt. metoder for å behandle en person. } class Film { // Variabler for dataene som gjelder en film. // ... // Evt. metoder for å behandle en film. } class TiAar { // Variabler for dataene som gjelder 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[] tiår = new TiAar[11]; // [0]=1900-1909, ..., [10]=2000-2009 /** * 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(); } void ordreløkke() { String ordre = ""; // Kommandoen som bruker taster inn. char char0 = '?'; // Første tegn i kommandoen. visMeny(); while (! ordre.equals("q")) { // Skriv ut ledetekst og les inn en ordre fra tastatur. skjerm.out("Kommando ('?' = meny): "); ordre = tast.readLine(); int ordreLengde = ordre.trim().length(); if (ordreLengde > 0) { char0 = ordre.charAt(0); } if (ordreLengde == 1 && char0 == '?') { visMeny(); } else if (ordreLengde >= 3 && char0 >= 'A' && char0 <= 'Z') { visInfoOmFilm(ordre); } // else if ...osv... // Skriv en else-if gren for hver ordretype. } } void visMeny() { // Skriv ut meny her. skjerm.outln("..."); skjerm.outln("? = 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. }
- 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 Joly eller mail), eller du kan scanne inn en papir-tegning. Det er scanner på Abel- og VB-termstuen. Hvis du velger elektronisk levering, skal du bruke en av disse filtypene: .pdf, .png, .gif, .jpg, .txt.
-
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:
Tilsvarende kan du teste for koder på mer enn ett tegn, men det fungerer best hvis teksten man skal lete inn i har et skilletegn på slutten av koden man ser etter (eller både foran og bak), f.eks. hvis du har valgt å lagre skuespillerlista til en film i en String-variabel «stars», og plusset på skilletegn bakif (film.sjangre.contains("a")) { // ...
(stars = stars + ";";) , så kan du teste om Sandra Bullock spiller i filmen slik:
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.if (film.stars.contains("san1;")) { // ...
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ørersplit(";") , hvis ikke kan man få en tom streng som første resultat av split. - 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 104-111 om tekster; og om put, get, keySet, values, size, og containsKey på side 180-189 om HashMap-er.
-
Store og små bokstaver: Du kan teste om et tegn i ordren
som brukeren tastet inn er stor eller liten bokstav på mange
måter, her er tre alternative måter, velg en av dem:
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 store bokstaver.if (tegn >= 'A' && tegn <= 'Z') { // ... if (Character.isUpperCase(tegn)) { // ... if (ordre.toUpperCase().equals(ordre)) { // ...
- Lesing av 6 - 7 felt: Linjene i datafilen "filmdata.txt" kan inneholde 6 eller flere felt. 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 startsWith("s="). Det går også an å lese datafilen vha. fil.inWord("\t") og lignende. Dette leser inn felt som har mellomrom inni seg riktig, men da trenger du også en smart måte å skille mellom evt. 7. felt og begynnelsen av neste linje.
Kilder
All data som står i datafilene kommer fra Wikipedia. Film-listen er tatt fra disse alfabetiske listene.Kommentarer og rettelser til denne obligen kan sendes til josek [at] ifi.uio.no (Jose Luis Rojas K.)