UMEÅ UNIVERSITET Inst. för Datavetenskap 050602 DELPROV2 OBJEKTORIENTERAD PROGRAMMERING I JAVA FÖR INGENJÖRER, 5P. (TDBA62) Datum : 050602 Tid : 4 timmar (9-13) Hjälpmedel : Allt. Kommunikation med andra personer (direkt eller indirekt) är dock inte tillåten, som t ex via mail, mobiltelefon, gemensamma kataloger etc. Antal uppgifter : 4 Poäng : 32 (delprovet får ej underskrida 30% av poängtalet, halva poängtalet (dp1 + dp2) krävs normalt för godkänt) Provet består av 4 uppgifter: 1 och 2 samt två (2) fritt valda uppgifter bland 3,4,5, 6 & 7. Kryssa för de uppgifter du lämnar in. Källkod skrivs ut i ett ickeproportionellt typsnitt (t.ex. courier). Namn, personnummer, användarnamn(@cs.umu.se) och sökvägen till filen/filarna skall finnas på all källkod. Skriv din dators namn på försättsbladet. Lösningarna skall vara snyggt och prydligt nedskrivna. Tankegången skall vara lätt att följa. Alla antaganden som inte är uppenbara skall redovisas. Den kod som ges i denna skrivning finns under länken dp2050602 på kursens hemsida. Här finns också andra eventuella filer som du kan behöva. Denna mapp kallas i resten av provtexten för provmappen. OBS! Kontrollera att din dator fungerar innan du börjar. Lycka till! UMEÅ UNIVERSITET 901 87 UMEÅ Tel.: 090-786 77 08 Fax: 090-786 61 26 e-mail: marie@cs.umu.se
Innan du börjar skall du göra följande: 1. Logga in på Unix-systemet med hjälp av putty 2. Om du har gjort i ordning katalogerna edu och java gå till steg 3: Skapa en ny katalog >mkdir edu Skydda katalogen med följande kommandon: >chmod 700 edu/ >setfacl -r -m g:tdb:r-x edu/ Gå ned i katalogen edu >cd edu Skapa en ny katalog java >mkdir java Skydda katalogen: >setfacl -r -m g:tdb:r-x java/ 3. Gå till din katalog >cd java eller >cd /edu/java om du hoppat direkt hit efter steg 1 4. Nu skapar du en plats för provets filer i /edu/java-katalogen Skapa en ny katalog >mkdir dp2050602 Skydda katalogen: >setfacl -r -m g:tdb:r-x dp2050602/ 5. Testa din inställning genom att gå till adressen http://www.cs.umu.se/~schedin/rights/ och klicka på Testa rättigheter. Logga in med ditt användarnamn och lösenord (på cs) och testa katalogen edu/java/dp2050602 Observera att ditt prov inte kan rättas om vi inte får tillgång till dina filer! 2(2)
Regler för delprov 2 Provet är en del av examinationen och skall alltså ske under tentamensliknande förhållanden. Examinationen är individuell och betygsgrundande. Detta får följande konsekvenser: Man är personligt ansvarig för de lösningar som lämnas in. Om man hittar lösningar eller delar av lösningar på nätet eller i litteraturen bör detta tydligt anges och man är fortfarande skyldig att själv vara fullständigt insatt i den lösning man redovisar och på uppmaning kunna svara för innehåll och funktion i hela eller delar av lösningen. Självklart får man inte söka eller hämta kod från någon av de övriga tentanderna, detta betraktas som fusk och handläggs som sådant. Några riktlinjer för hur lösningarna bedöms: Koden skall följa god programmeringsmetodik, vilket t.ex. innebär konsekvent indenterad och lämpligt kommenterad källkod. Lösningen behöver inte gå att kompilera för att ge poäng, så låt inte troliga syntaxfel ta för mycket tid i anspråk om du känner dig övertygad om att du löst det givna problemet, det räcker därför inte att en lösning fungerar för att ge full poäng, även här måste man på ett rimligt sätt underordna sig kravet på god programmeringsmetodik. 3(3)
Uppgift 1 (6 poäng) Klassen LivsMedel nedan är given (filen finns i provmappen). Klassen LivsMedel är abstrakt eftersom den har en abstrakt metod. Härled klassen Mjol från LivsMedel så att du på lämpligt sätt återanvänder den befintliga koden och gör klassen Mjol instantierbar. * Livsmedel är basklass för olika kategorier av livsmedel, * som gryn, mjöl, vätska osv. * * @author (Marie & Lena) * @version (dp2_050602) public abstract class LivsMedel private int mgd; private String enhet; private String namn; private boolean kanfrysas; private int inkopsdatum; * Konstruktor för LivsMedel public LivsMedel(int mgd, int indat, String namn, boolean frysbar, String mgdenhet) this.mgd = mgd; kanfrysas = frysbar; inkopsdatum = indat; enhet = mgdenhet; this.namn = namn; public int getmgd() return mgd; //getmgd 4(4)
public String getenhet() return enhet; //getenhet public String getnamn() return namn; //getnamn * Jämförelse av livsmedel * * @param m livsmedel att jämföra med * @return true om this.getnamn() samma som m.getnamn() public boolean sammasom(livsmedel m) return (this.getnamn().tolowercase().equals(m.getnamn().tolowercase())); * Jämförelse * * @param m matobjekt att jämföra med (vikt eller volym) * @return -1 om this < m, 0 om lika och +1 om this > m public abstract int jmfrmed(livsmedel m); //LivsMedel Uppgift 2 (6 poäng) Du är delaktig i ett projekt som utvecklar en varuautomat. Automaten innehåller ett antal olika varor och man kan mata in mynt i valörerna 1, 5, 10 och 20 kronor. Systemet som utvecklas innehåller just nu klasserna Varuautomat och MyntSamlare. Klassen Myntsamlare används dels för att samla in mynten som kunden betalar in och dels för att ge korrekt växel tillbaka till kunden. Din uppgift är att skriva metoden gevaxel som ska ligga i klassen Varuautomat med följande signatur: public MyntSamlare gevaxel(myntsamlare betalt, int kostnad) Du behöver alltså inte bry dig om hur varuautomaten är konstruerad för övrigt. Du får in ett objekt betalt som innehåller de mynt kunden matat in och parametern kostnad är kostnaden för de varor kunden köpt. Metoden ska returnera ett objekt av klassen Myntsamlare där följande villkor är uppfyllda: om kunden betalt för lite ska det synas genom att antalet mynt i objektet är -1 om kunden betalt exakt den summa som matats in ska (så klart!) antalet växelmynt vara 0 i alla övriga fall ska myntens sammanlagda värde exakt uppgå till det eftersökta växelbeloppet ett så litet antal mynt som möjligt ska användas. Vi antar att det finns tillräckligt många mynt i automaten av varje valör. Koden till Myntsamlare finns på nästa sida (den fullständiga koden finns i provmappen). 5(5)
6(6)
* MyntSamlare är en samling mynt i en varuautomat * * @author Lena KW * @version dp2050602 public class MyntSamlare // Antalet mynt som finns i automaten private int enkronor; private int femmor; private int tior; private int tjugor; public MyntSamlare() enkronor = 0; femmor = 0; tior = 0; tjugor = 0; public void adderaenkronor(int antal) enkronor = enkronor + antal; public void adderafemmor(int antal) public void adderatior(int antal) public void adderatjugor(int antal) Fungerar som adderaenkronor public int antalenkronor() return enkronor; public int antalfemmor() public int antaltior() public int antaltjugor() Fungerar som antalenkronor * tostring returnerar en sträng som beskriver objektet public String tostring() return "Enkronor: " + enkronor + "\nfemkronor: " + femmor + "\ntiokronor: " + tior + "\ntjugokronor: " + tjugor; //tostring //MyntSamlare 7(7)
I den följande delen får du lämna in högst två av uppgifterna Uppgift 3 (6 poäng) Studentexpeditionen på datavetenskap dras med ett rätt ålderstiget system för att hålla reda på alla kurser och studenter. Du får chansen att föreslå en design för ett nytt system som underlättar administrationen av studenternas kursval, registreringar och resultat. I systemet ska studenterna kunna välja vilka kurser de vill gå en viss termin och lärarna får välja vilka kurser de vill undervisa i. Inför varje terminsstart kan studenterna och lärarna begära en lista med aktuella kurser för en viss termin och göra sina val. För varje kurs finns en övre och en undre gräns på antalet deltagare. För att planera sina studier måste det vara möjligt att kunna ta reda på hela kursutbudet (dvs. inte bara på den aktuella terminen). Studenterna får välja högst fyra kurser plus högst två kurser som alternativ (om någon av kurserna skulle ställas in). I systemet finns också information om schemat för varje kurs. När studenterna gör sina val får de ut ett övergripande schema, så att de kan se om kurserna krockar (och i så fall kunna välja andra kurser för att undvika detta). Systemet måste kunna kontrollera att en student bara söker till kurser där denna uppfyller förkunskapskraven. Notera att förkunskaperna kan ändras med tiden och att kurser ibland kan tillgodoräknas som andra kurser. Lämna in en UML-liknande beskrivning av designen som innehåller alla klasser och som visar hur de hänger ihop. Oavsett vilken notation du väljer (UML eller egen) måste du förklara vad ev. pilar och streck representerar. Observera att det inte duger med CRC-kort som beskrivning. För varje klass ska viktiga attribut, metoder och parametrar finnas med. Detta får du gärna lämna in handskrivet. Uppgift 4 (3+5=8 poäng) Utgå från följande interface: Interface för objekt som kan mätas public interface Measurable Beräknar måttet för objektet. @return the measure double getmeasure(); a) Implementera en klass Die som representerar en sex sidig tärning. Din tärningsklass ska implementera interfacet ovan (måttet blir i detta fall tärningens värde). Det ska förutom den metod som specificeras i interfacet finnas en metod för att slå tärningen. För att ta fram slumptalen kan ni använda er av metoden Math.random() som ger ett slumptal i intervallet 0-1 (exklusive 1) som ett värde av typen double. 8(8)
b) Skriv ett litet testprogram som visar hur din tärningsklass tillsammans med klassen DataSet nedan kan användas för att beräkna medelvärdet av 100 tärningsslag public class DataSet private double sum; private Measurable maximum; private int count; Skapar en tom datamängd. public DataSet() sum = 0; count = 0; maximum = null; Lägg till ett värde till datamängden. @param x värdet public void add(measurable x) sum = sum + x.getmeasure(); if (count == 0 maximum.getmeasure() < x.getmeasure()) maximum = x; count++; beräkna medelvärdet av datat. @return medelvärdet eller 0 om inget värde har lagts till public double getaverage() if (count == 0) return 0; else return sum / count; Ta fram det största värdet i datamängden. @return maxvärdet eller null om inget värde lagts till public Measurable getmaximum() return maximum; Koden finns i provmappen. 9(9)
Uppgift 5 (10 poäng) Ett vanligt sätt att implementera dynamiska datastrukturer (t.ex. träd, stackar och köer) i programspråk är att använda så kallade länkade listor. En länkad lista består av ett antal noder, som innehåller dels det data som man vill lagra i datastrukturen, dels en eller flera referenser till andra noder. En nod i en enkellänkad lista har en referens till nästföljande nod, såsom visas i bilderna nedan. Observera att den sista nodens next-referens har värdet null för att markera slutet på listan. En fördel med att implementera strukturer på detta sätt är att ingen onödig plats behöver reserveras, strukturen är aldrig större än det antal element den innehåller vid en viss tidpunkt. Se klassdiagram för klassen QNode, som innehåller ett flyttal: tail Så här kan ett antal noder vara länkade under körningen av ett program: head Referensvariabeln head håller reda på köns första nod, dvs. en referens till ett objekt av klassen QNode och referensvariabeln tail refererar till köns sista nod. En kö är en datastruktur som kan implementeras med hjälp av en enkellänkad lista. En kö fungerar som en vanlig (ideal) kö: när man kommer till kön ställer man sig sist och den som står först i kön är den som först lämnar den. Uttag görs alltså i början av kön, medan insättningar görs i sist i kön. Elementära funktioner för en kö är bl.a.: add get isempty lägger till ett element sist tar bort och returnerar första elementet kontrollerar om kön är tom Implementera klassen QNode enligt ovan. Skriv sedan kö-klassen Q, med åtminstone ovanstående metoder, som använder en lista av noder för att lagra elementen i kön. Följande testprogram skall fungera med din lösning: public class Test public static void testaq() Q q = new Q(); try double n0 = q.get(); //#0--finns inte! catch (NullPointerException e) System.out.println("Man kan inte ta bort element ur en tom kö!\n"); if (q.isempty()); System.out.println("Ny tom kö skapad!\n"); 10(10)
q.add(7.5); //#1 q.add(-44.1); //#2 q.add(34.9); //#3 q.add(12.34); //#4 q.printq(); double n1 = q.get(); //#1 double n2 = q.get(); //#2 q.printq(); if (q.isempty()) System.out.println("Kön är tom"); else System.out.println("Kön är inte tom"); q.printq(); //testaq //Test Testprogrammet finns i provmappen. Man kan inte ta bort element ur en tom kö! Ny tom kö skapad! Köns längd = 4 Kö[1] = 7.5 Kö[2] = -44.1 Kö[3] = 34.9 Kö[4] = 12.34 Köns längd = 2 Kö[1] = 34.9 Kö[2] = 12.34 Kön är inte tom Köns längd = 2 Kö[1] = 34.9 Kö[2] = 12.34 Uppgift 6 (8 poäng) I den här uppgiften bygger vi vidare på Livsmedels-uppgiften (uppgift 1). Nu skulle vi vilja ha en receptklass för att enkelt kunna kolla om det som finns hemma räcker för ett visst recept. Varje recept innehåller bl.a. en uppräkning av ingredienser. Dessutom ska receptet ha en metod som kan ta en lista av LivsMedel, jämföra den med receptets egna ingredienser och avgöra om dessa räcker för att tillreda det som receptet beskriver. Härled ytterligare två klasser från LivsMedel, så att du kan konstruera objekt av klassen Recept med mer än en sorts ingrediens. Konstruera sedan en metod i Recept som gör den beskrivna jämförelsen. Naturligtvis behöver inte livsmedlen komma i samma ordning i de båda listorna. Alla receptets ingredienser behöver inte finnas med i den lista man jämför med. För att veta att man jämför samma sorts livsmedel räcker det (i det här exemplet) att man jämför den sträng som representerar namnet. Du behöver inte heller kontrollera att enheterna är desamma vid jämförelsen. Några exempel: Receptets ingredienser 3 dl vetemjöl 2 dl mjölk 1 st ägg 2 dl socker Lista1 (kylskåpet) 10 dl vetemjöl 10 dl mjölk Lista2 (kylskåpet) 3 st ägg 1 dl socker 10 dl vetemjöl 20 dl mjölk Lista3 (kylskåpet) 2 dl mjölk 100 g margarin 2 dl socker 3 dl vetemjöl 2 dl kaffe Ok! (alla ingredienser räcker) Ej ok! (minst en komp. räcker inte) Ok! (alla räcker) 11(11)
Uppgift 7 (10 poäng) Människan har i alla tider fascinerats av krypton och chiffer 1. I början användes enkla s.k. substitutionskrypton. Dessa går principiellt ut på att man alltid byter ett visst tecken mot ett annat givet tecken, vilket bestäms av den s.k. nyckeln. Så här går krypteringen till: abcdefghijklmnopqrstuvwxyzåäö //klartextalfabet öäåzyxwvutsrqponmlkjihgfedcba //nyckel Meddelande t e n t a Kryptotext1 j y p j ö Vid dekryptering så kör man denna process åt andra hållet för att komma tillbaka till originalmeddelandet. För varje tecken i den krypterade strängen tar man tecknet i samma position i nyckeln och får tillbaka klartexten. Så här: Kryptotext1 j y p j ö Meddelande t e n t a Detta kallas ett monoalfabetiskt substitutionskrypto. Dessa visade sig vara enkla att avkoda eftersom man vet att vissa bokstäver är mer frekventa i språket än andra (dessutom är vissa bokstavskombinationer mer frekventa). Därför kunde man genom att göra en frekvensanalys av den krypterade texten ta fram nyckeln till substitutionerna. Alldeles enkelt är det inte att få det rätt, men man kan alltid göra ett första försök. Konstruera åtminstone följande: en metod som krypterar enligt substitutionsprincipen en metod som dekrypterar enligt substitutionsprincipen. en metod som räknar frekvenser av tecken i den krypterade texten en metod som dechiffrerar den krypterade texten. Dechiffreringen görs genom att jämföra frekvenserna med fördelningen av tecken i svenska språket (se frekvenstabellen nedan). Det mest frekventa tecknet i den krypterade texten byts mot det vanligast förekommande tecknet i svenska språket (vilket är bokstaven e) osv. Någon form av sortering behövs alltså, men det spelar ingen roll vilken sorteringsmetod (algoritm) du väljer. Med all säkerhet kommer detta inte att ge tillbaka den ursprungliga texten, eftersom det krävs en lång text för att frekvensanalysen skall fungera bra. Du behöver inte kontrollera att den krypterade texten bara innehåller tecknen a,.., ö. Att formatera strängen på lämpligt sätt överlåter vi för tillfället till någon annan, så att det är gjort före anropet av dechiffreringsmetoden. 1 Texten i denna uppgift är baserad på beskrivningen i Simon Singhs bok Kodboken, MånPocket 2001, ISBN 91-7643-697-7. Rekommenderas! 12(12)
Du får själv välja hur koden ska organiseras, statiska metoder är helt ok, vill du starta i main så går det också bra. Självklart kan inte allt ligga i en metod i en klass, så god metodik krävs oavsett hur du väljer. Din lösning skall gå att provköra med följande kod (finns i provmappen): String alfabet = "abcdefghijklmnopqrstuvwxyzåäö"; String nyckel = "öäåzyxwvutsrqponmlkjihgfedcba";//exempelvis String kryptotext = encrypt(klartext, nyckel); System.out.println("Krypterad\t" + kryptotext); String dekrypterad = decrypt(kryptotext, nyckel); System.out.println("Dekrypterad\t" + dekrypterad); String dechiffrerad = dechipher(kryptotext); System.out.println("Dechiffrerad\t" + dechiffrerad); Frekvenstabell för svenska språket (finns inskriven i tillsammans med ovanstående så att du slipper skriva av den): a b c d e f g h i j k l m n o 9.3 1.3 1.3 4.5 9.9 2.0 3.3 2.1 5.5 0.7 3.2 5.2 3.5 8.8 4.1 p q r s t u v w x y z å ä ö 0.7 0.007 8.3 6.3 8.7 1.8 2.4 0.03 0.1 0.6 0.02 1.6 2.1 1.5 Uppgiften fortsätter på nästa sida! 13(13)
Alfabet abcdefghijklmnopqrstuvwxyzåäö Nyckel öäåzyxwvutsrqponmlkjihgfedcba Klartext Krypterad Dekrypterad dettaärenjättelångtextsominteharnågrablanktecken zyjjöblyptbjjyrcpwjyfjkoqupjyvölpcwlöäröpsjyåsyp dettaärenjättelångtextsominteharnågrablanktecken Strängens längd = 48 Efter frekvenssortering görs följande byten: Nyckelns tecken i motsvarande position (ö) a byts mot q (z) d byts mot z (y) e byts mot w (w) g byts mot x (v) h byts mot y (u) i byts mot j (q) m byts mot p (p) n byts mot b (f) x byts mot c (x) f byts mot ö (s) k byts mot å (o) o byts mot u (m) q byts mot f (j) t byts mot h (i) u byts mot ä (h) v byts mot v (d) z byts mot k (c) å byts mot g (b) ä byts mot m (ä) b byts mot o (å) c byts mot d (l) r byts mot l (k) s byts mot i (g) w byts mot s (r) l byts mot r (a) ö byts mot t (n) p byts mot n (e) y byts mot a (t) j byts mot e Minst frekvent Mest frekvent Krypterad zyjjöblyptbjjyrcpwjyfjkoqupjyvölpcwlöäröpsjyåsyp Dechiffrerad kaeetoranhoeealdnseaöeåufäneavtrndsrtmltnieagian Klartext dettaärenjättelångtextsominteharnågrablanktecken Den här texten är för kort för att ge bra utslag i frekvenserna, t.ex. förekom w, x, y och z inte alls. Men man kan ana ett mönster: de fyra vanligaste bokstäverna i språket är också de fyra mest frekventa i den krypterade texten, även om de inte riktigt kommer i rätt ordning. Ökar man på textens längd blir detta ännu tydligare, men riktigt rätt blir det tyvärr inte med denna enkla dechiffrering. 14(14)