LUNDS TEKNISKA HÖGSKOLA Institutionen för datavetenskap Lösning till tentamen EDAA45 Programmering, grundkurs 2017-08-23, 08:00-13: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(8) 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(8) 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 u2 Boolean true u3 u4 Int 6 u5 Set[Boolean] Set(false, true) u6 u7 Option[Int] None u8 Boolean false u9 u10
4(8) Lösning del B. 80 p. Uppgift B1: 25p. Endast de poänggivna delarna markerade med //p ingår i bedömningen: 1 object Keno { 2 type Ball = Int 3 val Min = 1 // Lowest ball number 4 val Max = 70 // Highest ball number 5 val N = 20 // Number of balls in a complete keno result 6 7 case class Coupon(name: String, balls: Set[Ball], iskingplayer: Boolean){ 8 def correct(isdrawn: Set[Ball]): Set[Ball] = balls.filter(isdrawn) //3p 9 // eller t.e.x: balls intersect isdrawn 10 def iskingwin(king: Ball) = iskingplayer && balls.contains(king) //4p 11 // eller t.ex.: iskingplayer && balls(king) 12 } 13 14 object HuxFlux { 15 import scala.util.random 16 17 private var isdrawn = Set.empty[Ball] 18 private var kenoking = 0 19 20 def reset(): Unit = { isdrawn = Set(); kenoking = 0 } 21 22 def nbrofdrawnballs: Int = isdrawn.size 23 def hasnext: Boolean = nbrofdrawnballs < N 24 def iscomplete: Boolean = nbrofdrawnballs == N 25 26 def next(): Ball = { // 7p 27 assert(hasnext, "balls already complete") 28 def draw = Random.nextInt(Max - Min + 1) + Min 29 var ball = draw 30 while (isdrawn(ball)) ball = draw 31 isdrawn += ball 32 ball 33 } 34 // alternativ lösning som bara drar slumptal en gång, men allokerar vektor: 35 def next2(): Ball = { 36 assert(hasnext, "balls already complete") 37 val remainingballs = (Min to Max).toVector diff isdrawn.tovector 38 val ball = remainingballs(random.nextint(remainingballs.length)) 39 isdrawn += ball 40 ball 41 } 42 43 def king: Ball = { // 6p 44 assert(iscomplete, "no king available") 45 if (kenoking == 0) kenoking = Random.shuffle(isDrawn.toVector).head 46 // eller t.ex. kenoking = isdrawn.tovector(random.nextint(isdrawn.size)) 47 kenoking 48 } 49 50 def result: Set[Ball] = { // 2p 51 assert(iscomplete, "incomplete result") 52 isdrawn 53 } 54 55 def sorted: Vector[Ball] = isdrawn.tovector.sorted // 3p 56 // eller: result.tovector.sorted 57 } 58 }
5(8) Uppgift B2: 35p. Endast de poänggivna delarna markerade med //p ingår i bedömningen: 1 object Data { 2 def getlines(): Vector[String] = // read rows and cols from file 3 scala.io.source.fromfile("europa.txt", "UTF-8").getLines.toVector 4 5 object Col { // Index för respektive kolumn i filen europa.txt 6 val (country, capitol, area) = (0, 1, 2) 7 } 8 9 val data: Vector[Vector[String]] = getlines.map(_.split(';').tovector) 10 11 val countries: Vector[String] = data.map(xs => xs(col.country)) // 3p 12 13 val capitolof: Map[String, String] = 14 data.map(xs => xs(col.country) -> xs(col.capitol)).tomap // 4p 15 16 val areaof: Map[String, Int] = 17 data.map(xs => xs(col.country) -> xs(col.area).toint).tomap // 5p 18 } 19 20 object Quiz { 21 import Data._ 22 import scala.io.stdin.readline 23 import scala.util.random 24 25 type Points = Int 26 val ptscapitol: Points = 100 27 val ptsbiggest: Points = 50 28 val probabilityofcapitolquestion = 0.4 29 30 def guesscapitol(country: String): String = 31 readline(s"vad heter huvudstaden i $country? >").tolowercase 32 33 def guessifbigger(country1: String, country2: String): Boolean = { 34 val a = readline(s"är $country1 större än $country2? (y/n) >") 35 a.tolowercase.startswith("y") 36 } 37 38 def printif(iscorrect: Boolean)(points: Int, answer: String): Unit = 39 if (iscorrect) println(s"rätt! Grattis till $points poäng :)\n$answer") 40 else println(s"fel :( \n$answer") 41 42 def showareaof(country: String): String = 43 s"$country är ${areaof(country)} km^2." 44 45 def showcapitolof(country: String): String = 46 s"huvudstad i $country är ${capitolof(country)}." 47 48 def randomcountry(): String = countries(random.nextint(countries.size)) 49 50 def askcapitol(): Points = { // 6p 51 val country = randomcountry() 52 val iscorrect = guesscapitol(country) == capitolof(country).tolowercase 53 printif(iscorrect)(ptscapitol, showcapitolof(country)) 54 if (iscorrect) ptscapitol else 0 55 } 56
57 def askbiggest(): Points = { // 9p 58 val country1 = randomcountry() 59 var country2 = randomcountry() 60 while (country1 == country2) country2 = randomcountry() 61 val iscorrect = 62 guessifbigger(country1, country2) == areaof(country1) > areaof(country2) 63 printif(iscorrect)(ptsbiggest, showareaof(country1)+"\n"+showareaof(country2)) 64 if (iscorrect) ptsbiggest else 0 65 } 66 67 def play(nbrofquestions: Int): Points = { // 8p 68 var pts: Points = 0 69 for (i <- 1 to nbrofquestions) { 70 println(s"\n--- Fråga nummer $i av $nbrofquestions ---") 71 if (Random.nextDouble < probabilityofcapitolquestion) pts += askcapitol() 72 else pts += askbiggest() 73 } 74 pts 75 } 76 77 def main(args: Array[String]): Unit = { 78 val nbrofquestions = args.headoption.map(_.toint).getorelse(1) 79 if (args.length > 1) scala.util.random.setseed(args(1).toint) 80 val pts = play(nbrofquestions) 81 println(s"\n*** Du fick $pts poäng. Tack och hej! ***") 82 } 83 } 6(8)
7(8) Uppgift B3: Java. 20p Endast de poänggivna delarna markerade med //p ingår i bedömningen: 1 import java.util.arraylist; 2 3 public class UberSquare { 4 private double debt = 0.0; 5 private int x; 6 private int y; 7 private int side; 8 private int id; 9 static private int nextid = 1; 10 static private boolean islogmode = false; 11 static private ArrayList<UberSquare> allsquares = new ArrayList<UberSquare>(); 12 13 public UberSquare(int x, int y, int side){ // 4p totalt 14 this.x = x; // init av x,y,size totalt 1p 15 this.y = y; 16 this.side = side; 17 id = nextid; // initialvärden id 1p 18 nextid += 1; // öka nextid 1p 19 allsquares.add(this); // lägg till i allsquares 1p 20 } 21 22 public int get(){ 23 return x; 24 } 25 26 public int gety(){ 27 return y; 28 } 29 30 public int area(){ 31 return side * side; 32 } 33 34 public UberSquare scale(int factor){ 35 side *= factor; 36 log("scale(" + factor + ") => " + tostring()); 37 return this; 38 } 39 40 public UberSquare move(int dx, int dy){ // 3p 41 debt += Math.hypot(dx, dy) + area(); 42 x += dx; 43 y += dy; 44 log("move(" + dx + ", " + dy + ") => " + tostring()); 45 return this; 46 } 47 48 public double pay() { //3p 49 double temp = debt; 50 debt = 0; 51 log("pay(" + temp + ") => " + tostring()); 52 return temp; 53 } 54 55 public String tostring(){ 56 return "UberSquare[id: " + id + ", pos: (" + x + "," + y + "), " +
57 "side: " + side + ", debt: " + debt + "]"; 58 } 59 60 public static ArrayList<UberSquare> findhighestdebt(){ // 10p 61 ArrayList<UberSquare> result = new ArrayList<UberSquare>(); 62 if (allsquares.size() > 0 ) { 63 UberSquare max = allsquares.get(0); // börja med första 64 // linjärsökning efter största: 65 for (int i = 1; i < allsquares.size(); i++) { 66 if (allsquares.get(i).debt > max.debt) { 67 max = allsquares.get(i); 68 } 69 } 70 // leta upp alla med lika stor skuld: 71 for (UberSquare us: allsquares) { 72 if (us.debt == max.debt) { 73 result.add(us); 74 } 75 } 76 } 77 return result; 78 } 79 80 static public void setlogmode(boolean on) { 81 islogmode = on; 82 log("log mode is on."); 83 } 84 85 static private void log(string msg) { 86 if (islogmode) { 87 System.out.println("LOG MESSAGE: " + msg); 88 } 89 } 90 } 8(8)