P RAKTISKT PROV I D ATAVETENSKAP
O BJEKTORIENTERAD PROGRAMMERING I J AVA
FÖR I NGENJÖRER , 5 P
Datum : 030602
Tid : 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
Totalpoäng : 32 (halva poängtalet TP + PP 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.
• Kryssa för de uppgifter du lämnar in.
• Källkod skrivs ut i ett ickeproportionellt typsnitt (t.ex. courier).
• Namn, personnummer, användarnamn 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 pp030602 på kursens hemsida. Där finns också eventuella andra filer som du kan behöva.
OBS! Kontrollera att din dator fungerar innan du börjar på allvar. Börja sedan med att läsa instruktionerna på nästa sida.
Lycka till!
Innan du börjar skall följande vara gjort:
• Logga in på Unix-systemet med hjälp av putty
• Gå till din katalog ~/edu/java: cd /edu/java
• Skapa en ny katalog: mkdir pp021101
• Skydda katalogen: chmod –R 700 pp030602 (obs stort R !)
Efter provet, tidigast klockan 13.00:
• Logga in på Unix-systemet med hjälp av putty
• Gå till din katalog /edu/java: cd /edu/java
• Ändra filskyddet: chmod –R 755 pp030602
Observera att ditt prov inte kan rättas om vi inte får tillgång till dina filer!
Regler för det praktiska provet
Detta ä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
Skärmdump - Screen shot
Se mappen pp030602 för detaljer.
Några viktiga UNIX kommandon:
>pwd
(PrintWorkingDirectory) Visar i vilken katalog du befinner dig. Kommandona nedan avser i huvudsak working directory, dvs. den aktuella mappen.
>ls -al
Listar alla filer i working directory tillsammans med olika uppgifter (t.ex. aktuella
rättigheter). Om man bara skriver –l istället för -al visas inte system-filerna (sådana vars namn börjar med en punkt).
>cd katalog
Flyttar ner i den angivna katalogen. Man kan flytta flera nivåer på en gång genom att ange vägen katalog/ katalog/ katalog. Om du inte vet ”var du är”, kan du använda pwd (se ovan) för att vara säker.
>chmod [-R] mode katalog/fil
Ändrar rättigheter på katalog/fil till de rättigheterna som anges i "mode".
Rättigheterna visas (via ls -l) som tre grupper med rwx där r står för läsrättighet, w för skrivrättighet och x för rättigheten att exekvera filen. Första gruppen rwx anger
rättigheterna för ägaren av filen. Andra gruppen rwx anger vilka rättigheter för andra personer i samma grupp som ägaren (i vårt fall är det studenterna på datavetenskap).
Tredje gruppen anger rättigheterna för övriga (här finns institutionens personal).
Viktiga "mode" är t.ex.
700 då ändras rättigheterna till rwx---, dvs bara ägaren får läsa, skriva och exekvera. Ingen annan får läsa, skriva eller exekvera (inte ens lärarna).
755 då ändras rättigheterna till rwxr-xr-x, dvs bara ägaren får läsa, skriva och exekvera. Gruppen (studenterna på kursen) och övriga världen får läsa och exekvera.
Om man anger -R (kan alltså utelämnas) ändras rättigheterna rekursivt i alla filer och kataloger som ligger under den katalogen som anges.
>mkdir katalognamn
Skapar en ny mapp i working directory, dvs. den aktuella mappen.
Uppgift 1 (6 poäng)
Utgå från klassen Bil nedan och lägg till en konstruktor som bara tar tjänstevikten som parameter. Härled sedan en klass Taxi som utöver att vara en Bil även håller reda på det maximala passagerarantalet som taxin får transportera.
public class Bil {
private double tjansteVikt; //private tillagt efteråt, men borde varit med!!
private int maxHastighet; // -”-
public Bil(int maxHastighet, double tjansteVikt) {
this.maxHastighet = maxHastighet;
this.tjansteVikt = tjansteVikt;
}//konstruktor
public double getVikt() {
return tjansteVikt;
}//getVikt
public int getToppfart() {
return maxHastighet;
}//getToppfart
// Ytterligare metoder (oviktiga just denna gång) }//Bil
Uppgift 2 (6+2=8 poäng)
I den här uppgiften skall du konstruera en klass som modellerar ett rationellt tal.
Rationella tal är tal som kan skrivas på formen
†
p q där
†
p och
†
q är heltal.
a) Klassen skall ha metoder för att ändra värdet på täljaren (
†
p), ändra värdet på nämnaren (
†
q), skriva ut talet, samt en metod för att omvandla talet till ett värde av typen double.
b) Skriv en metod som kan addera talet självt med ett annan rationellt tal och
returnera resultatet som ett rationellt tal. Du behöver inte förenkla resultatet, dvs.
om du har beräkningen
†
1 2+ 1
4 så är det ok att svaret blir
†
6 8. Tänk objektorienterat!
I den följande delen får du lämna in högst två av uppgifterna
Uppgift 3 (9 poäng)
Nedan följer en generell sorteringsalgoritm. Den grundläggande idéen är att sätta in en post R i en sekvens av ordnade poster, R1, …, Ri, (ordningen ges av nyckeln K dvs. K1≤ K2,
… ≤ Ki ) på ett sånt sätt att den resulterande följden med i+1 poster också är ordnad.
Algoritm INSERT (R, i)
//Sätt in en post R med nyckel K i sekvensen av ordnade poster R1, …, Ri, på ett sådant sätt att den resulterande sekvensen också är ordnad efter nyckeln K.//
j ¨ i
while K < Kj do
//Flytta Rj ett steg åt höger, så att R kan sättas in före (till vänster om) Rj Rj+1¨ Rj
j ¨ j-1 end
Rj+1¨ R end INSERT
Sorteringen går till så att man utgår från en ordnad sekvens av poster som bara består av R1, sedan sätter man successivt in posterna, R2, … , Rn i sekvensen. Detta sköts av
algoritmen INSORT.
Algoritm INSORT (R, n)
//Sortera posterna R1, …, Rn i stigande ordning med avseende på nyckeln K.
Antag n > 1//
for j ¨ 2 to n do
call INSERT(Rj,j-1) //sätt in posterna R2, … , Rn end
end INSORT
Utgå från klassen Bil i uppgift 1
public class Bil {
…
// Nu lägger vi till följande metod public String toString()
{
return "vikten " + tjansteVikt;
}//toString }//Bil
Du har ett antal bilar i ett fält/array och vill kunna sortera dessa med avseende på tjänstevikten.
Implementera sorteringsalgoritmen INSORT ovan som en statisk metod i en klass
tjänstevikten. Självklart kan det behövas en viss anpassning av algoritmen när den implementeras i Java, index kan ju behöva justeras t.ex.
Följande klass AlgoritmTest skall fungera med din sorteringsrutin. Metoden skrivut skriver på System.out vilket visas i ett terminalfönster som automatiskt dyker upp när du kör metoden testa. Ta med en skärmdump av det fönstret i din lösning tillsammans med koden för Algoritmer. Observera att du själv måste skriva metoden skrivut.
public class AlgoritmTest {
public static void testa() {
Bil[] bil = new Bil[7];
// Skapa tio bilar med slumpmässiga tjänstevikter for (int i = 0; i < bil.length; i++)
{
int v = (int)(Math.random() * 500) + 1000;
bil[i] = new Bil(150,v);
}
// Skriv ut det osorterade fältet skrivUt("Före sorteringen",bil);
// Sortera
Algoritmer.inSort(bil);
// Skriv ut det sorterade fältet skrivUt("Efter sorteringen",bil);
}//testa
// Här skall den privata metoden skrivUt ligga }//AlgoritmTest
Före sorteringen
Bil på plats nr 0 har vikten 1230.0 Bil på plats nr 1 har vikten 1275.0 Bil på plats nr 2 har vikten 1229.0 Bil på plats nr 3 har vikten 1195.0 Bil på plats nr 4 har vikten 1197.0 Bil på plats nr 5 har vikten 1287.0 Bil på plats nr 6 har vikten 1395.0 Efter sorteringen
Bil på plats nr 0 har vikten 1195.0 Bil på plats nr 1 har vikten 1197.0 Bil på plats nr 2 har vikten 1229.0 Bil på plats nr 3 har vikten 1230.0 Bil på plats nr 4 har vikten 1275.0 Bil på plats nr 5 har vikten 1287.0 Bil på plats nr 6 har vikten 1395.0
Uppgift 4 (9 poäng)
Människan har i alla tider fascinerats av krypton och chiffer. En tidig krypteringsteknik kallas Ceasar-kryptering. Principen är att man byter till ett tecken som ligger på ett visst avstånd från originaltecknet. Om man byter varje bokstav mot den bokstav som ligger tre tecken senare i alfabetet, så har man gjort en Ceasar-kryptering. ABBA blir t.ex. DEED.
En variant på Ceasar-kryptering kallas Vignere-kryptering. Denna kryptering fungerar så att nyckeln appliceras cykliskt mot originalmeddelandet. En fördel med detta är att det inte finns något enkelt samband mellan en enskild bokstav och det tecken den ersätts med vid krypteringen. Det går till så att nyckeltecknens kodvärde adderas till motsvarande teckens värde i originalmeddelandet och ger via summan ett krypterat tecken. Så istället för att alltid ta tecknet som ligger på ett fast avstånd, använder man nyckelns tecken för att bestämma avståndet. Nyckelns tecken tilldelas kodvärden på följande sätt : A har värdet 0, B har värdet 1, C har värdet 2,… och Z har värdet 25. Originalmeddelandets tecken får sitt ordningsnummer i teckenuppsättningen som värde, i det här fallet UNICODE.
Ett exempel : Nyckeln består här av strängen NYCKEL
Nyckel N Y C K E L
Kodvärde 13 24 2 10 4 11
Original J a g g i l l a r J a v a
värde 74 97 103 32 103 105 108 108 97 114 32 74 97 118 97
Nyckel N Y C K E L N Y C K E L N Y C
värde 13 24 2 10 4 11 13 24 2 10 4 11 13 24 2
Summa 87 121 105 42 107 116 121 132’38 99 124 36 85 110 142’48 99
Krypterat W y i * k t y & c | $ U n 0 c
Vid dekryptering så kör man processen åt andra hållet för att komma tillbaka till originalmeddelandet. Så här:
Krypterat W y i * k t y & c | $ U n 0 c
värde 87 121 105 42 107 116 121 38 99 124 36 85 110 48 99
Nyckel N Y C K E L N Y C K E L N Y C
värde 13 24 2 10 4 11 13 24 2 10 4 11 13 24 2
Differens 74 97 103 32 103 105 108 14’
108 97 114 32 74 97 24’ 118 97
Klartext J a g g i l l a r J a v a
Ursprungssträng : ->Jag gillar Java<- Krypterad : ->Wyi*kty&c|$Un0c<-
Tillbaka igen : ->Jag gillar Java<-
När man använder datorer innehåller ”alfabetet” många fler tecken än naturliga alfabet.
Om man vill hålla sig till de ”tryckbara tecknen” så måste ordningsvärdet ligga i intervallet 32…126 för UNICODE.
I exemplet ovan ser man:
Original v
värde 118
Nyckel Y
värde 24
Summa 142
’48 tecknet ’v’ i originalmeddelandet har ordningsnummer 118 och
det skall adderas med kodvärde 24 för tecknet ’Y’ i nyckeln. Då får man summan 142 som skall tolkas som ordningsnummret för ett tecken. När detta värde > 126, börjar man om från 32 igen, så att 127’33, 128’34 osv. Då blir 142’48 och tolkas som tecknet ’0’.
Det blir alltså en cirkel där slutet knyts ihop med början.
Krypterat 0 Lösningen skall innehålla en komplett implementation av klassen Vignere med två statiska metoder String encrypt resp. String decrypt som båda tar två argument av typen String, dels den sträng som skall konverteras, dels nyckeln. Du får utgå från att nyckeln består av enbart stora bokstäver (A,.. Z) i din lösning. Du behöver inte hantera å, ä och ö som är besvärliga eftersom de inte följer alfabetet naturligt i UNICODE, se
exemplet i nedanstående testkörning.
Din lösning skall gå ett provköra med följande kod :
public class TestaKrypton {
public static void main(String[] args) {
String urString = "Jag gillar Java";
String nyckel = "NYCKEL";
System.out.println("Ursprungssträng : ->" + urString + "<-");
String kodString = Vignere.encrypt(urString, nyckel);
System.out.println("Krypterad : ->" + kodString + "<-");
String kontrollString = Vignere.decrypt(kodString, nyckel);
System.out.println("Tillbaka igen : ->" + kontrollString + "<-\n");
urString = "Är detta svårt?";
nyckel = "TENTAMEN";
System.out.println("Ursprungssträng : ->" + urString + "<-");
kodString = Vignere.encrypt(urString, nyckel);
System.out.println("Krypterad : ->" + kodString + "<-");
kontrollString = Vignere.decrypt(kodString, nyckel);
System.out.println("Tillbaka igen : ->" + kontrollString + "<-\n");
}//main }//TestaKrypton
Tips!
För att gå från siffervärde till tecken kan man göra så här:
char c = ’A’;
int v = (int) c; //Nu har v värdet 65
För att gå från tecken till siffervärde gör du så här:
int v = 118;
char c = (char) v; //Nu har c värdet ’v’
På kursens hemsida finns koden ovan och en länk till en tabell där du kan se hur tecknen är ordnade och vilket ordningsnummer de har.
Uppgift 5 (9 poäng)
Dagligvarukedjan
GoMat
har kontaktat dig för att få anbud på ett system som kan sköta administrationen av butikerna. Butikerna har leverantörer, personal och varor som ska administreras. Dessutom vill kedjan självfallet kunna kontakta sina butikschefer i olika ärenden, t.ex. få information om försäljningen under en viss period. Som egenföretagare i konsultbranschen måste du nu snabbt komma med ett utkast till detta system, annars går det mycket lukrativa uppdraget till någon annan. Naturligtvis kommer du att tjänamassor på att sälja systemet även till andra butikskedjor om det går riktigt bra.
Du ska alltså föreslå en design (inte implementera) till detta system.
OBS! Du ska inte utreda något som har med användargränssnittet att göra (GUI designen).
Lämna in en UML-liknande beskrivning av designen som innehåller alla klasser och som visar hur de hänger ihop. För varje klass ska viktiga attribut och metoder finnas med.
Detta får du gärna lämna in handskrivet.
Uppgift 6 ( 9 poäng)
I exemplet med administration av resultat i en friidrottstävling (se pp030602) finns en klass Gren som administrerar en enskild tävlingsgren. Den har en metod reultatLista som returnerar ett fält av Deltagare, där referenserna har satts så att resultaten antingen nås i stigande eller avtagande ordning. Detta är dock en lite klumpig lösning, det vore mer konsekvent att returnera en ResultatLista. Implementera en klass ResultatLista som härleds från klassen Lista. Ändra sedan i koden så att Deltagare[] inte behöver användas när man vill ha en lista med resultat från en gren.
Observera att det inte är exakt samma kod som i föreläsningsexemplet, Gren hette t.ex.
GrenResultat tidigare.