LUNDS TEKNISKA HÖGSKOLA Institutionen för datavetenskap Lösning till tentamen EDAA45 Programmering, grundkurs 2017-04-20, 14:00-19:00 Generella bedömningsriktlinjer Del A: Varje rad kan ge max 2p. Del B: Typerna och värdena ska skrivas som det står i lösningstabellen för full poäng. Dock får svaret skilja sig vad gäller i betydelselös användning av blanktecken och radbrytningar. Citationstecken runt strängar är ok men behövs inte. Om värdet är rätt, så när som på mindre detaljer i tostringrepresentationen, till exempel 42.0 i stället för 42, ges inget avdrag. Om rätt svar är ett kryss i kolumn 3 eller 4, men man kryssat för kompileringsfel när det ska vara exekveringsfel, eller tvärt om, eller om man kryssat i båda, ges 1 i avdrag. Om man svarat med fel typ men rätt värde ges 1 i avdrag. Ofullständig generisk typ, t.ex. Option istf. Option[String] ger 1 i avdrag. Om man svarat med rätt typ men fel värde ges 1 i avdrag. Om både värde och typ är fel ges 2 i avdrag. Om man svarat med typ/värde och kryss i kolumn 3 och/eller 4 på samma rad ges 2 i avdrag. Totala poängen för en uppgift kan inte bli negativ; om alla avdrag för en uppgift blir mer än maxpoängen ges 0 poäng. Om samma typ av fel förekommer i samma uppgift mer än en gång görs bara avdrag en gång vid första förekomsten. Enkla misstag som är lätta att åtgärda ger 1 i avdrag eller 2 i avdrag, beroende på hur allvarligt felet är. Allvarliga misstag eller stora ofullständigheter ger upp till maxpoäng i avdrag, beroende på hur mycket av koden som måste skrivas om för att det ska fungera och vara begripligt. 1
2(7) Poängmarkering Alla markeringar sker med penna i avvikande färg, helst röd. Skriv en kommentar bredvid poängmarkering som förklarar poängen om det inte är uppenbart varför poängen dras/ges. +. Välj för en viss uppgift (t.ex. B1) en av dessa sätt att markera poäng: Minuspoäng. Detta är det vanligaste sättet att markera och det lättaste om lösningen är någorlunda komplett och rimlig. Poängen markeras genom att ange avdrag med t.ex. -1 Om ett avdrag görs en gång för samma fel som förekommer på andra ställen i uppgiften ange en punkt efter poängen, t.ex. -1. På det ställe där samma fel återkommer ange ett långt minustecken utan poäng efter. + Pluspoäng. Om lösningen saknar stora delar och/eller är långt ifrån att fungera är det lättast att ange pluspoäng t.ex. +3 som motsvarar helhetsbedömning av vad denna deluppgift är värd. Om det finns brister eller problem som inte renderar avdrag, men som bör påpekas i upplysande syfte, ange ett långt minustecken utan poäng efter och skriv en kommentar om vad det gäller. Obetydliga brister som inte ger avdrag markeras också med ett långt minustecken utan poäng efter. Om många obetydliga brister förekommer kan dessa adderas till ett engångsavdrag om det är lämpligt när helhetsbedömning görs och uppgiftens poängsumma räknas samman. Den totala poängen för varje uppgift (t.ex. B1) anges inringat som positiva poäng utan varken pluseller minustecken framför, t.ex. 8 Uppgiftens totala poängsumma skrivs även på omslagets framsida under respektive uppgift. Stryk gärna under de delar i koden som är speciellt intressanta för poängmarkeringen. Om du skriver fel, stryk över din markering och skriv en ny. Generella avdrag och typiska fel Felaktigt matchade (klammer)parentespar, eller glömda (klammer)parenteser ger 1 i avdrag en gång per uppgift. Om nödvändigt semikolon saknas (t.ex. mellan flera satser på samma rad) ges 1 i avdrag. Mindre fel i likhet med föregående punkter där det framgår tydligt vad som egentligen avses ger 1 i avdrag. Obetydliga fel behöver ej ge avdrag om de är enstaka. Mindre fel vid användning av samlingsmetod, t.ex. +: i stället för :+ eller liknande, ger 1 i avdrag. Deklaration av var när det skulle kunna vara en val och fungera lika bra ger 1 i avdrag Deklaration av val när det måste vara var för att koden ska fungera ger 2 i avdrag. Onödig användning av this ger 1 i avdrag. = istf. == ger 1 i avdrag. Saknad else-gren så att värde saknas ger 2 i avdrag.
3(7) Lösning del A. Evaluera uttryck. 20 p Vid kompileringsfel sätt kryss. Vid exekveringsfel sätt kryss. Ange statisk typ som kompilatorn härleder om ej kompileringsfel eller exekveringsfel. Ange dynamiskt värde som tilldelas vid exekvering om ej kompileringsfel eller exekveringsfel. u0 Double 42.0 u1 Boolean false u2 Boolean true u3 Int 240 u4 Int 3 u5 X u6 Any 42 u7 X u8 Int 42 u9 X u10 Boolean true
4(7) Lösning del B. Skriva kod. 80 p Uppgift B1: 25p. Endast de poänggivna delarna markerade med //Xp ingår i bedömningen: 1 object NLP { 2 val ispunctuation = Set('.', '-', ',', ';', '?', '!') 3 val isstopword = Set("om", "i", "till", "och", "med", "för", "är", "alla") 4 5 case class Doc(text: String) { 6 val words: Vector[String] = // 8p 7 text.map(ch => if (ispunctuation(ch)) ' ' else ch) 8.toLowerCase 9.split(' ') 10.filter(_.nonEmpty) 11.toVector 12 13 val freqmap: Map[String, Int] = // 5p 14 words.groupby(x => x).mapvalues(_.length) 15 16 def freq(word: String): Int = freqmap.getorelse(word, 0) 17 18 val terms: Set[String] = words.toset diff isstopword // 4p 19 20 val norm: Double = math.sqrt(terms.toseq.map(t => freq(t) * freq(t)).sum) 21 } 22 23 def cosinesimilarity(a: Doc, b: Doc): Double = { // 8p 24 val allterms: Set[String] = a.terms ++ b.terms 25 val sumfreqproduct = allterms.toseq.map(t => a.freq(t) * b.freq(t)).sum 26 sumfreqproduct/(a.norm * b.norm) 27 } 28 } words: 8p fördelas ungefär så här: 3p för omvandling av separatortecken till blanka, 1p för omvandling till små bokstäver, 1p för splittning på blanktecken, 2p för bortfiltrering av tomma strängar, 1p för omvandling till Vector. freqmap: 5p fördelas ungefär så här: 2p för grupperingen, 1p för skapande av Map, 2p för beräkning av storleken. Exempel på motsvarande, alternativ lösning som också ger 5p: 1 val freqmap: Map[String, Int] = { 2 val m = scala.collection.mutable.map.empty[string, Int] // 1p 3 words foreach { w => m.update(w, m.getorelse(w, 0) + 1 } // 3p 4 m.tomap // 1p 5 } term: 4p fördelas ungefär så här: 1p för filter 1p för Not 1p för användning av isstopword, 1p för omvandling till mängd. cosinesimilarity: 8p fördelas ungefär så här: 2p för unionen av termer, 4p för produktsumman, 2p divisionen med normprodukten.
5(7) Uppgift B2: 30p. Endast de poänggivna delarna markerade med //Xp ingår i bedömningen: 1 object SchoolAllocation { 2 3 case class Pos(x: Double, y: Double) { 4 def distanceto(other: Pos): Double = // 2p 5 math.hypot(x - other.x, y - other.y) 6 } 7 8 class Student(val name: String, val prefs: Seq[School], val pos: Pos){ 9 private var next = -1 10 11 def nextschool: School = { next += 1; prefs(next) } // 4p 12 } 13 14 class School(val name: String, maxstudents: Int, val pos: Pos){ 15 import scala.collection.mutable.arraybuffer 16 17 private var current: ArrayBuffer[Student] = ArrayBuffer.empty 18 19 def allocation: Vector[Student] = current.tovector 20 21 def add(student: Student): Option[Student] = { // 13p 22 current.append(student) 23 if (current.length > maxstudents) { // find index of student with max distance 24 var maxdistindex = 0 25 for (i <- 1 until current.length) { 26 if (pos.distanceto(current(i).pos) > 27 pos.distanceto(current(maxdistindex).pos)) { 28 maxdistindex = i 29 } 30 } 31 val bumped = current.remove(maxdistindex) 32 Some(bumped) 33 } else None 34 } 35 } 36 37 def allocate(students: Seq[Student], schools: Seq[School]): Unit = { // 11p 38 val studentbuffer = students.tobuffer 39 while (studentbuffer.nonempty) { 40 val student = studentbuffer.remove(0) 41 val school = student.nextschool 42 println(s"allokera ${student.name} till ${school.name}") 43 val bumpedopt = school.add(student) 44 bumpedopt foreach { bumped => 45 studentbuffer.append(bumped) 46 println(s"${bumped.name} utknuffad från ${school.name}") 47 } 48 } 49 } 50 51 }
6(7) Uppgift B3: Java. 25p Endast de poänggivna delarna markerade med //Xp ingår i bedömningen: put, count, isfull. 1 public class Grid { 2 public static final int rows = 6; 3 public static final int cols = 7; 4 5 private char[][] grid = new char[rows][cols]; 6 7 public Grid() { 8 for (int r = 0; r < rows; r++){ 9 for (int c = 0; c < cols; c++){ 10 grid[r][c] = ' '; 11 } 12 } 13 } 14 15 public char get(int row, int col){ 16 if (row >= 0 && row < rows && col >= 0 && col < cols) { 17 return grid[row][col]; 18 } else { 19 return ' '; 20 } 21 } 22 23 public int put(int col, char marker){ // 7p 24 int row = 0; 25 while (get(row, col)!= ' ') { 26 row++; 27 } 28 if (row == rows) { 29 return -1; 30 } else { 31 grid[row][col] = marker; 32 return row; 33 } 34 } 35 36 private int count(int startrow, int startcol, 37 int deltarow, int deltacol, char ch){ // 11p 38 int result = 0; 39 int r = startrow + deltarow; 40 int c = startcol + deltacol; 41 while (get(r, c) == ch) { // while marker is ch: count and add deltas 42 result++; 43 c = c + deltacol; 44 r = r + deltarow; 45 } 46 r = startrow - deltarow; 47 c = startcol - deltacol; 48 while (get(r, c) == ch) { // loop in opposite direction: subtract deltas 49 result++; 50 c = c - deltacol; 51 r = r - deltarow; 52 } 53 return result; 54 } 55
7(7) 56 public boolean iswinnerat(int row, int col, char marker){ 57 if (grid[row][col]!= marker) { 58 return false; 59 } else { 60 return count(row, col, 1, 0, marker) >= 3 // up-down 61 count(row, col, 0, 1, marker) >= 3 // right-left 62 count(row, col, 1, 1, marker) >= 3 // diagonal 1 63 count(row, col, 1, -1, marker) >= 3; // diagonal 2 64 } 65 } 66 67 public boolean isfull(){ // 7p 68 boolean foundspace = false; 69 int col = 0; 70 while (col < cols &&!foundspace){ 71 foundspace = get(rows - 1, col) == ' '; 72 col++; 73 } 74 return!foundspace; 75 } 76 } Typiska engångsavdrag med 1 i avdrag: saknat semikolon saknat return men rätt värde i slutet av blocket Int istf int saknade tomma parenteser efter metod () fel indexering med xs(i) istf xs[i] eller xs.get(i) felaktig uppdatering av ArrayList, tilldelning istället för add Onödigt this på statisk medlem