Datortentamen i TDP007 fredag 10 juni 2016 08:00-12:00 ------------------------------------------------------ Tentan startar kl. 08:00 och pågår till 12:00. Ni kommer att få köra på begränsade datortentakonton, precis som under duggan. Instruktioner för att logga in på dessa lämnas i salen. Alla filer som ni behöver för att lösa uppgifterna finns i hemkatalogen när ni har loggat in. Där finns också en PDF-version av en tidig utgåva av kursboken som ni gärna får använda er av. Öppna den med kommandot okular eller xpdf. Svar på frågor skrivs i vanliga textfiler och programkod skrivs i rb-filer. En fil per huvuduppgift ska produceras, totalt alltså sex filer. Ingen särskild inlämning behöver göras. När man är färdig loggar man ut och lämnar salen. Tentan består av sex uppgifter, några indelade i deluppgifter, som totalt kan ge 32 poäng. För godkänt krävs 50%, dvs minst 16 poäng. För betyg 4 krävs minst 21 poäng och för 5 minst 26 poäng. Inga poäng från duggor kan räknas tillgodo, utan tentan bedöms helt på egen hand. Om man redan har fått ett betyg genom duggan eller tidigare tentor kan det aldrig sänkas, bara höjas. Uppgift 1: Teorifrågor (5p) --------------------------- a) Om man kör följande Ruby-program, varför skriver det ut att a är 45 och inte 73? (1p) def sub a = 73 yield end def main a = 45 sub { puts "a = #{a}" } end main b) Konstruera ett reguljärt uttryck som kan matcha olika stavningar av efternamnet "Karlsson", med "C" eller "K" i början, med ett eller två "s", eller med "z"! (1p) c) Vad är det för skillnad på om ett XML-dokument är "valid" respektive "well-formed"? (1p) d) Beskriv minst två egenskaper hos språket Ruby som gör det lämpat för att användas som bas för interna domänspecifika språk och motivera svaret. (2p) Uppgift 2: Behandling av data i textfiler (5p) ---------------------------------------------- I filen bly-i-fisk.txt finns en tabell som visar hur mycket bly som finns i sill och strömming fiskad utanför Sveriges kust. Värdena är angivna i mikrogram per gram torrvikt och kommer från Naturvårdsverket. Skriv ett program som läser in tabellen i filen till en lämplig datastruktur. Därefter ska programmet skriva ut en lista med vilken mätplats som fått högst resultat för respektive år, inklusive detta mätvärde. Efter detta ska ytterligare en lista skrivas ut som presenterar hur många gånger respektive mätplats haft det högsta värdet. Programmet ska fungera så här: >> read_table("bly-i-fisk.txt") 1981: 0.197 (Harufjärden) 1982: 0.141 (Landsort) ... 2010: 0.068 (Utlängan) 2011: 0.073 (Väderöarna) Harufjärden: 3 Ängskärsklubb: 5 Landsort: 8 Utlängan: 12 Fladen: 2 Väderöarna: 1 Mätningen kommer från: http://www.naturvardsverket.se/Sa-mar-miljon/Statistik-A-O/Bly-i-fisk/ Uppgift 3: XML (6p) ------------------- I filen movies.xml finns information om filmutbudet på en påhittad biograf. Första delen av filen visar vilka filmer som går vissa datum. För varje föreställning indikeras också hur många platser som är lediga i salongen just nu. Andra delen av filen visar vilka salonger som finns och hur stora de är. Din uppgift är att skriva olika funktioner för att kunna läsa in och hantera informationen i filen. Om du vill göra en SAX-lösning hittar du ett exempel att utgå från i filen sax_example.rb och om du vill göra en DOM-lösning hittar du lite information om metoderna i klassen REXML::Element samt några exempel på XPath-uttryck i filen rexml.txt. Du ska läsa in bioprogrammet och för en given dag visa alla föreställningar i kronologisk (tidsmässig) ordning, samt hur många procent av platserna som är bokade just nu. Här är ett exempel på hur det ska fungera: >> bookings("movies.xml","2013-03-07") 14:30 FS6 7.7% War and Peace 14:30 FS8 1.1% Story of my life 18:00 FS4 2.6% It happened in the jungle 18:15 FS6 16.9% War and Peace 21:00 FS7 8.8% Dark and cold midnight 21:00 FS8 5.7% Us against the world Uppgift 4: DSL (5p) ------------------- Rebeckas Restaurangservice utvecklar programvaror som används av caféer, restauranger och liknande inrättningar. En av deras produkter är ett kassa- och bokningssystem som ritar upp en schematisk bild av restaurangen på skärmen där man kan se alla bord. Servitörerna kan klicka på borden på skärmen för att mata in beställningar eller ordna kvitton. Rebecka vill gärna att restaurangägarna ska kunna konfigurera systemet själv, om man bygger om eller flyttar runt borden. Därför vill hon ha ett enkelt domänspecifikt språk för att specificera hur restaurangen ser ut. I filen pelles.rb finns ett exempel på en layout för Pelles Pizzeria. Varje fil börjar alltid med raden size , som anger hur stor bilden av restaurangen på skärmen ska vara i antal tecken. Därefter kan man använda kommandot table , , , för att definiera ett bord. Varje bord har ett unikt nummer och storleken avser hur många personer som kan sitta vid det. Koordinaterna pekar ut var på bilden bordet ska ritas ut. Man kan rita upp väggar eller andra hinder med kommandot wall , , , som innebär att man ritar ut en fyrkant på skärmen där den första koordinaten är övre vänstra hörnet och den andra är nedre högra. Alla andra kommandon, vilka som helst, innebär att namnet skrivs ut med stora bokstäver på skärmen med början på den koordinat som anges. Din uppgift är nu att med hjälp av de tekniker för DSL som vi har tittat på i Ruby skriva kod som kan tolka Rebeckas domänspecifika språk och bygga upp en datastruktur som motsvarar restauranglayouten. Vi vill kunna åstadkomma två saker: utskrift av restauranglayouten med enkel teckengrafik och lagring av information om respektive bord. Exempel: >> r = Restaurant.new("pelles.rb") # >> r.print .----------------------------------------. | | | ##### ENTRANCE ####################### | | | | | | .----. .----. .----. | | | 1 | | 8 | | 9 | | | '----' '----' '----' | | | | .----. .----. | | | 2 | | 10 | | | '----' '----' | | | | .----. | | | 3 | | | '----' ##################### | | # | | .----. .----. .----. .----. # | | | 4 | | 5 | | 6 | | 7 | # | | '----' '----' '----' '----' # | | | '----------------------------------------' >> r[5].size 4 Här har vi alltså tolkat koden i filen pelles.rb, vilket har resulterat i ett objekt r av klassen Restaurant. Vi kan skriva ut layouten med r.print samt kolla storleken på bord 5 med r[5].size. Skriv kod som gör detta möjligt. Uppgift 5: Icke-deterministisk programmering (5p) ------------------------------------------------- De constraint-nätverk som vi har arbetat med har endast innehållit logiska värden och tal. Du ska nu få konstruera constraints som även kan innehålla tecken. Uppgiften består av två delar som kan ge poäng oberoende av varandra. Originalfilen som följde med seminariet finns bland de filer du har tillgång till. a) Konstruera en ny constraint Converter som i ena änden tar in ett heltal i intervallet 1-26 och i andra änden skickar ut ett tecken (eller snarare en sträng med ett tecken) i intervallet "A" till "Z". Givetvis ska informationsflödet kunna gå åt båda hållen. Så här skulle det kunna funka: >> key_char=Connector.new("key char") => # >> key_int=Connector.new("key int") => # >> Converter.new(key_int, key_char) => #, @char_connector=#> >> key_char.user_assign "C" D, [2010-02-23T15:34:06.744356 #28241] DEBUG -- : key char ignored request D, [2010-02-23T15:34:06.744702 #28241] DEBUG -- : key char got new value: C D, [2010-02-23T15:34:06.744799 #28241] DEBUG -- : key int got new value: 3 => "ok" b) Konstruera en ny constraint Transposer som har tre in-/utgångar. Denna constraint har till uppgift att genomföra en mycket enkel kryptering som består i att man förskjuter en bokstav ett visst antal steg i alfabetet. Om man ska förskjuta tre steg betyder det alltså att t.ex. A blir D. En Transposer ska ha tre in-/utgångar som har följande uppgifter: - en krypteringsnyckel i form av ett tal i intervallet 1-26 som talar om hur stor förskjutningen ska vara - en klartext i form av ett tecken (sträng av längden 1) i intervallet "A" till "Z" - en krypterad text, också i form av ett tecken i samma intervall som ovan Om man förskjuter så många steg att man passerar "Z" ska man givetvis börja om från "A" igen. De två deluppgifterna ger 2,5 poäng vardera. Uppgift 6: Parsning (6p) ------------------------ I den här uppgiften ska vi använda parsern från filen rdparse.rb för att läsa in en kalender. Informationen i kalendern ligger lagrad i vanlig text och ett exempel finns i filen calendar.txt som innehåller följande: - 6 mars 2014 - 08.15-10.00 'Labb, SU02' 10.15-12.00 'Föreläsning, A2' 13.15-15.00 'Seminarium, D31' - 7 mars 2014 - 10.00-11.00 'Möte med Anders' 12.00-13.30 'Lunch med Lisa' Uppgiften är att, med utgångspunkt från exemplet DiceRoller, skriva en enkel parser för kalenderdata. (Just detta exempel skulle antagligen ha varit enklare att läsa in med t.ex. reguljära uttryck, men den här gången ska vi använda vår parser.) Vi vill att det i slutändan ska fungera så här: >> c = Calendar.new => # >> c.read_meetings("calendar.txt") => [["Labb, SU02", 2014-03-06 08:15:00 +0100, 2014-03-06 10:00:00 +0100], ["Föreläsning, A2", 2014-03-06 10:15:00 +0100, 2014-03-06 12:00:00 +0100], ["Seminarium, D31", 2014-03-06 13:15:00 +0100, 2014-03-06 15:00:00 +0100], ["Möte med Anders", 2014-03-07 10:00:00 +0100, 2014-03-07 11:00:00 +0100], ["Lunch med Lisa", 2014-03-07 12:00:00 +0100, 2014-03-07 13:30:00 +0100]] Metoden read_meetings() som anropas ovan använder sig av parsern för att tolka innehållet i filen och returnera en datastruktur som innehåller kalenderinformationen. I lösningen ovan har vi lagrat start- och sluttid för respektive händelse i Time-objekt, men det är inte nödvändigt. Man kan även tänka sig egengjorda klasser, men de ska i så fall innehålla motsvarande information.