Bokmål Det Matematisk-naturvitenskapelege fakultet UNIVERSITETET I BERGEN Eksamen i emnet INF101/INF101F – Programmering II Mandag 24. september 2012, kl. 09-14. Tillatte hjelpemidler: alle skrevne og trykte. Antall sider: 5. • Det vil lønne seg å skaffe seg oversikt over hele eksamenssettet før du begynner å løse det. • Du har lov å bruke resultatene fra andre oppgaver og punkt, selv om du ikke har løst disse når du trenger resultatene. • Alle spørsmål skal besvares, og alle svar skal begrunnes. • Prosentsatsene angir omtrentlig vekt ved sensur. Oppgave 1 – Teori: Referanser [10%] a) (5/10) Programmet i Figur 1 implementerer en veldig enkel lenket liste. Studér programmet, og tegn noen enkle diagrammer som illustrerer hvordan datastrukturene til c, bc, og abc ser ut etter konstruksjon, og etter tilordningene på linje 31 og 36. b) (5/10) Hva blir resultatet (utskriften) av programmet? Forklar kort. Oppgave 2 – Minesweeper [30%] Det tradisjonelle spillet Minesweeper har røtter helt tilbake til 60-tallet, og var et populært prosjekt blant hobbyprogrammører på 80-tallet. Spillet foregår på et rutebrett, der det er utplassert et antall skjulte miner. Målet er å avdekke alle rutene der det ikke er plassert miner. Som hjelp markerer spillet – for hver avdekket rute – hvor mange av naborutene som inneholder miner. Vi skal implementere en liten del av funksjonaliteten til Minesweeper. Vi begynner med å definere en klasse MineSweeper, som bruker IArray2D (se vedlegg) for å representere spillbrettet. Klassen skal holde rede på • hvor minene er plassert, • hvilke felter som er åpnet/klarert, og hvor mange nabominer et åpent felt har a) (10/30) Du kan velge å bruke én eller flere IArray2D til å lagre informasjonen. • Deklarér feltvariablene til klassen MineSweeper. • Deklarér eventuelle hjelpeklasser (du trenger ikke skrive kode for konstruktører/get*/set* for disse). 1 1 public class Node<T> { 2 private T data; 3 private Node<T> next; 4 5 /** Construct new list node 6 * @param data Data value 7 * @param next Reference to tail, or null if this is the last element 8 */ 9 public Node(T data, Node<T> next) { 10 this.data = data; 11 this.next = next; 12 } 13 14 /** 15 * @return A dot-terminated, comma-separated representation of 16 * the list, e.g., "A, B, C." 17 */ 18 public String toString() { 19 return data + (next == null ? "." : ", " + next.toString()); 20 } 21 22 public static void main(String[] args) { 23 Node<String> c = new Node<String>("C", null); 24 Node<String> bc = new Node<String>("B", c); 25 Node<String> abc = new Node<String>("A", bc); 26 27 System.out.println("c: " + c.toString()); 28 System.out.println("bc: " + bc.toString()); 29 System.out.println("abc: " + abc.toString()); 30 31 bc = new Node<String>("D", new Node<String>("E", null)); 32 System.out.println("c: " + c.toString()); 33 System.out.println("bc: " + bc.toString()); 34 System.out.println("abc: " + abc.toString()); 35 36 c.data = "X"; 37 System.out.println("c: " + c.toString()); 38 System.out.println("bc: " + bc.toString()); 39 System.out.println("abc: " + abc.toString()); 40 } 41 } Figur 1: En enkel implementasjon av lenket liste. 2 Skriv (med ord) en datainvariant som beskriver hvilke verdier i datastrukturen som representerer gyldige brett, i henhold til spillereglene. b) (10/30) Skriv en metode public int mineDetector(Position pos) som går gjennom alle nabofeltene til pos, og teller hvor mange miner som er plassert der. Metoden returnerer −1 dersom det er en mine på posisjon pos, ellers 0–8 avhengig av hvor mange miner nabofeltene har. Tips: Lag en metode som gitt en posisjon returnerer en liste av (eller iterator over) alle naboer til posisjonen. Hint: Husk å ta hensyn til kanten av spillebrettet! c) (10/30) Skriv en metode public void clear(Position pos) som • Kaster MineExplodedException dersom pos inneholder en mine. • Teller nabominene, og merker brettet med hvor mange naboer som ble funnet. • Dersom antall naboer er 0, skal metoden fortsette på alle de omkringliggende feltene, og klarere dem. Dette gir effekten med et stort område som åpner seg hvis man er ‘heldig’ og klikker et sted uten miner i nærheten. Hint: Husk å ta hensyn til kanten av spillebrettet! Oppgave 3 – Temperaturproblemer [60%] Studenten Peer holder på å lage et lite programbibliotek for å håndtere temperaturer, og han begynner med følgende kode. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /** Temperatur i grader Celsius. Alltid større enn det absolutte nullpunkt, -273,15◦ C. */ public class Celsius implements Comparable<Celsius> { protected double g; public boolean datainvariant () { return g >= -273.15; } public Celsius ( double x ) { g = x; } public double toKelvin () { return g+273.15; } public int if ( g if ( g return } compareTo ( Celsius x ) { < x.g ) return -1; > x.g ) return +1; 0; } Han passer nøye på å definere datainvarianten som sikrer at temperaturen ikke skal bli lavere enn det absolutte null-punkt (den teoretisk laveste temperaturen som finnes). Kelvin er en temperaturskala som starter på det absolutte nullpunkt, og som ellers følger Celsius-skalaen. For å sjekke implementasjonen skriver Peer følgende aksiom. 3 public static void compareKelvin ( Celsius a, Celsius b ) { assertEquals( a.compareTo(b) <= 0, a.toKelvin() <= b.toKelvin() ); } Aksiomet bruker den statiske metoden assertEquals fra pakken junit.framework.Assert til å utføre selve testen. Det sjekker at det er en sammenheng mellom ordningen på temperaturene og deres verdi i Kelvin. Etter å ha studert temperatur-begrepet noe mer, finner Peer ut at han også vil lage klasser for måleskalaene Fahrenheit og Kelvin. Disse organiserer han som subklasser til klassen Celsius: 1 2 3 4 5 6 7 /** Temperatur i Kelvin, en absolutt skala som følger Celsius. */ public class Kelvin extends Celsius { public boolean datainvariant () { return g >= 0; } public Kelvin ( double x ) { super(0); g = x; } public double toKelvin () { return g; } } 1 2 3 4 5 6 7 /** Temperatur i Fahrenheit. */ public class Fahrenheit extends Celsius { public boolean datainvariant () { return g >= -459.67; } public Fahrenheit ( double x ) { super(0); g = x; } public double toKelvin () { return (g + 459.67) * 5/9; } } a) (10/60) Slik koden nå er skrevet er det fullt mulig å sette data som bryter de deklarerte datainvariantene. Hvilke rutiner (konstruktører og metoder) må modifiseres for å sikre oss mot dette? Skriv om de aktuelle rutinene slik at de kaster et passende, egendefinert unntak (exception) dersom en ulovlig temperatur blir satt. b) (10/60) Anta at det finnes et testdatasett i tabellen Celsius[] dataCelsius; Lag en enhetstest (JUnit-testmetode) som bruker disse dataene til å sjekke aksiomet compareKelvin. c) (10/60) Initialiser tabellen dataCelsius med et testdatasett som gjør at aksiomet compareKelvin avslører en alvorlig feil i koden. Forklar hvordan problemet oppstår. Hint: aksiomet skal være korrekt også for temperaturer representert i ulike temperaturskalaer. d) (10/60) Peer forsøker nå å reparere koden ved å føye følgende kode til klassen Kelvin (og lage tilsvarende metoder for de andre subklassene). public int compareTo ( Kelvin x ) { if ( g < x.g ) return -1; if ( g > x.g ) return +1; return 0; } 4 public int compareTo ( Celsius x ) { if ( g < x.g+273.15 ) return -1; if ( g > x.g+273.15 ) return +1; return 0; } public int compareTo ( Fahrenheit x ) { if ( g < x.toKelvin() ) return -1; if ( g > x.toKelvin() ) return +1; return 0; } Hvorfor vil ikke dette hjelpe på problemet? Hint: Hva er typen til a og b i compareKelvin? Utfør en endring i den opprinnelige koden som vil løse problemet oppdaget i c). e) (10/60) Hva vil det si at metoden equals er kompatibel med den naturlige ordningen (compareTo)? Er dette tilfelle med koden slik den er? Hvis ikke, lag en implementasjon av equals som er korrekt mht. dette kravet. f) (10/60) Synes du at Peer har gjort gode valg når han har designet temperatur-klassene? Hva er eventuelt problematisk? Forklar hvordan du selv ville løst oppgaven å lage et programbibliotek for å håndtere temperaturer i forskjellige skalaer. Lykke til! Anya Helene Bagge 5 Vedlegg IArray2D.java 1 /** 2 * Grensesnitt for en 2D-tabell. 3 * 4 * Du kan anta at det finnes en 5 * class Array2D<E> implements IArray2D<E> 6 * og at du kan lage en ny tabell, initialisert med null, med 7 * new Array2D<E>(width, height) 8 * 9 * @param <E> Elementtypen 10 */ 11 public interface IArray2D<E> { 12 /** 13 * @param pos En posisjon 14 * @return Elementet på posisjonen pos, eller null 15 * @requires isValid(pos) 16 */ 17 E get(Position pos); 18 19 /** 20 * @param pos En posisjon 21 * @param e Nytt element på posisjonen pos, eller null 22 * @requires isValid(pos) 23 */ 24 void set(Position pos, E e); 25 26 /** 27 * @return Høyden 28 */ 29 int getHeight(); 30 31 /** 32 * @return Bredden 33 */ 34 int getWidth(); 35 36 /** 37 * @param pos En posisjon 38 * @return true hvis posisjonen er gyldig i tabellen 39 */ 40 boolean isValid(Position pos); 41 42 /** 43 * @return en kopi av tabellen 44 */ 45 IArray2D<E> copy(); 46 } i Position.java 1 /** Koordinater */ 2 public class Position { 3 /** X- og Y-Verdiene */ 4 private final int x, y; 5 6 /** 7 * Konstruer en ny posisjon 8 */ 9 public Position(int x, int y) { 10 this.x = x; 11 this.y = y; 12 } 13 14 /** @return X-koordinaten */ 15 public int getX() { 16 return x; 17 } 18 19 /** @return Y-koordinaten */ 20 public int getY() { 21 return y; 22 } 23 } ii
© Copyright 2024