Tenta i TDP007 onsdag 17 mars 2010 kl 8-12 ------------------------------------------ Uppgift 1: Grundläggande Ruby (6p) ---------------------------------- a) Hitta på ett kodexempel (som inte är taget ur boken) som på ett bra sätt visar hur man kan använda iteratorer. Skriv sedan samma kod, men helt utan att använda iteratorer. (2p) b) Konstruera ett reguljärt uttryck som kan matcha en korrekt e-postadress. (1p) c) Definiera en klass Date som ska användas för att lagra datum. När man instansierar ett objekt ska man ange år, månad och dag. Klassen ska dessutom innehålla en metod next som flyttar fram det aktuella datumet en dag på ett korrekt sätt. (3p) Uppgift 2: Textfiler, reguljära uttryck m.m. (5p) ------------------------------------------------- I de tre filerna flicknamn.txt, slalom.txt och befolkning.txt finns tre olika tabeller med information. Du ska nu få chansen att göra uppgiften från det andra seminariet lite snyggare. Utan att ändra det minsta i dessa tre filer ska du skriva en klass Table som kan användas för att läsa in dessa tre tabellerna. Tanken är att klassen ska utformas så att den klarar av lite olika typer av tabeller. Du får själv genom att titta på de tre exemplen försöka hitta likheter och skillnader mellan filerna. Hoppa över huvudrubrikerna i tabellerna, men läs in kolumnrubrikerna så att du kan använda dem som nycklar i en hash för varje rad. Själva tabellen ska vara en array av hash. Tabellvärden som är tal ska omvandlas till tal, om det är möjligt. Se följande exempel: t1 = Table.read("flicknamn.txt") t1 = t1.sort { |item1,item2| item2[2005] <=> item1[2005] } puts "Det mest populära nya flicknamnet 2005 var:" puts t1[0]["Namn"] t2 = Table.read("befolkning.txt") puts "Första året i tabellen med fler födda än döda var:" data = t2.detect { |item| item["Born"]>item["Dead"] } puts data["Year"] t3 = Table.read("slalom.txt") puts "Number of times Austria won the Olympic gold medal in slalom:" puts t3.inject(0) { |res,item| item["Country"]=="Austria" ? res+1 : res } Tanken är att denna kod ska generera utskriften: Det mest populära nya flicknamnet 2005 var: Emma Första året i tabellen med fler födda än döda var: 2002 Number of times Austria won the Olympic gold medal in slalom: 6 Uppgift 3: XML (5p) ------------------- På Lilla Hembageriet använder man datorer för att planera bakningen. I filen cake.xml finns ett antal recept på kakor som ska bakas, samt uppgifter om hur många av varje kaka man planerar att baka under en viss dag (i taggen "batches"). En av de viktigaste ingredienserna att hålla koll på är antalet ägg. Eftersom det är viktigt att äggen är färska brukar bagaren Pelle beställa ägg från sin lokala äggleverantör dagen innan. För att underlätta vill Pelle ha ett program som kan läsa igenom en XML-fil med en plan för vad som ska bakas och räkna ut hur många ägg det går åt totalt. Eftersom Pelle misstänker att han kan vilja räkna andra ingredienser i framtiden vill han att lösningen ska kunna räkna vilken ingrediens som helst. Han vill ha en strömparserlösning (SAX), så det ska han få. Så här ska det funka i slutändan: >> count_ingredient("cake.xml" , "egg") => 55 Talet 55 kommer sig av att i just den här exempelfilen vill man baka 10 sockerkakor, 5 tigerkakor och 5 banankakor. För detta måste Pelle beställa 55 ägg. Uppgift 4: Domänspecifika språk (6p) ------------------------------------ Bob Arlington, även känd som "Bob the Builder", äger en kedja av bygg- och järnaffärer runt om i USA. En gång per månad vill han ha en sammanställning av hur mycket som har sålts i alla affärer. Hans utvecklingsavdelning har lyckats skriva ett program som kan generera rapporter från de olika affärerna och ett exempel på en sådan månadsrapport finns i filen sales.rb. Det som behöver göras nu är att gå igenom rapporten och summera hur många som sålts av varje vara. Bob vill att du ska göra detta med hjälp av någon teknik för domänspecifika språk i Ruby. Du ska alltså betrakta den här textfilen som källkod och skriva ett litet program som kan köra filen och därmed få fram statistiken som Bob vill ha. Som du ser i filen finns det tre huvudtyper av artiklar som Bob säljer. Han vill veta vilken artikel i varje kategori som säljer bäst. I praktiken innebär det att han vill att det ska funka ungefär så här: >> s=SalesAccumulator.load("sales.rb") => # >> s.most_popular For tool the most popular item is pliers (61) For fixing the most popular item is shank_nail (97) For other the most popular item is ear_plugs (82) => nil Definiera klassen SalesAccumulator som kommer fungera som en enkel interpretator för det lilla domänspecifika språket. Klassen ska kunna läsa in och summera artiklar, samt tala om vilken som säljer bäst i varje kategori. Klassen ska utformas på ett sådant sätt att det inte blir några problem om Bob börjar sälja andra artiklar, dvs hårdkoda så lite som möjligt. Uppgift 5: Icke-deterministisk programmering (5p) ------------------------------------------------- Lisa ska bygga en uteplats i sin trädgård. Den ska vara i form av en rätvinklig triangel. På de tre sidorna ska hon sätta kantstenar, och för att slippa dela på dessa vill hon gärna att sidorna ska vara så långa att stenarna går jämnt upp. Här kommer den (kanske) välkända Pythagoras sats in i bilden. Den säger att om man har en rätvinklig triangel med de två korta sidorna av längden a och b, så är förhållandet till längden på den långa "sneda" sidan c så här: a^2+b^2=c^2. Den mest kända Pythagorastriangeln är den som har följande sidor: 4 |\ stenar | \ 5 stenar |__\ 3 stenar En sådan tjusig uteplats skulle Lisa kunna bygga med totalt 12 kantstenar. Hon är nu intresserad av att hitta alla möjliga sådana trianglar för att kunna välja vilken som är bäst till hennes uteplats. Eftersom trädgården inte är hur stor som helst så får en sida vara högst 20 kantstenar lång. Din uppgift är att lösa Lisas problem med hjälp av problemlösaren i filen amb_test.rb. (Rent matematisk ska du alltså hitta alla heltalslösningar till a^2+b^2=c^2 sådana att a,b,c<=20. Lisa vill inte ha med "speglade" lösningar två gånger, dvs om vi har med triangeln med sidorna 3, 4 och 5 behöver vi inte ha med triangeln med sidorna 4, 3 och 5.) Uppgift 6: Parsning (5p) ------------------------ En grupp av arkeologer har just upptäckt lämningar efter en utdöd civilisation som man kallar för Cromare. De verkade ha ett annorlunda talsystem, baserat på fyra symboler: Symbol Värde -------------- i 1 x 10 c 100 m 1000 På gamla lertavlor har man funnit matematiska uträkningar med detta konstiga talsystem. Uppenbarligen kunde man blanda dessa "siffror" hur man ville. Ordningen spelade ingen roll, så som det gör i vårt talsystem. Vi tycker ju att 123 inte är samma tal som 321, men för Cromarna var ixi, xii och iix samma tal (tolv enligt vårt sätt att räkna). Istället för att använda våra symboler för de fyra räknesätten har man använt symbolerna P (plus), M (minus), G (multiplikation) och D (division). Deras uträkning "micPcix" betyder alltså 1101 plus 111, vilket borde bli 1212 om man räknar som vi gör. De verkade också kunna kombinera dessa operatorer så att "xiGiiPi" skulle motsvara (11*2)+1 = 23. Din uppgift är att hjälpa arkeologerna genom att skriva en parser som kan tolka matematiska uttryck som är skrivna som Cromarna gjorde. Utgå från parsern som finns i rdparse.rb. Följande är ett exempel på hur det skulle kunna se ut: >> CromanParser.new.start [Croman Calculator] xPiPiPi => 13 [Croman Calculator] iiGxPiii => 23 [Croman Calculator] iiGcDxxxxx => 4