Lösningsförslag till tentamen i EDA011, lördagen den 16 december 2006



Relevanta dokument
Tentamen i EDA011 Programmeringsteknik för F, E, I, π och N

Tentamen, EDAA20/EDA501 Programmering

Lösningsförslag till tentamen i EDA011 Programmeringsteknik för F, E, I, π och N

Tentamen, EDAA20/EDA501 Programmering

Lösningsförslag till tentamen i EDA011/EDA017 Programmeringsteknik för F, E, I, π och N 25 maj 2009

Grundläggande programmering med C# 7,5 högskolepoäng

Föreläsning 3-4 Innehåll

Föreläsning 8 SLUMPTAL, SIMULERING + INTRODUKTION TILL VEKTORER

Att deklarera och att använda variabler. Föreläsning 10. Synlighetsregler (2) Synlighetsregler (1)

Tentamen, EDAA20/EDA501 Programmering

Tentamen, EDA501/EDAA20 Programmering M MD W BK L

Tentamen, EDA501 Programmering M L TM W K V

Föreläsning 3-4 Innehåll. Diskutera. Metod. Programexempel med metod

Dagens text. Programmeringsteknik. Mer om Scanner-klassen. Dialogrutor (klassen JOptionPane) Bubbelsortering. Omslagsklasser.

Tentamen, EDAA10 Programmering i Java

Tentamen, EDA501 Programmering M L TM W K V

Tentamen DE12, IMIT12, SYST12, ITEK11 (även öppen för övriga)

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Lösningsförslag till tentamen

TENTAMEN OOP

Fält av referenser. Konstruktorerna används för att skapa Bilar och Trafikljus.

Föreläsning REPETITION & EXTENTA

ITK:P1 Föreläsning 1. Programmering. Programmeringsspråket Java. Stark typning Explicit typning Strukturerat Hög säkerhet

Del A (obligatorisk för alla)

Laboration A Objektsamlingar

Sammanfattning och repetition utgående från typiska tentamensuppgifter

Föreläsning 9-10 Innehåll

EDAA20 Föreläsning Klassen ArrayList. Viktiga operationer på ArrayList. Generisk klass

Tentamen OOP

Malmö högskola 2008/2009 CTS

Sortering. Om du följt dessa steg korrekt så ska böckerna nu vara sorterade.

TENTAMEN PROGRAMMERINGSMETODIK MOMENT 2 - JAVA, 4P

TENTAMEN OOP

Tentamen, EDAA20/EDA501 Programmering

Malmö högskola 2007/2008 Teknik och samhälle

Saker du ska kunna Föreläsning 13 & 14

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Muddy. Funktioner / metoder. Punktnotation. Evalueringsordning

Lösningsförslag till tentamen i EDA011/EDA017 Programmeringsteknik för F, E, I, π och N 27 maj 2008

Tentamen i Grundläggande programmering STS, åk 1 lördag

DAT043 Objektorienterad Programmering

Tentamen Datastrukturer (DAT037)

Tentamen i Programmering

TENTAMEN PROGRAMMERING I JAVA, 5P SOMMARUNIVERSITETET

Tentamen på kursen DA7351, Programmering , kl Malmö högskola Teknik och samhälle. DA7351, Programmering

Dagens text. Programmeringsteknik. Mer om Scanner-klassen. Dialogrutor (klassen JOptionPane) Bubbelsortering. Omslagsklasser.

Programmering för språkteknologer II, HT2011. Rum

Det finns en referensbok (Java) hos vakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Tentamen, EDAA10 Programmering i Java

Programmering för språkteknologer II, HT2014. Rum

Del A (obligatorisk för alla)

Typkonvertering. Java versus C

Tentamen. Lösningsförslag

Lösningsförslag till tentamen för TDA540 Objektorienterad Programmering

F5 Selektion och iteration. ID1004 Objektorienterad programmering Fredrik Kilander

Lösningsförslag tentamen FYTA11 Java

Föreläsning Innehåll. Hantera många element. Exempel: polygon Godtyckligt antal element. Exempel: polygon forts

Vem är vem på kursen. Objektorienterad programvaruutveckling GU (DIT011) Kursbok Cay Horstmann: Big Java 3rd edition.

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Lösningsförslag till tentamen

Objekt-orientering. Java är ett objekt-orienterat programmeringsspråk

Det finns en referensbok (Java) hos vakten som du får gå fram och läsa men inte ta tillbaka till bänken.

TDDE10 TDDE11, 725G90/1. Objektorienterad programmering i Java, Föreläsning 2 Erik Nilsson, Institutionen för Datavetenskap, LiU

Sammanfattning och repetition utgående från typiska tentamensuppgifter

Generiska konstruktioner. Kursbokens kapitel 13

Lösningsförslag till tentamen Datastrukturer, DAT037,

Tentamen Datastrukturer, DAT037 (DAT036)

Föreläsning 10 OM DELMÅLSKONTROLLEN ; VARIABLERS SYNLIGHET STRING OCH STRINGBUILDER

Tentamen Programmeringsteknik II Skrivtid: Hjälpmedel: Java-bok (vilken som helst) Skriv läsligt! Använd inte rödpenna!

LÖSNINGSFÖRSLAG Programmeringsteknik För Ing. - Java, 5p

Föreläsning 5&6 LOGISKA VARIABLER; IMPLEMENTERA KLASSER; MER ALGORITMER

OOP Omtenta

public och private Obs: private inte skyddar mot access från andra objekt i samma klass.

PROGRAMMERING-Java Omtentamina

DIAGNOSTISKT PROV. Tid. Hjälpmedel. Antaganden. Rättning. Övrigt. Diagnostiskt Prov. Klockan Inga

Tentamen Programmeringsteknik för BME, C, D, E, F, I, N & Pi

Objektorienterad programmering. Fält som funktionsresultat. Mer om fält: att uppdatera ett parameterfält. Kontrast: Parametrar av primitiv typ

Objektorienterad programmering. Telefonboken igen, en bättre version. En jämförelse. Föreläsning 4

Det finns en referensbok (Java) hos tentavakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Tentamen, EDA017, Programmeringsteknik för C, E, I och Pi

Tentamen EDA501/EDAA20 M L TM W K V

OOP Tentamen

Grundkurs i programmering, 6 hp (725G61) Dugga 2 tillfälle 2

DI-institutionen Sid 1 av 6 Hans-Edy Mårtensson Sten Sundin

Det finns en referensbok (Java) hos tentavakten som du får gå fram och läsa men inte ta tillbaka till bänken.

TENTAMEN OOP

public boolean containskey(string key) { return search(key, head)!= null; }

4 13 / %.; 8 </" '': " / //&' " " ' * TelefonKostnad +,-%&. #!" $% " &' . > / ' 5 /' * 13/ &' static Math 1+" &'/ % 12 "" static "' * 1 /") %& &

Lösningsförslag till tentamen för TDA540 Objektorienterad Programmering

1 Uppgift 1. a) Skapar ett Company-objekt med hjälp av den överlagrade konstruktorn. Du kan själv välja värden på instansvariablerna.

Grundläggande programmering med C# 7,5 högskolepoäng. Provmoment: Ladokkod: Tentamen ges för: TEN1 NGC011 ADAEK17, ASYST17 samt öppen för alla

Föreläsning 3: Abstrakta datastrukturer, kö, stack, lista

Lösningsförslag till tentamen i EDA690 Algoritmer och Datastrukturer, Helsingborg

Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren om att du har förstått dessa även om detaljer kan vara felaktiga.

Datastrukturer. Föreläsning Innehåll. Program med vektor Exempel. Deklarera vektorer

LÖSNINGSFÖRSLAG TENTAMEN

13 Prioritetsköer, heapar

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Introduktion till Datalogi DD1339. Föreläsning 2 22 sept 2014

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Transkript:

Lösningsförslag till tentamen i EDA011, lördagen den 16 december 2006 Detta lösningsförslag är skrivet i stor hast, så det är möjligt att det innehåller en del slarvfel jag ber i så fall om ursäkt för det. Maila mig gärna om du hittar något som ser konstigt ut. Observera att man kan lösa många av uppgifterna på flera andra likvärdiga sätt att din lösning inte liknar min betyder därför inte nödvändigtvis att din är fel. Vi är även väl medvetna om att man ibland gör misstag när man sitter fem timmar och skriver med papper och penna detta är något som vi tar hänsyn till vid rättningen. Tentamen var utformad så att ni skulle få tillräckligt mycket kod att skriva, så att enstaka fel inte skulle bli så avgörande. Uppgift 1 Figuren får inte plats i detta dokument, jag kommer istället att lägga ut den på kurshemsidan (http://www.cs.lth.se/eda011). Som vanligt var meningen med figuren att ni skulle få en känsla för hur klasserna i uppgiften hänger ihop. Uppgift 2 Vi behöver följande attribut: Namn, id-nummer och telefonnummer: lagras som strängar. Aktuell skuld: lagras som heltal. Alla skivor vi hyr: kan lagras antingen i en vektor, eller i en lista. Om vi väljer att använda en vektor (som nedan), så behöver vi även en heltalsvariabel som håller reda på hur många skivor vi hyr. Vi får därför följande inledande rader i klassen: class Customer { private String name, idnbr, phonenbr; private int debt; private Disc[] renteddiscs = new Disc[10]; private int nbrofrenteddiscs = 0; public Customer(String name, String idnbr, String phonenbr) { this.name = name; this.idnbr = idnbr; this.phonenbr = phonenbr; public String getname() { return this.name; 1

public String getidnbr() { return this.idnbr; public String getphonenbr() { return this.phonenbr; //... Operationerna för att hantera hyrda skivor påminner mycket om några av operationerna i inlämningsuppgift 3: public void rent(disc disc) { this.renteddiscs[this.nbrofrenteddiscs++] = disc; public void returndisc(disc disc) { for (int i = 0; i < this.nbrofrenteddiscs; i++) { if (this.renteddiscs[i] == disc) { this.renteddiscs[i] = this.renteddiscs[--this.nbrofrenteddiscs]; return; public Disc[] getdiscs() { Disc[] discs = new Disc[this.nbrOfRentedDiscs]; for (int i = 0; i < this.nbrofrenteddiscs; i++) { discs[i] = this.renteddiscs[i]; return discs; public int nbrofrenteddiscs() { return this.nbrofrenteddiscs; Man kan tänka sig att låta Customer-klassen se till att de skivor den hyr och lämnar tillbaka uppdateras automatiskt det var egentligen meningen att klassen VideoStore skulle göra det, men vi drar inte av om ni sköter det härifrån istället. Operationerna rent och returndisc skulle i så fall bli något i stil med: public void rent(disc disc) { this.renteddiscs[this.nbrofrenteddiscs++] = disc; disc.rentedby(this, Date.now().plus(1)); public void returndisc(disc disc) { for (int i = 0; i < this.nbrofrenteddiscs; i++) { if (this.renteddiscs[i] == disc) { this.renteddiscs[i] = this.renteddiscs[--this.nbrofrenteddiscs]; 2

Date today = Date.now(); if (disc.getreturndate().before(today)) { this.adddebt(20*disc.getreturndate().daysuntil(today)); disc.returned(); return; De operationer som hanterar kundens skulder påminner en hel del om den Accountklass som vi såg när vi började implementera klasser det är helt OK att låta skulden bli negativ (vilket motsvarar att vi låter kunden göra en liten förbetalning av eventuellt kommande skulder): public void adddebt(int amount) { this.debt += amount; public void paydebt(int amount) { this.debt -= amount; public int getdebt() { return this.debt; Uppgift 3 Jag hade dragit ner på antalet operationer i klassen VideoStore för att det inte skulle bli för mycket för er att skriva (det står i uppgiften att klassen bland annat innehåller operationerna i specifikationen) en av de operationer jag hade strukit var addmovie, eftersom den skulle bli så lik addcustomer. I det avslutande stycket före uppgift 1 står: I klassen VideoStore skall vi hålla reda på samtliga filmer, skivor och kunder.... men det verkar vara ganska många som inte har lagt in någon vektor med filmer i klassen VideoStore (det är möjligt att det hade varit mer naturligt för er att lägga in en sådan vektor om ni hade fått skriva addmovie-operationen). Man kan lösa uppgiften även utan en sådan film-vektor, men några av operationerna blir svårare att skriva jag inser att det var lätt att missa formuleringen ovan, och vi kommer vid rättningen inte att göra något större väsen av om ni inte har någon film-vektor (detta gäller även uppgift 1). Klassen blir enklast att implementera om vi har attribut för alla filmer, alla skivor och alla kunder och liksom i uppgift 2 kan vi välja om vi vill använda listor eller vektorer. Om vi väljer vektorer (och då på köpet får tre heltalsattribut för att hålla reda på hur många element som används), så kan vi skriva: class VideoStore { private Movie[] movies; private int nbrofmovies; private Disc[] discs; 3

private int nbrofdiscs; private Customer[] customers; private int nbrofcustomers; //... Innan vi lägger till en kund måste vi undersöka om kunden redan finns eller inte enklast är att göra det genom att anropa findcustomer: public boolean addcustomer(string idnbr, String name, String phonenbr) { if (this.findcustomer(idnbr)!= null) { return false; this.customers[this.nbrofcustomers++] = new Customer(name, idnbr, phonenbr); return true; Operationen finddisc är precis som alla sök-operationer vi sett tidigare: public Disc finddisc(string eancode) { for (int i = 0; i < this.nbrofdiscs; i++) { if (this.discs[i].geteancode().equals(eancode)) { return this.discs[i]; return null; Här bör vi använda equals för att jämföra strängarna (eller compareto) det är ingen katastrof om du testat med hjälp av ==, det skulle visserligen inte fungera, men vi räknar det inte som något allvarligt fel. När vi skall lägga till en ny skiva måste vi först testa om filmen finns, och därefter se till att det inte tidigare fanns en skiva med samma artikelkod. Om vi klarar båda dessa villkor lägger vi en ny skiva sist i registret (och använder samtidigt den referens till filmen som vi fick när vi undersökte om den fanns): public int adddisc(string title, String eancode) { Movie movie = this.findmovie(title); if (movie == null) { return 1; if (this.finddisc(eancode)!= null) { return 2; this.discs[this.nbrofdiscs++] = new Disc(movie,eanCode); return 0; Även när vi skall hyra ut skivor måste vi testa ett antal saker: Först undersöker vi om det överhuvudtaget finns någon skiva med den aktuella artikelkoden, finns det ingen sådan så returnerar vi 1. Om vi hittar skivan, men den är uthyrd (isrented()), så returnerar vi 2. 4

Därefter testar vi om kunden finns med hjälp av findcustomer-operationen, om vi får null tillbaka så returnerar vi 3. Slutligen testar vi om den aktuella kunden har någon skuld (getdebt()). När alla tester är klara kan vi notera i både skivan och kunden att vi hyr ut skivan, och returnera 0: public int rentdisc(string eancode, String idnbr) { Disc disc = this.finddisc(eancode); if (disc == null) { return 1; if (disc.isrented()) { return 2; Customer customer = this.findcustomer(idnbr); if (customer == null) { return 3; if (customer.getdebt() > 0) { return 4; disc.rentedby(customer, Date.now().plus(1)); customer.rent(disc); return 0; Vid återlämningen måste vi återigen testa om skivan finns (enklast med hjälp av finddisc), och om den inte finns, eller inte är uthyrd, så avbryter vi genom att returnera false. När vi har hittat skivan så kan vi fråga den vilken kund det är som har hyrt. Återstår nu att kontrollera att skivan lämnas i tid, och att eventuellt uppdatera betyget på filmen (om grade är större än 0). Eftersom kunderna sätter betyg på filmer, inte på skivor, måste vi fråga skivan vilken film som finns på den, och anropa addgrade-operationen på filmen. public boolean returndisc(string eancode, int grade) { Disc disc = this.finddisc(eancode); if (disc == null!disc.isrented()) { return false; Customer customer = disc.getcustomer(); if (customer == null) { // borde inte kunna inträffa! return false; customer.returndisc(disc); Date today = Date.now(); if (disc.getreturndate().before(today)) { customer.adddebt(20*disc.getreturndate().daysuntil(today)); disc.returned(); if (grade > 0) { disc.getmovie().addgrade(grade); return true; 5

För att ta reda på antalet tillgängliga skivor med en given titel kan vi först hämta en referens till själva filmen (det är inte helt nödvändigt, se nedan). Om filmen inte finns kan vi direkt avbryta och skicka tillbaka 0, annars kan vi gå igenom hela vektorn med skivor, och för varie skiva som innehåller filmen kollar vi om den är uthyrd eller inte: public int nbrofavailablediscs(string movietitle) { Movie movie = this.findmovie(movietitle); if (movie == null) { return 0; int count = 0; for (int i = 0; i < this.nbrofdiscs; i++) { Disc disc = this.discs[i]; if (disc.getmovie() == movie &&!disc.isrented()) { count++; return count; Här är jämförelsen == korrekt, eftersom vi bara har ett objekt per film. Vi kan även göra detta på andra sätt, exempelvis: public int nbrofavailablediscs(string movietitle) { int count = 0; for (int i = 0; i < this.nbrofdiscs; i++) { Disc disc = this.discs[i]; if (disc.getmovie().gettitle().equals(movietitle) &&!disc.isrented()) { count++; return count; Operationen nbrofavailablediscs är användbar när vi skall skriva ut samtliga filmer: public void printmovies() { for (int i = 0; i < this.nbrofmovies; i++) { Movie movie = this.movies[i]; System.out.printf("%2d %s (%.1f)\n", this.nbrofavailablediscs(movie.gettitle()), movie.gettitle(), movie.getaveragegrade()); Denna lösning är lite ineffektiv (när vi anropar nbrofavailablediscs så gör den en sökning efter filmen, som vi ju redan har en referens till när vi anropar operationen) vi hade enkelt kunnat komma runt denna ineffektivitet genom att exempelvis införa en operation nbrofavailablediscs(movie movie), som vi skulle kunna anropa ifrån den andra nbrofavailablediscs-operationen ovan, men det behöver vi absolut inte göra här! 6

När jag pratade med några av er efter tentan verkade det som att operationen, makecalllist hade varit besvärlig, och det besvärligaste var nog att skriva ut namn och telefonnummer bara före den första av de filmer som är försenade för varje kund (det vore lättare om vi kunde skriva ut namn och telefonnummer före varje film som var försenad, eller skriva ut namn och telefonnummer till varje kund vi stöter på). Vi kan lösa det med hjälp av en logisk variabel, och kan antingen skriva allt som en operation: public void makecalllist() { Date today = Date.now(); for (int i = 0; i < this.nbrofcustomers; i++) { Customer c = this.customers[i]; boolean alreadyfoundlatedisc = false; Disc[] discs = c.getdiscs(); for (int k = 0; k < discs.length; k++) { Disc d = discs[k]; if (d.getreturndate().before(today)) { if (!alreadyfoundlatedisc) { System.out.println(c.getPhoneNbr() + ": " + c.getname()); alreadyfoundlatedisc = true; System.out.println(" " + d.getmovie().gettitle()); eller, att bryta upp den i två operationer: public void makecalllist() { for (int i = 0; i < this.nbrofcustomers; i++) { this.checkforlatediscs(this.customers[i]); private void checkforlatediscs(customer c) { Date today = Date.now(); boolean alreadyfoundlatedisc = false; Disc[] discs = c.getdiscs(); for (int k = 0; k < discs.length; k++) { Disc d = this.discs[k]; if (d.getreturndate().before(today)) { if (!alreadyfoundlatedisc) { System.out.println(c.getPhoneNbr() + ": " + c.getname()); alreadyfoundlatedisc = true; System.out.println(" " + d.getmovie().gettitle()); 7

Det kan verka praktiskt att testa om kunden har en skuld, för att se om hon har skivor hemma men det fungerar inte riktigt. Dels får kunderna inte någon skuld förrän de lämnar tillbaka filmerna, och dessutom står skulden kvar tills den betalts (dvs den kan stå kvar även efter att filmerna lämnats tillbaks). Inte heller detta räknas som något allvarligt fel. Uppgift 4 Vi kan skriva en klass Mastermind som löser uppgiften följande attribut är användbara: nbrofdigits, som är antalet siffror i våra rader, maxvalue, som är övre gränsen för de siffror som får ingå, hidden och guess, som är heltalsvektorer som innehåller den gömda raden, och den senaste gissningen, och hiddendist, som innehåller fördelningen av olika siffror i den gömda raden (eftersom denna aldrig ändras är det lika bra att beräkna den en gång för alla). Vi får därför inledningsvis: class Mastermind { public static void main(string[] args) { int nbrofdigits = Keyboard.nextInt("Antal siffror: "); int maxvalue = Keyboard.nextInt("Största möjliga värde: "); Mastermind m = new Mastermind(nbrOfDigits, maxvalue); m.run(); private int nbrofdigits, maxvalue; private int[] hidden, guess; private int[] hiddendist; // antalet av olika värden i gömda raden public Mastermind (int nbrofdigits, int maxvalue) { this.nbrofdigits = nbrofdigits; this.maxvalue = maxvalue; //... Huvudoperationen, run(), skall skapa en gömd rad, och därefter låta användaren gissa nya rader tills hon lyckas gissa rätt rad: public void run() { this.setup(); int count = 0; for (;;) { count++; this.inputguess(); if (this.checkguess()) { break; 8

System.out.printf("Grattis, du klarade det på %d gissningar.\n", count); Vi hade även kunnat använda en do-while-loop ovan: public void run() { this.setup(); int count = 0; do { count++; this.inputguess(); while (!this.checkguess()); System.out.printf("Grattis, du klarade det på %d gissningar.\n", count); Operationen setup() skapar vektorer för våra båda rader (hidden och guess), lagrar en slumpmässig rad i hidden, och beräknar därefter fördelningen av olika värden i hidden (detta värde lagras i hiddendist): private void setup() { this.guess = new int[this.nbrofdigits]; this.hidden = new int[this.nbrofdigits]; Random rng = new Random(); for (int i = 0; i < this.nbrofdigits; i++) { this.hidden[i] = rng.nextint(this.maxvalue) + 1; this.hiddendist = this.countdistribution(this.hidden); För att bestämma fördelningen av olika värden (från 1 upp till maxvalue) kan vi använda det som vi kallade registrering: private int[] countdistribution(int[] row) { int[] dist = new int[this.maxvalue+1]; for (int i = 0; i < this.nbrofdigits; i++) { dist[row[i]]++; return dist; Vi kommer att få nytta av denna operation även när vi skall poängsätta den gissade raden. Inläsning av en ny rad är enkelt: private void inputguess() { System.out.print("Gissa rad: "); for (int i = 0; i < this.nbrofdigits; i++) { this.guess[i] = Keyboard.nextInt(); Det enda som återstår nu är funktionen som skall testa den gissade raden vi gör den till en boolean-operation för att enkelt kunna avbryta loopen i run()-operationen, och ber den samtidigt att skriva ut antalet helt korrekta siffror, och antalet korrekta men felplacerade siffror med hjälp av den algoritm som beskrevs i uppgiften: 9

private boolean checkguess() { int[] guessdist = this.countdistribution(this.guess); int color = 0; for (int i = 1; i <= this.maxvalue; i++) { color += Math.min(this.hiddenDist[i], guessdist[i]); int place = 0; for (int i = 0; i < this.nbrofdigits; i++) { if (this.hidden[i] == this.guess[i]) { place++; color--; System.out.printf(" %d %d\n", place, color); return place == this.nbrofdigits; 10