Datorlaborationer

LUNDS TEKNISKA HÖGSKOLA
Institutionen för datavetenskap
EDA017 Programmeringsteknik för E, I och Pi
HT 2013
Datorlaborationer
Anvisningar
Datorlaborationerna ger exempel på tillämpningar av det material som behandlas under kursen
och ger träning på att skriva program. Det finns 9 stycken datorlaborationer.
Anmälan till laborationsgrupp sker via kursens hemsida. Laboration 1-5 går HT2 2013 och
6-9 är schemalagda till VT1 2014. Laborationerna är individuella, det vill säga att de ska lösas
med självständigt enskilt arbete. Det är tillåtet att diskutera laborationerna och dess lösningar
med kurskamraterna, men var och en måste skriva sin egen lösning. Du måste arbeta med
varje laboration under ”rätt” vecka (om du inte är sjuk, se nedan). Om du är mycket ambitiös
kan du dock arbeta i förväg och få flera uppgifter godkända vid ett redovisningstillfälle, under
förutsättning att laborationsledaren har tid med detta. Du får däremot inte komma i efterhand
och kräva att bli godkänd på flera uppgifter (utom om du har varit sjuk).
Till varje laboration finns det förberedelser som du ska göra före laborationen. Kontakta
kursansvarig om det dyker upp några frågor när du förbereder laborationen.
• Till varje laborationsuppgift finns det läsanvisningar och förberedelseuppgifter. Före varje
laboration måste du ha:
– studerat läroboken enligt läsanvisningarna,
– läst igenom hela laborationen noggrant,
– löst förberedelseuppgifterna. I dessa uppgifter ska du skriva delar av de program som
ingår i laborationen. Det krävs inte att allt du skrivit är helt korrekt, men du måste ha
gjort ett rimligt försök. Kontakta en lärare om du får problem med uppgifterna.
Vi förutsätter att du har förberett dig enligt ovan innan du kommer till laborationen — det
är nödvändigt för att labhandledaren ska kunna hjälpa dig på bästa sätt.
Om du har förberett dig väl bör du hinna med alla uppgifterna under laborationen. Om
du inte gör det så får du göra de resterande uppgifterna på egen hand och redovisa dem
vid påföljande laborationstillfälle eller resurstillfälle (och förbereda dig mera till nästa laboration).
• Om du är sjuk vid något laborationstillfälle så måste du anmäla detta till kursansvarig
([email protected]) före laborationen. Om du uteblir utan att ha anmält sjukdom
så får du inte göra uppgiften förrän kursen går nästa gång, dvs nästa år, och då får du
inte något slutbetyg i kursen i år. Om du varit sjuk bör du göra uppgiften på egen hand
och redovisa den vid ett senare tillfälle. Har du varit sjuk och behöver hjälp för att lösa
laborationen så gå till något av de resurstillfällen som finns tillgängliga för det program du
läser. Det kommer också att anordnas en ”uppsamlingslaboration” i slutet av varje termin.
Laboration 1 – introduktion
2
Laboration 1 – introduktion
Mål: Under denna laboration ska du lära dig vad ett datorprogram är och se exempel på enkla
program. Du ska också lära dig att editera, kompilera och exekvera enkla Java-program med
hjälp av programutvecklingsverktyget Eclipse. Du ska också prova att använda Eclipse debugger.
Förberedelseuppgifter
• Läs igenom kapitel 1 i läroboken.
• Läs avsnittet Bakgrund.
• Läs igenom anvisningarna om Eclipse (finns i kurskompendiet).
Bakgrund
Ett datorprogram är ett antal rader text som beskriver lösningen till ett problem. Vi börjar med
att titta på ett mycket enkelt problem: att från datorns tangentbord läsa in två tal och beräkna
och skriva ut summan av talen. Lösningen kan se ut så här i Java:
1
2
3
4
5
6
7
8
9
10
11
12
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
System.out.println("Skriv två tal");
Scanner scan = new Scanner(System.in);
double nbr1 = scan.nextDouble();
double nbr2 = scan.nextDouble();
double sum = nbr1 + nbr2;
System.out.println("Summan av talen är " + sum);
}
}
Detta är nästan samma program som beskrivs i Eclipse-handledningen, men talen som summeras läses från tangentbordet. Du behöver inte förstå detaljerna i programmet nu, men vi vill
redan nu visa ett program som gör någonting intressantare än bara skriver ut ”Hello, world!”.
Allt som behövs för att du ska förstå programmet kommer vi att gå igenom under de första
veckorna av kursen. Förklaring av de viktigaste delarna av programmet:
• Rad 1: en inläsningsklass Scanner importeras från ett ”paket” med namnet java.util.
Detta paket och många andra ingår i Javas standardbibliotek.
• Rad 3: public class Calculator talar om att programmet, klassen, heter Calculator.
• Rad 4: public static void main(String[] args) talar om att det som vi skriver är ett
”huvudprogram”. Varje Javaprogram måste innehålla en klass med en main-metod. Exekveringen börjar och slutar i main-metoden.
• Rad 5: texten Skriv två tal skrivs ut på skärmen (println betyder ”print line”). När
man använder Eclipse så hamnar utskrifter i konsolfönstret.
• Rad 6: inläsningsobjektet scan skapas. Vi kommer senare att gå igenom ordentligt vad
detta betyder — nu räcker det att du vet att man alltid måste skapa ett sådant objekt när
man vill läsa från tangentbordet.
• Rad 7: en variabel nbr1 som kan innehålla ett reellt tal (double-tal) deklareras. Det betyder
att man skapar plats för variabeln i datorns minne. Man tilldelar också nbr1 ett talvärde
som man läser in från tangentbordet med nextDouble().
• Rad 8: samma sak med variabeln nbr2.
Laboration 1 – introduktion
3
• Rad 9: variabeln sum deklareras. Talen nbr1 och nbr2 adderas och summan lagras i sum.
• Rad 10: resultatet (innehållet i variabeln sum) skrivs ut.
• Rad 11: slut på main-metoden.
• Rad 12: slut på klassen.
Uppgifter
1.
Logga in på datorn. Öppna ett terminalfönster.
2.
Under laborationerna kommer du att använda en hel del färdigskrivna eller nästan färdigskrivna program. Nu ska du skapa ett Eclipse-arbetsområde (workspace) som innehåller
alla dessa filer.
1. Ett förberett arbetsområde finns i packad form i filen eda017-workspace.zip som
finns i katalogen /usr/local/cs/eda017/. Flytta musmarkören till terminalfönstret
så att det blir aktivt och skriv följande kommandon:
cd
unzip /usr/local/cs/eda017/eda017-workspace.zip
cd betyder att du flyttar dig till din hemkatalog, unzip packar upp filen.
2. Nu har du fått en katalog eda017-workspace i din hemkatalog. Katalogen innehåller
underkatalogerna cs_eda017, cs_eda017_src, lab1, lab2, lab3, . . . Kontrollera innehållet i ptdc-workspace med följande kommando:
ls eda017-workspace
I ptdc-workspace finns också en katalog .metadata. När du senare startar Eclipse
skapas i din hemkatalog en katalog .eclipse. Dessa kataloger syns inte när du gör ls,
eftersom deras namn inleds med punkt. Rör inte dessa kataloger — de används av
Eclipse för att spara viktig information, och om de inte finns eller har fel innehåll så
går det inte att starta Eclipse.
Alternativt kan du hämta filen eda017-workspace.zip från kursens hemsida:
1. Starta en webbläsare och gå till kursens hemsida, cs.lth.se/kurs/eda017.
2. Klicka på Laborationer.
3. Ladda ner filen eda017-workspace.zip till din hemkatalog.
4. Packa upp filen enligt punkt 1 ovan.
5. .zip-filen behövs inte mera. Tag bort den med följande kommando:
rm eda017-workspace.zip
3.
Nu ska du starta Eclipse. Ge följande kommando:
eclipse &
Efter en stund får du en dialogruta där Eclipse frågar efter vilket arbetsområde som du
vill använda. Ändra förslaget workspace till eda017-workspace.
&-tecknet betyder att Eclipse ska startas ”i bakgrunden”, alltså som ett fristående program. Det medför att man inte låser terminalfönstret utan kan arbeta med andra saker i
Laboration 1 – introduktion
4
det samtidigt som Eclipse kör. Alternativt kan du starta Eclipse genom att välja Eclipse
(den senaste versionen) från Gnome-menyn Applications > Programming.
I Eclipse-fönstret finns i projektvyn (”Package Explorer”, längst till vänster) projekten
cs_eda017, cs_eda017_src, lab1, lab2, lab3, . . . — det är de projektkataloger som finns i
ptdc-workspace. Filerna med namn som börjar på lab innehåller färdigskrivna program
som utnyttjas under laborationerna. cs_eda017 innehåller en biblioteksfil (.jar-fil) med
klasser som utnyttjas. cs_eda017_src innehåller källkoden (.java-filerna) till dessa klasser
— de behövs inte för laborationerna, men en del brukar vara intresserade av att titta på
dem.
4.
Du ska nu ladda in filen Calculator.java i en editor så att du kan ändra den. Man måste
klicka en hel del för att öppna en fil:
a) Öppna projektet lab1 genom att klicka på pilen bredvid projektet.
b) Öppna katalogen src genom att klicka på pilen.
c) Öppna paketet (default package) genom att klicka på pilen.
d) Öppna filen Calculator.java genom att dubbelklicka på filnamnet. Filen öppnas i en
editorflik.
5.
Kör programmet: markera Calculator.java i projektvyn, högerklicka och välj Run As >
Java Application. I konsolfönstret skrivs texten Skriv två tal. Klicka i konsolfönstret,
skriv två tal och tryck på return. Observera: när man skriver reella tal ska man vid
inläsning använda decimalkomma. När man skriver reella tal i programkod använder
man decimalpunkt.
Man kan köra det senaste programmet en gång till genom att klicka på Run-ikonen i
verktygsraden.
6.
Ändra main-metoden i klassen Calculator så att fyra rader skrivs ut: talens summa,
skillnad, produkt och kvot. Exempel på utskrift när talen 24 och 10 har lästs in:
Summan av talen är 34.0
Skillnaden mellan talen är 14.0
Produkten av talen är 240.0
Kvoten mellan talen är 2.4
Du ska alltså efter utskriften av summan lägga in rader där talens skillnad, produkt och
kvot beräknas och skrivs ut. Subtraktion anger man med tecknet -, multiplikation med *,
division med /.
Under tiden du skriver så kommer du att märka att Eclipse hela tiden kontrollerar så
att allt du skrivit är korrekt. Fel markeras med kryss till vänster om raden. Om du håller
musmarkören över ett kryss så visas en förklaring av felet. Om man sparar en fil som
innehåller fel så visas felmeddelandena också i Problem-fliken längst ner.
Du kommer också att märka att Eclipse kommer med förslag på vad du kan skriva.
När du till exempel har skrivit System.out.p så får du upp en ruta med allt som man
kan göra med System.out som börjar med p. Det här tycker en del är bra, andra tycker
att det är irriterande. Under nästa laboration ska vi visa hur man stänger av denna hjälp,
om man inte vill ha den.
Laboration 1 – introduktion
5
7.
Spara filen. Filen kompileras automatiskt när den sparas.
När .java-filen kompileras skapas en ny fil med samma namn som klassen men med
tillägget .class. Denna fil innehåller programmet översatt till byte-kod och används när
programmet exekveras.
Man ser inte .class-filerna inuti Eclipse, men de lagras i arbetsområdet precis som
.java-filerna. .java-filerna finns i en katalog src under respektive projektkatalog, .classfilerna finns i en katalog bin.
8.
Kör programmet och kontrollera att utskriften är korrekt. Rätta programmet om den inte
är det.
9.
Du ska nu använda Eclipse debugger för att följa exekveringen av programmet. Normalt
använder man debuggern för att hitta fel i program, men här är avsikten bara att du ska
se hur programmet exekverar rad för rad och att du ska bekanta dig med debuggerkommandona.
• Sätt en brytpunkt på den första raden i main-metoden. Kör programmet under debuggern (Debug As > Java Application).
• Svara ja på frågan om du vill byta till Debug-perspektivet.
• Klicka på Step Over-ikonen några gånger. Notera att den rad i programmet som
ska exekveras markeras i editorfönstret och att variabler som deklareras dyker upp
i variabelvyn till höger. Variablernas aktuella värden visas i ett av eclipse-fönsterna,
se till att du ser detta och kan identifiera hur variablerna får sina värden under
programmets exekvering.
• Sätt en brytpunkt på raden där du skriver kvoten mellan talen.
• Klicka på Resume-ikonen för att köra programmet fram till brytpunkten.
• Klicka på Resume igen för att köra programmet till slut.
Byt tillbaka till Java-perspektivet genom att klicka på knappen Java längst till höger i
verktygsfältet.
10.
Följande program använder den färdiga klassen SimpleWindow:
import se.lth.cs.eda017.window.SimpleWindow;
public class SimpleWindowExample {
public static void main(String[] args) {
SimpleWindow w = new SimpleWindow(500, 500, "Drawing Window");
w.moveTo(100, 100);
w.lineTo(150, 100);
}
}
Specifikationen av klassen SimpleWindow finns i appendix C i läroboken, eller online via
länk från kurshemsidan. Förklaring av de viktigaste delarna av programmet:
• På den första raden importeras den färdiga klassen SimpleWindow.
• Raderna som börjar med public och de två sista raderna med } är till för att uppfylla
Javas krav på hur ett program ska se ut.
• På nästa rad deklareras en referensvariabel med namnet w och typen SimpleWindow.
Därefter skapas ett SimpleWindow-objekt med storleken 500 × 500 pixlar och med
titeln ”Drawing Window”. Referensvariabeln w tilldelas det nya fönsterobjektet.
Laboration 1 – introduktion
6
• Sedan flyttas fönstrets ”penna” till punkten 100, 100.
• Slutligen ritas en linje.
Programmet finns inte i arbetsområdet, utan du ska skriva det från början. Skapa en fil
SimpleWindowExample.java:
a) Markera projektet lab1 i projektvyn,
b) Klicka på New Java Class-ikonen i verktygsraden.
c) Skriv namnet på klassen (SimpleWindowExample).
d) Klicka på Finish.
Dubbelklicka på SimpleWindowExample.java för att ladda in filen i editorn (om detta
inte redan gjorts automatiskt). Som du ser har Eclipse redan fyllt i klassnamnet och de
parenteser som alltid ska finnas. Komplettera klassen med main-metoden som visas ovan.
Spara filen, rätta eventuella fel och spara igen. Provkör programmet.
11.
Ändra programmet genom att välja bland metoderna i klassen SimpleWindow. Till exempel
kan du rita en kvadrat, ändra färg och linjebredd på pennan, rita fler linjer, skriva text,
etc.
12.
Öppna filen LineDrawing.java. I filen finns följande kod, komplettera programmet så att
det fungerar. Raderna med kommentarer ska ersättas med riktig programkod.
public class LineDrawing {
public static void main(String[] args) {
SimpleWindow w = new SimpleWindow(500, 500, "LineDrawing");
w.moveTo(0, 0);
while (true) {
// vänta tills användaren klickar på en musknapp
// rita en linje till den punkt där användaren klickade
}
}
}
Ledtråd: SimpleWindow innehåller också operationer för att ta hand om musklick. Dessa operationer har följande beskrivning:
/** Väntar tills användaren har klickat på en musknapp */
void waitForMouseClick();
/** Tar reda på x-koordinaten för musens position
vid senaste musklick */
int getMouseX();
/** Tar reda på y-koordinaten för musens position
vid senaste musklick */
int getMouseY();
Fundera ut vad som händer i programmet. while (true) betyder att repetitionen ska
fortsätta ”i oändlighet”. Man avbryter programmet genom att välja Quit i File-menyn i
SimpleWindow-fönstret.
Spara filen, rätta eventuella fel och spara då igen. Provkör programmet.
Checklista
Exempel på vad du ska kunna efter laborationen:
Laboration 1 – introduktion
7
• Starta Eclipse, öppna önskat arbetsområde (workspace) och öppna önskat projekt.
• Skapa .java-filer och skriva in enkla Java-program. (Med enkla program menas här ett
program på några rader som till exempel Calculator.)
• Kunna använda operationen System.out.println och förstå vad som händer när den används.
• Förstå vad det innebär att läsa in tal från tangentbordet.
• Spara .java-filer (kompilering sker då automatiskt).
• Exekvera program.
• Använda debuggern:
– Sätta och ta bort brytpunkt.
– Starta debuggern.
– Köra fram till en brytpunkt med Resume.
– Exekvera stegvis med Step over (och senare i kursen med Step Into).
– Byta mellan debug-perspektivet och Java-perspektivet.
Laboration 2 – använda färdigskrivna klasser, kvadrat
8
Laboration 2 – använda färdigskrivna klasser,
kvadrat
Mål: Du ska lära dig att läsa specifikationer av klasser och att utnyttja färdigskrivna klasser för
att lösa enkla uppgifter. Du ska också lära dig lite mera om Eclipse.
Förberedelser
•
•
•
•
Studera avsnitt 2 och 3.1-3.2 i läroboken.
Läs avsnittet Bakgrund.
Lös uppgift 2.2 och 2.5 i läroboken.
Tänk igenom följande frågor och se till att du kan svara på dem:
1.
2.
3.
4.
5.
Vad är en main-metod? Hur ser en klass med en main-metoden ut i stora drag?
Vad är referensvariabler och vad har man dem till?
Hur skapar man objekt?
Hur utför man en operation på ett objekt?
Vad använder man parametrar till?
Bakgrund
En klass Square som beskriver kvadrater har nedanstående specifikation.
/** Skapar en kvadrat med övre, vänstra hörnet i x,y
och med sidlängden side. */
Square(int x, int y, int side);
/** Ritar kvadraten i fönstret w. */
void draw(SimpleWindow w);
/** Raderar bilden av kvadraten i fönstret w. */
void erase(SimpleWindow w);
/** Flyttar kvadraten avståndet dx i x-led, dy i y-led. */
void move(int dx, int dy);
/** Tar reda på x-koordinaten för kvadratens läge. */
int getX();
/** Tar reda på y-koordinaten för kvadratens läge. */
int getY();
/** Tar reda på kvadratens area. */
int getArea();
Användning av klassen Square
I nedanstående program skapas först ett ritfönster. Därefter skapas en kvadrat som placeras mitt
i fönstret och ritas upp.
import se.lth.cs.eda017.window.SimpleWindow;
import se.lth.cs.eda017.square.Square;
public class DrawSquare {
public static void main(String[] args) {
Laboration 2 – använda färdigskrivna klasser, kvadrat
9
SimpleWindow w = new SimpleWindow(600, 600, "DrawSquare");
Square sq = new Square(250, 250, 100);
sq.draw(w);
}
}
• På rad 1 och rad 2 importeras de klasser som behövs, i detta fall: klassen SimpleWindow och
klassen Square. De klasserna finns inte i Javas standardbibliotek utan har skrivits speciellt
för kurserna i programmeringsteknik. Klasserna finns i ”paket” vars namn börjar med
se.lth.cs; det betyder att de är utvecklade vid institutionen för datavetenskap vid LTH,
som använder domännamnet cs.lth.se.
• På rad 5 skapas ett SimpleWindow-objekt. Refererensvariabeln w refererar till detta objekt.
• Därefter skapas ett Square-objekt som referensvariabeln sq refererar till.
• Slutligen ritas kvadraten sq.
Notera parametrarna som man använder när man skapar objekten. I new-uttrycket som skapar
kvadratobjektet står det till exempel (250, 250, 100). Det betyder att kvadraten ska ha läget
250, 250 och sidlängden 100. Läget och sidlängden kan man ändra senare i programmet, med
sq.move(dx,dy) och sq.setSide(newSide).
Lägg också märke till att referensvariablerna w och sq har olika typer. En referensvariabels
typ avgör vilka slags objekt variabeln får referera till. w får referera till SimpleWindow-objekt och
sq får referera till Square-objekt.
Användning av klassen SimpleWindow
Bläddra fram källkoden till klassen Square, ni hittar klassen i Eclipse-projektet cs_eda017_src
under katalogen src och i paketet se.lth.cs.eda017.square. Titta på källkoden och försök
förstå vad som händer. Några av operationerna i SimpleWindow (operationerna för att flytta
pennan och för att rita linjer) utnyttjas i operationen draw i klassen Square.
SimpleWindow innehåller också operationer, som inte används i Square, t.ex. för att ta hand
om musklick. Dessa operationer har följande beskrivning:
/** Väntar tills användaren har klickat på en musknapp. */
void waitForMouseClick();
/** Tar reda på x-koordinaten för musens position vid senaste musklick. */
int getMouseX();
/** Tar reda på y-koordinaten för musens position vid senaste musklick. */
int getMouseY();
När exekveringen av ett program kommer fram till waitForMouseClick så ”stannar” programmet och fortsätter inte förrän man klickat med musen någonstans i programmets fönster. Ett
program där man skapar ett fönster och skriver ut koordinaterna för varje punkt som användaren klickar på har följande utseende:
import se.lth.cs.eda017.window.SimpleWindow;
public class PrintClicks {
public static void main(String[] args) {
SimpleWindow w = new SimpleWindow(600, 600, "PrintClicks");
while (true) {
Laboration 2 – använda färdigskrivna klasser, kvadrat
10
w.waitForMouseClick();
w.moveTo(w.getMouseX(), w.getMouseY());
w.writeText("x = " + w.getMouseX() + ", " + "y = " + w.getMouseY());
}
}
}
while (true) betyder att repetitionen ska fortsätta ”i oändlighet”. Man avbryter programmet
genom att välja Quit i File-menyn i SimpleWindow-fönstret.
Också i nedanstående program ska användaren klicka på olika ställen i fönstret. Nu är det
inte koordinaterna för punkten som användaren klickar på som skrivs ut, utan i stället avståndet mellan punkten och den förra punkten som användaren klickade på. Vi sparar hela tiden
koordinaterna för den förra punkten (variablerna oldX och oldY).
Gå igenom ett exempel ”för hand” och övertyga dig om att du förstår hur programmet
fungerar.
Laboration 2 – använda färdigskrivna klasser, kvadrat
11
import se.lth.cs.eda017.window.SimpleWindow;
public class PrintClickDists {
public static void main(String[] args) {
SimpleWindow w = new SimpleWindow(600, 600, "PrintClickDists");
int oldX = 0; // x-koordinaten för "förra punkten"
int oldY = 0; // y-koordinaten
while (true) {
w.waitForMouseClick();
int x = w.getMouseX();
int y = w.getMouseY();
w.moveTo(x, y);
int xDist = x - oldX;
int yDist = y - oldY;
w.writeText("Avstånd: " + Math.sqrt(xDist * xDist + yDist * yDist));
oldX = x;
oldY = x;
}
}
}
Datorarbete
1.
Logga in på datorn, starta Eclipse, öppna projektet lab2. (Logga in, starta Eclipse och
öppna ett projekt ska du alltid göra, så det skriver vi inte ut i fortsättningen.)
2.
Öppna en webbläsare och gå till kursens hemsida, cs.lth.se/kurs/eda017. Under Dokumentation finns en länk till dokumentationen av de färdigskrivna klasser som används
under laborationerna, alltså klasserna i paketet se.lth.cs.eda017. Leta upp och titta
igenom specifikationen av klassen Square. Det är samma specifikation som finns under
Bakgrund, fast i något annorlunda form.
3.
Klassen DrawSquare finns i filen DrawSquare.java. Öppna filen, kör programmet.
4.
Kopiera filen DrawSquare.java till en ny fil med namnet DrawThreeSquares.java. Enklast
är att göra så här:
1. Markera filen i projektvyn, högerklicka, välj Copy.
2. Högerklicka på (default package), välj Paste, skriv det nya namnet på filen.
Notera att Eclipse ändrar klassnamnet i den nya filen till DrawThreeSquares.
Ändra sedan klassen så att kvadraten ritas tre gånger. Mellan uppritningarna ska
kvadraten flyttas. Du ska fortfarande bara skapa ett kvadratobjekt i programmet. Resultatet ska bli en figur med ungefär följande utseende:
Testa programmet, rätta eventuella fel.
12
Laboration 2 – använda färdigskrivna klasser, kvadrat
5.
Någonstans i ditt program skapar du ett kvadratobjekt med en sats som har ungefär följande utseende: Square sq = new Square(300,300,200). Tag bort denna sats från programmet (eller kommentera bort den). Eclipse kommer att markera flera fel i programmet,
eftersom sq inte är deklarerad och du senare i programmet utnyttjar den variabeln. Läs
och tolka felmeddelandena.
Lägg sedan in satsen Square sq = null i början av programmet. Eclipse kommer inte
att hitta några fel, eftersom programmet nu följer de formella reglerna för Javaprogram.
Exekvera sedan programmet och se vad som inträffar. Studera felmeddelandet så att du
kan tolka det.
Meddelanden om exekveringsfel skrivs i konsolfönstret. Det skrivs också ut en ”stack
trace” för felet: var felet inträffade, vilken metod som anropade metoden där det blev
fel, vilken metod som anropade den metoden, osv. Om man klickar på ett radnummer
öppnas rätt fil i editorn med den raden markerad (under förutsättning att programtexten,
”källkoden”, för den filen är tillgänglig).
Lägg sedan tillbaka den ursprungliga satsen för att skapa kvadratobjektet. Ändra parametern w i det första anropet av draw till null. Kör programmet, studera det felmeddelande som du får.
När man får exekveringsfel kan det vara svårt att hitta orsaken till felet. Här är en
debugger till stor hjälp, i och med att man kan sätta brytpunkter och köra programmet
stegvis.
6.
Kör programmen PrintClicks och PrintClickDists.
7.
Skriv ett program där ett kvadratobjekt skapas och ritas upp i ett ritfönster. När användaren klickar med musen i fönstret ska bilden av kvadraten raderas, kvadraten flyttas
till markörens position och ritas upp på nytt. Titta gärna på den totala specifikationen
av SimpleWindow och Square som finns länkat från kurshemsidan. Vilka metoder som
verkar användbara för detta kan du hitta i dokumentationen?
Välj ett lämpligt namn på klassen. För att skapa en fil för klassen kan du antingen
skapa en tom klass (klicka på New Java Class-ikonen, skriv namnet på klassen, klicka på
Finish) eller kopiera någon av de filer som du redan har.
Testa programmet.
8.
Modifiera programmet i uppgift 7 så att varje flyttning går till så att kvadraten flyttas
stegvis till den nya positionen. Efter varje steg ska kvadraten ritas upp (utan att den
gamla bilden raderas). Exempel på kvadratbilder som ritas upp när flyttningen görs i 10
steg:
klickat här
ursprunglig position
Kvadratens slutliga position behöver inte bli exakt den position som man klickat på. Om
man till exempel ska flytta kvadraten 94 pixlar i 10 steg är det acceptabelt att ta 10 steg
med längden 9.
Skriv in och testkör programmet.
Laboration 2 – använda färdigskrivna klasser, kvadrat
9.
13
Observera att programmet från uppgift 8 ritar många bilder av samma kvadrat och att
alla bilderna kommer att synas i fönstret när programmet är slut. Om man raderar den
”gamla” bilden innan man ritar en ny bild så kommer man att få en ”rörlig”, ”animerad”,
bild. För att man ska se vad som händer måste man då göra en paus mellan uppritning
och radering — det gör man med SimpleWindow-metoden delay, som har en parameter
som anger hur många millisekunder man ska vänta. Exempel:
while (sq.getSide() > 0) {
sq.draw(w);
SimpleWindow.delay(10);
sq.erase(w);
sq.setSide(sq.getSide() - 10);
}
Kodsnutten ovan animerar en ny mindre kvadrat tills dess att kvadratens sida blivit
mindre än eller lika med noll.
Kopiera koden från uppgift 8 till en ny fil AnimatedSquare.java. Lägg in fördröjning
och radering så att kvadratbilden blir ”animerad”.
Anmärkning: i ett ”riktigt” program som visar rörliga bilder åstadkommer man inte animeringen på det här sättet. Denna lösning har bristen att man inte kan göra något annat
under tiden som animeringen pågår, till exempel kan programmet inte reagera på att man
klickar med musen.
10.
I denna uppgift ska du lära dig fler kommandon i Eclipse. Det finns ett otal kommandon,
mer eller mindre avancerade, och många av dem använder man sällan. Tre kommandon
som man ofta använder:
• Source-menyn > Format. Korrigerar programlayouten i hela filen. Ser till exempel till
att varje sats skrivs på en rad, att det är blanka runt om operatorer, och så vidare.
Man bör formatera sina program regelbundet, så att de blir läsbara. Observera att
programmet ska vara korrekt formaterat när du visar det för labhandledaren för att
få det godkänt. Notera också kortkommandot som står intill menyalternativet. Prova
att använda kortkommandot också, och lär dig gärna det, då det är snabbare och mer
bekvämt än att klicka.
• Refactor-menyn > Rename. Ändrar namn på den variabel eller metod som markerats
(lokalt om det är en lokal variabel, i hela klassen om det är ett attribut, även i andra
klasser om det är en publik metod).
Man kan ställa in hur mycket hjälp man ska få av editorn när man skriver Javaprogram.
Det gör man i Preferences. . . i Window-menyn. Det finns hur många möjligheter som
helst att ändra hur Eclipse uppför sig. Om du ändrar i Preferences och har ställt till det
för dig: använd knappen Restore Defaults! Om fönstret skulle se konstigt ut: gör Reset
Perspective i Windows-menyn.
11.
Kontrollera med hjälp av checklistan nedan att du behärskar de olika momenten i laborationen. Diskutera med övningsledaren om någonting är oklart.
Checklista
Exempel på vad du ska kunna efter laborationen:
• Tyda specifikationer av klasser.
• Skriva program som använder färdiga klasser:
14
Laboration 2 – använda färdigskrivna klasser, kvadrat
– Deklarera referensvariabler och skapa objekt.
– Utföra operationer på objekt.
Laboration 3 – implementera klasser, kvadrat
15
Laboration 3 – implementera klasser, kvadrat
Mål: Du ska träna på att implementera klasser.
Förberedelseuppgifter
• Studera kap 3 i läroboken noggrant.
• Läs igenom texten i avsnittet Bakgrund.
Bakgrund
Klassen Point beskriver en punkt. Den har följande specifikation:
/** Skapar en punkt med koordinaterna x,y. */
Point(int x, int y);
/** Tar reda på x-koordinaten. */
int getX();
/** Tar reda på y-koordinaten. */
int getY();
/** Flyttar punkten avståndet dx i x-led, dy i y-led. */
void move(int dx, int dy);
/** Returnerar avståndet mellan denna punkt och punkten p. */
double distanceTo(Point p);
/** Returnerar en teckensträng som representerar punkten. Strängen
innehåller punktens koordinater. Ex: 150 200 */
String toString();
Specifikationen är till för den som ska använda klassen när den är färdig. Här ser man hur man
skapar Point-objekt och vilka metoder man kan anropa på ett sådant.
String är en typ (egentligen en klass) som används för att beskriva en teckensträng, dvs. en
följd av tecken. Se avsnitt 6.7 i läroboken.
Implementeringen av klassen Point ser ut så här:
public class Point {
private int x; // punktens x-koordinat
private int y; // punktens y-koordinat
/** Skapar en punkt med koordinaterna x,y. */
public Point(int x, int y) {
this.x = x;
this.y = y;
}
/** Tar reda på x-koordinaten. */
public int getX() {
return x;
}
/** Tar reda på y-koordinaten. */
public int getY() {
return y;
}
Laboration 3 – implementera klasser, kvadrat
16
/** Flyttar punkten avståndet dx i x-led, dy i y-led. */
public void move(int dx, int dy) {
x = dx;
y = dy;
}
/** Returnerar avståndet mellan denna punkt och punkten p. */
public double distanceTo(Point p) {
return Math.hypot(x - p.x, y - p.y);
}
/** Returnerar en teckensträng som representerar punkten. Strängen
innehåller punktens koordinater. Ex: 150 200 */
public String toString() {
return x + " " + y;
}
}
Observera skillnaden mellan specifikationen (beskrivningen) av klassen och implementeringen
(programkoden).
Implementeringen av klassen Point ska finnas i en egen fil med namnet Point.java. Den
innehåller den fullständiga programkoden för klassen. Här deklareras attribut och här finns de
satser som utförs när en metod anropas.
Studera klassen ordentligt och försäkra dig att du förstår alla detaljer. Tänk igenom följande
frågor och se till att du kan svara på dem:
1.
2.
3.
4.
5.
Vilka attribut finns i klassen Point?
Vad händer inuti konstruktorn?
Vad menas med public och private?
Varför står det void framför vissa metodnamn?
Vad innebär return?
Inuti metoden distanceTo måste man komma åt den andra punktens x- och y-koordinat för
att kunna beräkna avståndet till den. Trots att attributen är privata kan man skriva p.x och p.y
för att nå dessa koordinater. Det beror på att ett attribut som är deklarerat private är privat
för klassen och inte bara för ett speciellt objekt. Men man kan även nå den andra punktens
koordinater på ett annat sätt. Hur?
Datorarbete
1.
Kopiera filen Square.java från projektet cs_eda017_src till detta projektet (Lab3). Kopiera
även filen DrawThreeSquares.java från Lab2 (som innehåller en main-metod som använder klassen Square). Din ”nya”, kopierade, DrawThreeSquares.java ska nu använda den
version av Square.java som du just kopierat till ditt projekt (Lab3). Detta gör vi genom att
i filen DrawThreeSquares.java, ta bort raden som importerar klassen Square. Nu kommer
java söka efter klassen Square i samma katalog som vi lagt vår DrawThreeSquares.java,
och eftersom Square nu finns där behöver den alltså inte importeras. Kontrollera att ditt
projekt kompilerar utan fel innan du går vidare till nästa steg.
2.
Ett objekts tillstånd kan representeras på olika sätt och ändras utan att det påverkar specifikationen eller de andra klasser i programmet som utnyttjar klassen. Inuti klassen Square
finns det två heltalsattribut x och y som håller reda på kvadratens position. Man skulle
lika gärna kunna använda en punkt för detta. Byt ut attributen x och y mot ett attribut av
typen Point. Gör de ändringar som krävs i resten av klassen. Kör programmet DrawThreeSquares för att kontrollera att klassen fortfarande fungerar. OBS: Koden i DrawThre-
Laboration 3 – implementera klasser, kvadrat
17
eSquares ska inte behöva ändras för att få programmet i att fungera. Klassen Square ska
alltså bara ändras internt, anropen till den ska inte förändras alls.
3.
Lägg till följande metoder i klassen Square:
/** Returnerar true om punkten med koordinaterna x,y ligger inuti
kvadraten. */
boolean contains(int x, int y);
/** Returnerar true om denna kvadrat och kvadraten sq överlappar. */
boolean overlaps(Square sq);
Ledning: Använd contains inuti overlaps. Och glöm inte att det ofta hjälper att först
rita och tänka på hur problemet ska lösas utan att tänka på programmeringskod (eller
möjligtvis bara skriva pseudokod). För att sen gå tillbaks till att fundera på hur det skrivs
i Java. Ni sitter oftast inne med lösningen även om ni inte tror att ni kan programmera
det!
4.
Skriv en klass med en main-metod där du skapar och ritar några Square-objekt och på
något sätt använder metoden overlaps för att testa om metoden är korrekt eller ej. Kör
programmet och kontrollera att allt fungerar som det ska. Använd gärna debuggern för
att hitta eventuella fel.
5.
Kontrollera med hjälp av checklistan nedan att du behärskar de olika momenten i laborationen. Diskutera med övningsledaren om någonting är oklart.
Checklista
Exempel på vad du ska kunna efter laborationen:
• Förstå skillnaden mellan specifikation och implementering.
• Implementera en klass:
– attribut
– konstruktor
– void-metoder och funktioner
• Tyda felutskrifter vid kompileringsfel och rätta felen.
• Tyda felutskrifter vid exekveringsfel och rätta felen.
• Förstå hur logiska uttryck kan användas för att jämföra två objekt.
• Kunna använda metoder inneifrån andra metoder, och kunna använda metoder som returnerar boolean.
Laboration 4 – implementera klasser, gissa tal
18
Laboration 4 – implementera klasser, gissa tal
Mål: Du ska fortsätta på att träna att implementera klasser. Du ska också få mer träning i att
använda if-, for- och while-satser.
Förberedelseuppgifter
• Repetera kap 2 och 3 i läroboken.
• Läs igenom texten i avsnittet Bakgrund.
Bakgrund
Under den här laborationen ska du skriva ett program för spelet ”Gissa talet”. Spelet går till så
att datorn ”tänker” på ett tal inom ett visst intervall. Användaren gissar på ett tal och får reda
på om det är för litet, för stort eller korrekt. Spelet fortsätter tills användaren gissat rätt tal.
Klassen NumberToGuess beskriver objekt som kan välja ett slumptal i ett visst intervall och
hålla reda på detta.
/** Skapar ett objekt med ett slumpmässigt valt heltal i
intervallet [min, max]. */
NumberToGuess(int min, int max);
/** Tar reda på minsta möjliga värde talet kan ha. */
int getMin();
/** Tar reda på största möjliga värde talet kan ha. */
int getMax();
/** Tar reda på om talet är lika med guess. */
boolean isEqual(int guess);
/** Tar reda på om talet är större än guess. */
boolean isBiggerThan(int guess);
Förutom denna klass ska du skriva en klass med en main-metod som utför själva spelet.
Datorarbete
1.
Öppna projektet lab4. Där finns en fil NumberToGuess.java med ett ”skelett” (en klass
utan attribut och med tomma metoder) till klassen NumberToGuess.
Implementera klassen NumberToGuess: Skriv in attributen i klassen. Skriv gärna en
kommentar till varje attribut som förklarar vad attributet betyder. Skriv också konstruktorn och se till att alla attribut får rätt startvärden. Implementera de övriga operationerna.
Ett av attributen ska tilldelas ett slumpmässigt valt värde. Användning av slumptal
beskrivs i läroboken, avsnitt 6.10. För tillfället behöver du bara veta att man måste skapa
ett Random-objekt och att man får ett nytt slumpmässigt heltal i intervallet [0, n) med
funktionen nextInt(n). Skrivsättet [0, n) betyder att 0 ingår i intervallet, n ingår inte i
intervallet. rand.nextInt(100) ger alltså ett slumpmässigt heltal mellan 0 och 99.
2.
I projektet lab4 finns det ett program TestNumberToGuess som är tänkt att användas för att
testa att metoderna i klassen NumberToGuess ger rätt resultat. Studera gärna programmet
om du vill. Kör programmet. Utskrifterna från programmet ger besked om allt fungerar
som det ska eller ej. Rätta eventuella fel och provkör igen.
Laboration 4 – implementera klasser, gissa tal
19
3.
Skriv programmet som utför en spelomgång där användaren får gissa på ett tal upprepade
gånger tills rätt tal gissats. Intervallets min- och max-värde samt användarens gissningar
ska läsas in. Efter en gissning ska användaren få besked om ifall det gissade talet var för
litet, för stort eller korrekt. Sist i programmet ska antal gissningar som krävdes skrivas ut.
Testa programmet.
4.
(Frivillig uppgift) Det finns olika mer eller mindre smarta sätt att gissa talet. I den här uppgiften ska du skriva ett program som ska ta reda på hur många gissningar som krävs om
man använder en optimal strategi. I programmet ska du använda klassen OptimalGuesser
(se nedan). Genom att anropa metoden nbrGuesses ett stort antal gånger och ta reda på
det maximala antal gissningar som krävdes kan man uppskatta antal gissningar som krävs
för ett visst intervall.
/** Beskriver en spelare som gissar tal på ett optimalt sätt. */
public OptimalGuesser();
/** Gissar tal på ett optimalt sätt tills rätt tal gissats.
nbr är det objekt som håller reda på det tal som ska gissas.
Returnerar antal gissningar som krävdes. */
public int nbrGuesses(NumberToGuess nbr);
Implementera klassen OptimalGuesser. Börja med att fundera ut vilken strategi man ska
använda för att behöva så få gissningar som möjligt. Diskutera med din labhandledare
ifall du är osäker på vilken strategi du ska använda inuti metoden nbrGuesses.
5.
(Frivillig uppgift) Skriv ett program som anropar metoden nbrGuesses ett stort antal
gånger och tar reda på största antalet gissningar som krävdes.
Ledning: För att beräkna maximala antalet gissningar behöver du en lokal variabel
som håller reda på hittills största värde. Kontrollera efter varje anrop av nbrGuesses om
denna variabel behöver uppdateras.
Att beräkna maximum (eller minimum) är ett vanligt problem (behandlas i läroboken,
avsnitt 7.13). Här är en generell algoritmen för att beräkna maximum:
max = "litet värde";
för alla värden
value = "nästa värde";
if (value > max) {
max = value;
}
Laboration 5 – implementera klasser, Turtle
20
Laboration 5 – implementera klasser, Turtle
Mål: Du ska fortsätta att träna på att implementera och använda klasser. Du ska också få mer
träning i att använda Eclipse debugger.
Förberedelseuppgifter
• Repetera kap 3 i läroboken.
• Tänk igenom följande frågor och se till att du kan svara på dem:
1. Vad är en specifikation respektive en implementering av en klass?
2. Vad är ett attribut? Var deklareras attributen? När reserveras det plats för dem i datorns minne och hur länge finns de kvar?
3. När exekveras satserna i konstruktorn? Vad brukar utföras i konstruktorn?
4. Vilka likheter/skillnader finns det mellan attribut, lokala variabler och formella parametrar.
5. Vad menas med public och private?
• Läs avsnittet Bakgrund.
Bakgrund
I grafiksystemet Turtle graphics kan man rita linjer. Linjerna ritas av en (tänkt) sköldpadda som
går omkring i ett ritfönster. Sköldpaddan har en penna som antingen kan vara lyft (då ritas
ingen linje då sköldpaddan går) eller sänkt (då ritas en linje). Sköldpaddan kan bara gå rakt
framåt, i den riktning som huvudet pekar. När sköldpaddan står stilla kan den vrida sig så att
dess huvud pekar åt olika håll.
En klass Turtle som beskriver en sköldpadda av detta slag har följande specifikation:
/** Skapar en sköldpadda som ritar i ritfönstret w. Från början
befinner sig sköldpaddan i punkten x,y med pennan lyft och
huvudet pekande rakt uppåt i fönstret (i negativ y-riktning). */
Turtle(SimpleWindow w, int x, int y);
/** Sänker pennan. */
void penDown();
/** Lyfter pennan. */
void penUp();
/** Går rakt framåt n pixlar i den riktning som huvudet pekar. */
void forward(int n);
/** Vrider beta grader åt vänster runt pennan. */
void left(int beta);
/** Går till punkten newX,newY utan att rita. Pennans läge (sänkt
eller lyft) och huvudets riktning påverkas inte. */
void jumpTo(int newX, int newY);
/** Återställer huvudriktningen till den ursprungliga. */
void turnNorth();
/** Tar reda på x-koordinaten för sköldpaddans aktuella position. */
int getX();
/** Tar reda på y-koordinaten för sköldpaddans aktuella position. */
int getY();
Laboration 5 – implementera klasser, Turtle
/** Tar reda på sköldpaddans riktning, i grader från positiv x-led. */
int getDirection();
21
Observera att vi här bestämmer vilket fönster som sköldpaddan ska rita i när vi skapar ett
sköldpaddsobjekt. Det kan väl sägas motsvara verkligheten: en sköldpadda ”befinner” sig ju
alltid någonstans.
I följande program ritar en sköldpadda en kvadrat med sidorna parallella med axlarna:
import se.lth.cs.window.SimpleWindow;
public class TurtleDrawSquare {
public static void main(String[] args) {
SimpleWindow w = new SimpleWindow(600, 600, "TurtleDrawSquare");
Turtle t = new Turtle(w, 300, 300);
t.penDown();
for (int i = 0; i < 4; i++) {
t.forward(100);
t.left(90);
}
}
}
I nedanstående variant av programmet har vi gjort två ändringar: 1) längden på sköldpaddans
steg väljs slumpmässigt mellan 0 och 99 pixlar, 2) efter varje steg görs en paus på 100 millisekunder. Den första ändringen medför att figuren som ritas inte blir en kvadrat, den andra ändringen
medför att man ser hur varje linje ritas.
import se.lth.cs.window.SimpleWindow;
import java.util.Random;
public class TurtleDrawRandomFigure {
public static void main(String[] args) {
Random rand = new Random();
SimpleWindow w = new SimpleWindow(600, 600, "TurtleDrawRandomFigure");
Turtle t = new Turtle(w, 300, 300);
turtle.penDown();
for (int i = 0; i < 4; i++) {
t.forward(rand.nextInt(100));
SimpleWindow.delay(100);
t.left(90);
}
}
}
Användning av slumptal beskrivs i läroboken, avsnitt 6.10. För tillfället behöver du bara veta
att man måste skapa ett Random-objekt och att man får ett nytt slumpmässigt heltal i intervallet
[0, n) med funktionen nextInt(n). Skrivsättet [0, n) betyder att 0 ingår i intervallet, n ingår inte
i intervallet. rand.nextInt(100) ger alltså ett slumpmässigt heltal mellan 0 och 99.
När klassen Turtle ska implementeras måste man bestämma vilka attribut som klassen ska
ha. En sköldpadda måste hålla reda på:
• fönstret som den ska rita i: ett attribut SimpleWindow w,
• var i fönstret den befinner sig: en x-koordinat och en y-koordinat. För att minska inverkan
av avrundningsfel i beräkningarna ska x och y vara av typ double,
Laboration 5 – implementera klasser, Turtle
22
• i vilken riktning huvudet pekar. Riktningen kommer alltid att ändras i hela grader. Man
kan själv välja om attributet som anger riktningen ska vara i grader eller i radianer,
• om pennan är lyft eller sänkt. Ett sådant attribut bör ha typen boolean. booleanvariabler
kan bara anta två värden: true eller false. Man testar om en booleanvariabel isPenDown
har värdet true med if (isPenDown) . . . .
När sköldpaddan ska gå rakt fram i den aktuella riktningen ska en linje ritas om pennan är sänkt.
Den aktuella positionen ska också uppdateras. Antag att sköldpaddan i ett visst ögonblick är
vriden vinkeln α i förhållande till positiv x-led. När operationen forward(n) utförs ska pennan
flyttas från punkten ( x, y) till en ny position, som vi kallar ( x1, y1):
x
(x1, y1)
n
α
(x, y)
y
Av figuren framgår att ( x1, y1) ska beräknas enligt:
x1
= x + n cos α
y1
= y − n sin α
I Java utnyttjas standardfunktionerna Math.cos(alpha) och Math.sin(alpha) för att beräkna
cosinus och sinus. Vinkeln alpha ska ges i radianer.
x och y är av typ double. När koordinaterna utnyttjas som parametrar till SimpleWindowmetoderna moveTo och lineTo och när de ska returneras som funktionsresultat i getX och getY
måste de avrundas till heltalsvärden. Det kan till exempel se ut så här:
w.moveTo((int) Math.round(x), (int) Math.round(y));
Datorarbete
1.
I filen Turtle.java i projektet lab5 finns ett ”skelett” (en klass utan attribut och med tomma
metoder) till klassen Turtle.
Implementera klassen Turtle: Skriv in attributen i klassen. Skriv gärna en kommentar
till varje attribut som förklarar vad attributet betyder. Skriv också konstruktorn och se till
att alla attribut får rätt startvärden. Implementera de övriga operationerna.
2.
Klasserna TurtleDrawSquare och TurtleDrawRandomFigure finns i filerna TurtleDrawSquare.java och TurtleDrawRandomFigure.java. Kör programmen och kontrollera att din Turtleimplementation är korrekt.
Använd gärna debuggern för att hitta eventuella svårfunna fel. Här kan det vara bra
att utnyttja kommandot Step Into. Det fungerar som Step Over med skillnaden att man
följer exekveringen in i metoder som anropas.
3.
Du ska nu träna mer på att använda debuggern i Eclipse. I fortsättningen förutsätter vi
att du utnyttjar debuggern för att hitta fel i dina program.
Laboration 5 – implementera klasser, Turtle
23
Välj ett av programmen från uppgift 2. Sätt en brytpunkt på den rad där Turtleobjektet skapas. Kör programmet i debuggern. Använd Step Into och följ hur man från
main-metoden ”gör utflykter” in i metoderna i klassen Turtle.
Lägg märke till vilka storheter (variabler, attribut, parametrar) som är tillgängliga när
man ”är i” main-metoden resp. inuti någon metod i klassen Turtle.
Tips! Om du klickar på trekanten framför this i variabelvyn visas Turtle-objektets
attribut.
4.
Skriv ett program där en sköldpadda tar 1000 steg i ett fönster. Sköldpaddan ska börja
sin vandring mitt i fönstret. I varje steg ska steglängden väljas slumpmässigt i intervallet
[1, 10]. Efter varje steg ska sköldpaddan vridas ett slumpmässigt antal grader i intervallet
[−180, 180].
5.
Skriv ett program där två sköldpaddor vandrar över ritfönstret. Steglängden och vridningsvinkeln ska väljas slumpmässigt i samma intervall som i föregående uppgift. Vandringen ska avslutas när avståndet mellan de båda sköldpaddorna är mindre än 50 pixlar.
Sköldpaddorna ska turas om att ta steg på följande sätt:
while ("avståndet mellan sköldpaddorna" >= 50) {
"låt den ena sköldpaddan ta ett slumpmässigt steg och göra
en slumpmässig vridning"
"låt den andra sköldpaddan ta ett slumpmässigt steg och göra
en slumpmässig vridning"
SimpleWindow.delay(10);
}
Låt den ena sköldpaddan börja sin vandring i punkten (250,250) och den andra i (350,350).
6.
Betrakta klasen Turtle. Ge exempel på ett attribut, en formell parameter och en lokal
variabel. Ange också var i klassen/programmet respektive storhet är tillgänglig och får
användas.
Exempel på
Attribut
Formell parameter
Lokal variabel
Namn
Får användas var
Laboration 6 – vektorer, simulering av patiens
24
Laboration 6 – vektorer, simulering av patiens
Mål: Du ska skriva ett enkelt simuleringsprogram och lära dig att använda vektorer.
Förberedelseuppgifter
• Studera avsnitt 8.1–8.3 i läroboken.
• Läs avsnittet Bakgrund.
• Betrakta följande satser:
Card[] theCards = new Card[52];
theCards[0] = new Card(Card.SPADES, 12);
theCards[1] = new Card(Card.HEARTS, 13);
// 1
// 2
Se till att du kan förklara vad som händer i steg 1 respektive 2 ovan. Rita en figur (på
papper) som visar vilka variabler och objekt som finns när man exekverat satserna till och
med punkt 1 resp. 2 ovan.
Bakgrund
Patiensen 1–2–3 läggs på följande sätt: Man tar en kortlek, blandar den och lägger sedan ut
korten ett efter ett. Samtidigt som man lägger korten räknar man 1–2–3–1–2–. . . , det vill säga
när man lägger det första kortet säger man 1, när man lägger det andra kortet säger man 2, osv.
Patiensen går ut om man lyckas lägga ut alla kort i leken utan att någon gång få upp ett ess när
man säger 1, någon 2-a när man säger 2 eller någon 3-a när man säger 3.
Man kan med hjälp av sannolikhetslära bestämma exakt hur stor sannolikheten är att patiensen ska gå ut.1 Men det är betydligt enklare att uppskatta sannolikheten genom att lägga
patiensen många gånger och räkna antalet gånger som den går ut.
Allra snabbast går det om datorn lägger patiensen. Då har man användning av följande
klasser, som beskriver kort och kortlekar:
/** konstanter för färgerna */
static final int SPADES = ...;
static final int HEARTS = SPADES + 1;
static final int DIAMONDS = SPADES + 2;
static final int CLUBS = SPADES + 3;
/** Skapar ett spelkort med färgen suit (SPADES, HEARTS, DIAMONDS, CLUBS)
och valören rank (1-13). */
Card(int suit, int rank);
/** Tar reda på färgen. */
int getSuit();
/** Tar reda på valören. */
int getRank();
/** Returnerar en läsbar representation av kortet, till exempel
"spader ess". */
String toString();
1
Se ”Fråga Lund om matematik”, www.maths.lth.se/query/answers, sök efter ”patiens” på sidan.
Laboration 6 – vektorer, simulering av patiens
/** Skapar en kortlek. */
CardDeck();
25
/** Blandar kortleken. */
void shuffle();
/** Undersöker om det finns fler kort i kortleken. */
boolean moreCards();
/** Drar det översta kortet i leken. */
Card getCard();
I följande program skriver man ut färg och valör för alla kort som man drar ur en blandad
kortlek:
public class CardExample {
public static void main(String[] args) {
CardDeck deck = new CardDeck();
deck.shuffle();
while (deck.moreCards()) {
Card c = deck.getCard();
System.out.println(c);
}
}
}
Med hjälp av System.out.println(c) skriver man ut ett kort på skärmen. Inuti println anropas metoden toString och den sträng som metoden returnerar kommer att skrivas ut. Det är
alltså i Card-klassens toString-metod man bestämmer hur kortet ska presenteras på skärmen.
Datorarbete
1.
Öppna projektet lab6. I projektet finns bland annat den färdiga klassen Card. Öppna filen
Card.java och se hur klassen är implementerad.
2.
Ett program med programraderna från den tredje förberedelseuppgiften finns i filen ArrayExample.java. Sätt en brytpunkt i början av programmet och provkör programmet i
debuggern. Klicka på plustecknet framför theCards i variabelvyn så ser du innehållet i
vektorn.
3.
Implementera klassen CardDeck.
I klassen ska man hålla reda på de 52 korten i en kortleken. Det gör man enklast
genom att lagra korten i en vektor:
import java.util.Random;
public class CardDeck {
private Card[] cards;
private int current; // index för "nästa" kort
private static Random rand = new Random();
public CardDeck() {
cards = new Card[52]; // skapa vektorn
... // skapa korten, lägg in dem i vektorn
current = 0;
}
Laboration 6 – vektorer, simulering av patiens
26
...
}
Att skapa korten i ordning är inte så enkelt – man känner ju inte värdet på konstanterna som anger färgerna. Men man ser att konstanterna ligger i ordning, så man kan skriva
satser som den följande:
for (int suit = Card.SPADES; suit <= Card.CLUBS; suit++) ...
När man ska blanda kortleken bör man använda följande algoritm:
för i = 51, 50, ..., 1 {
nbr = slumptal i intervallet [0,i+1)
byt plats på korten med index i och index nbr
}
4.
Ett testprogram (i filen TestCardDeck.java) för CardDeck finns i projektet. Testprogrammet
skapar en kortlek och skriver ut alla korten. Därefter blandas kortleken och alla kort skrivs
ut på nytt.
Kör programmet och kontrollera att det som skrivs ut ser ut att stämma.
5.
Skriv ett huvudprogram som utnyttjar klasserna Card och CardDeck för att lägga patiensen ett stort antal gånger och därefter skriva ut sannolikheten för att patiensen ska gå
ut.
Kör programmet. Den korrekta sannolikheten är ungefär 0.008165.
Laboration 7 – använda klassen ArrayList
27
Laboration 7 – använda klassen ArrayList
Mål: Du ska träna på att att använda klassen ArrayList. Du ska också få träning i att läsa data
från textfiler och skriva ut på textfiler.
Förberedelseuppgifter
• Studera avsnitt 12.1-12.3 och 12.8 i läroboken.
• Studera avsnitt 7.8 och 7.9 i läroboken.
• Läs igenom texten i avsnittet Bakgrund.
Bakgrund
Under den här laborationen ska du ska du implementera en klass Drawing som beskriver en
teckning bestående av ett antal linjer. Linjerna ritas upp i ett fönster av typen SimpleWindow.
I klassen finns det bland annat metoder för att lägga till och ta bort linjer. Till hjälp har du
klasserna Point (från lab 3) som beskriver en punkt och Line som beskriver en linje. Klasserna
har följande specifikationer:
Point
/** Skapar en punkt med koordinaterna x,y. */
Point(int x, int y);
/** Tar reda på x-koordinaten. */
int getX();
/** Tar reda på y-koordinaten. */
int getY();
/** Flyttar punkten avståndet dx i x-led, dy i y-led. */
void move(int dx, int dy);
/** Returnerar avståndet mellan denna punkt och punkten p. */
double distanceTo(Point p);
/** Returnerar en teckensträng som representerar punkten. Strängen
innehåller punktens koordinater. Ex: 150 200 */
String toString();
Line
/** Skapar en linje med ändpunkterna p1 och p2. */
Line(Point p1, Point p2);
/** Skapar en linje med ändpunkterna x1, y1 och x2, y2. */
Line(int x1, int y1, int x2, int y2) ;
/** Returnerar linjens längd */
double length();
/** Returnerar true om punkten p är nära linjen. */
boolean isNear(Point p);
/** Ritar linjen i fönstret w. */
void draw(SimpleWindow w);
Laboration 7 – använda klassen ArrayList
28
/** Raderar linjen i fönstret w. */
void erase(SimpleWindow w);
/** Returnerar en teckensträng som representerar linjen. Strängen
innehåller linjens ändpunkter Ex:
20 25 50 60 */
String toString()
Ledning och anvisningar för att implementera klassen Line:
• Låt klassen ha två attribut av typen Point för att hålla reda på linjens ändpunkter.
• För att avgöra om en viss punkt är ”nära” linjen kan man göra så här. Beräkna och summera avstånden från punkten till linjens två ändpunkter. Om skillnaden mellan denna summa
och linjens längd understiger ett visst värde, t. ex. 10, är punkten ”nära” linjen.
Drawing
/** Skapar ett ritnings-objekt som kan innehålla linjer. Ritningen kommer
att ritas i ritfönstret w. */
Drawing(SimpleWindow w);
/** Lägger till en linje i ritningen. Koordinater för linjens ändpunkter är
x1,y1 och x2,y2. Ritar upp nya linjen i ritfönstret. */
void addLine(int x1, int y1, int x2, int y2);
/** Låter användaren lägga till en eller flera linjer i ritningen.
Användaren klickar på första linjens startpunkt och därefter på
linjernas slutpunkter. Varje ny linje ska ritas ut i ritfönstret.
Användaren dubbelklickar i ritfönstret när inga fler linjer ska läggas
till. */
void collectLines();
/** Tar reda på antal linjer */
int nbrLines();
/** Tar bort de n senast tillagda linjerna och raderar dem i ritfönstret.
Om n är större än antal linjer tas alla linjer bort. */
void erase(int n);
/** Tar bort den linje som användaren klickar tillräckligt nära på.
Returnerar true om någon linje togs bort. */
boolean eraseLine()
/** Läser linjernas koordinater från textfilen med namnet fileName och
skapar linjerna. */
void readFromFile(String fileName);
/** Skriver linjernas koordinater på textfilen med namnet fileName och
skapar linjerna. */
void saveToFile(String fileName);
Ledning och anvisningar för att implementera klassen Drawing::
• Klassen ArrayList ska användas för att lagra linjerna inuti Drawing.
• I klassen finns en metod, collectLines, som låter användaren lägga till ett valfritt ett antal
linjer genom att klicka i fönstret. Så här går det till:
– Användaren klickar i fönstret för att bestämma första linjens startpunkt.
– Användaren klickar på en ny position i fönstret för att bestämma linjens slutpunkt.
Denna punkt blir samtidigt startpunkt för nästa linje.
Laboration 7 – använda klassen ArrayList
29
– Det hela upprepas tills användaren dubbelklickar i fönstret (dvs. klickar på samma
position i fönstret två gånger i rad).
För att rita en teckning behövs det också ett program som använder Drawing. Du ska skriva en klass med en main-metod där du låter användaren åstadkomma en teckning genom att
upprepade gånger få välja mellan följande alternativ:
1. Lägga till en eller flera linjer till ritningen. – Användaren klickar på första linjens startpunkt
och därefter på linjernas slutpunkter. Användaren dubbelklickar i ritfönstret när inga fler
linjer ska läggas till.
2. Ta bort ett antal linjer – Det är de senaste tillagda linjerna som ska tas bort. Antal linjer
som ska tas bort läses in från tangentbordet.
3. Ta bort en linje som väljs ut genom att användaren klickar på (nära) den.
4. Avsluta programmet
Ledning och anvisningar
• Låt användaren välja alternativ genom att skriva in talen 1, 2, 3 ... på tangentbordet.
• När det valda alternativet är utfört ska man kunna välja igen. Detta upprepas till användaren väljer att avsluta.
• Se till att det finns vettiga utskrifter så att den som använder programmet vet vad som ska
göras (klicka i fönstret, skriva in värden på tangentbordet).
• I början av programmet ska användaren få möjlighet att läsa in linjer från en textfil.
• När programmet ska avslutas ska användaren få möjlighet att spara linjerna på en textfil.
Datorarbete
1.
Öppna projektet lab7.
2.
Ditt program kommer att använda klassen Point från laboration 3. Du måste ange att
filerna i projektet lab3 ska vara tillgängliga i detta projekt:
1. Högerklicka på projektet lab7, välj Build Path > Configure Build Path.
2. Klicka på Projects.
3. Klicka på Add. . . , välj projektet lab3.
3.
Skapa och implementera klassen Line. I projektet finns det ett program TestLine som
anropar alla metoder i klassen Line. Tag bort kommentartecknen i TestLine och testkör
programmet. Om testprogrammet inte hittar några fel i Line visas ett fönster med en linje
och enbart true skrivs ut i konsolfönstret.
4.
Skapa och implementera klassen Drawing.
5.
Skriv programmet som låter en användare framställa en teckning. Notera att beskrivningen över hur programmet ska fungera återfinns i slutet av kapitlet Bakgrund ovan. Testa
programmet.
Laboration 8 – matris, spelet life
30
Laboration 8 – matris, spelet life
Mål: Du ska skriva program som använder matriser. Du ska också få mer träning på att använda
färdiga klasser och att implementera egna klasser.
Förberedelseuppgifter
• Studera avsnitt 8.4 i läroboken.
• Läs avsnittet Bakgrund.
Bakgrund
”Game of Life”, konstruerat av matematikern John Conway, är ett simuleringsspel som uppvisar
likheter med de förändringar som äger rum i samhällen med levande individer.
Som spelplan används ett rutnät. En ruta kan antingen vara tom eller innehålla en individ.
Från en given spelplan, en generation, ska samhället ändra sin struktur enligt vissa regler för
födelse och död.
Nedanstående regler gäller när en ny generation bildas. Alla förändringar vid en generationsväxling sker samtidigt över hela rutnätet.
1. Fortlevnad. En individ lever vidare till nästa generation om den har 2 eller 3 grannar.
2. Dödsfall. En individ med 4 eller fler grannar dör av trängsel. En individ med 0 eller 1
granne dör av isolering.
3. Födelse. I en tom ruta gränsande till exakt 3 individer föds en individ.
Varje ruta i rutnätet har 8 grannrutor. Även de diagonalt intilliggande rutorna betraktas alltså
som grannrutor.
Exempel på fyra på varandra följande generationer i Life-spelet (individerna markeras med
fyllda rutor):
Generation 1
Generation 2
Generation 3
Generation 4
Du ska skriva ett program för Life-spelet. Användargränssnittet, det fönster där spelplanen
ritas upp, beskrivs av en färdigskriven klass med namnet LifeView. Användaren kan när som
helst ändra spelplanens utseende genom att klicka på en ruta i spelplanen. Om man klickar
på en tom ruta skapas en individ i rutan, om man klickar på en fylld ruta töms rutan. Detta
utnyttjas normalt för att skapa generation 1.
Förutom spelplanen ritas en Next-knapp, som användaren klickar på när nästa generation
ska skapas och ritas upp, samt en Quit-knapp som användaren klickar på när spelet ska avslutas.
Följande klasser ska finnas i lösningen:
LifeBoard, som beskriver spelplanen och generationsräknaren. Innehåller operationer för att
ta reda på och ändra spelplanens utseende, t ex vilka rutor som ska vara tomma och vilka som
ska innehålla individer.
LifeView, som beskriver hur spelplanen presenteras på skärmen. Innehåller operationer för
att rita upp spelplanen och för att vänta på att användaren klickar i rutorna eller på Next- eller
Quit-knappen. Klassen är färdigskriven (specifikationen finns nedan).
Laboration 8 – matris, spelet life
31
Life, som beskriver Life-spelet. Innehåller operationer för att skapa en ny generation enligt
reglerna och för att skapa en individ i en ruta eller tömma en ruta.
LifeController, en klass med en main-metod, som genomför Life-spelet från generation 1
till ”Quit”.
Specifikation för LifeBoard och LifeView:
/** Skapar en spelplan med rows rader och cols kolonner. Spelplanen är från
början tom, dvs. alla rutorna är tomma och generationsnumret är 1. */
LifeBoard(int rows, int cols);
/** Undersöker om det finns en individ i rutan med index row,col. Om
index row,col hamnar utanför spelplanen returneras false. */
boolean get(int row, int col);
/** Lagrar värdet val i rutan med index row, col. */
void put(int row, int col, boolean val);
/** Tar reda på antalet rader. */
int getRows();
/** Tar reda på antalet kolonner. */
int getCols();
/** Tar reda på aktuellt generationsnummer. */
int getGeneration();
/** Ökar generationsnumret med ett. */
void increaseGeneration();
/** Skapar vy till spelplanen board. */
LifeView(LifeBoard board);
/** Ritar upp de fixa delarna av spelplanen (rutnätet,
generationsräknaren och knapparna. */
void drawBoard();
/** Ritar om de delar av fönstret som ändrats sedan föregående
uppritning. */
void update();
/** Väntar tills användaren klickar med musen. Ger:
1: klick i ruta på spelplanen. Index för rutan kan hämtas med
getRow och getCol.
2: klick i Next-rutan.
3: klick i Quit-rutan.
int getCommand();
/** Tar reda på radnummer för den klickade rutan efter kommando nr 1. */
int getRow();
/** Tar reda på kolonnummer för den klickade rutan efter kommando nr 1. */
int getCol();
Rutorna i rutnätet numreras 0..rows–1, 0..cols–1. I klassen LifeBoard finns det dock en tänkt
”ram” kring rutnätet. I ramrutorna finns inga individer. Genom att ramen finns behöver du inte
specialbehandla rutorna i kanten av rutnätet. Du kan alltså göra get(row,col) med row/col =
–1 eller rows/cols. I de fallen ger metoden get alltid resultatet false.
Laboration 8 – matris, spelet life
32
Klassen Life har följande specifikation:
/** Skapar ett Life-spel med spelplanen board. */
Life(LifeBoard board);
/** Skapar en ny generation. */
void newGeneration();
/** Ändrar innehållet i rutan med index row, col från individ till tom
eller tvärtom. */
void flip(int row, int col);
Datorarbete
Det är lämpligt att lösa ett stort problem stegvis. Först skriver man lite kod, sedan testar man
att det fungerar innan man går vidare. Därför är laborationsuppgiften uppdelad i mindre deluppgifter.
1.
Öppna projektet lab8. I filen LifeBoard.java finns ett skelett (en klass utan attribut och
med tomma metoder) till klassen LifeBoard.
Implementera klassen LifeBoard.
2.
Ett testprogram (TestLifeBoard.java) för klassen LifeBoard finns i projektet. Testprogrammet testar inte klassen fullständigt, men skapar ett LifeBoard-objekt, låter ett LifeViewobjekt rita upp brädet samt anropar de olika metoderna i LifeBoard.
Kör programmet och kontrollera att det fungerar som det ska. Avsluta exekveringen
genom att klicka i Quit-rutan på spelplanen.
3.
Det är dags att börja arbeta med den riktiga main-metoden. Inspiration kan hämtas från
testprogrammet (TestLifeBoard.java). Skapa en fil med namnet LifeController.java som
ska innehålla main-metoden. Du ska till att börja med se till att Quit-knappen fungerar
(Vänta med rutnätet och Next-knappen).
Ledning: Med metoden getCommand i LifeView kan man vänta tills användaren klickar
på en ruta eller en knapp. Då returneras ett tal med vars hjälp man kan avgöra vad
användaren gjorde. Låt alltså användaren klicka i fönstret tills användaren klickar i Quitrutan. Avsluta då programmet med hjälp av System.exit(0).
Kör programmet och kontrollera att du kan avsluta programmet genom att trycka på
Quit-knappen.
4.
Skapa en fil Life.java som ska innehålla klassen Life. Implementera konstruktorn och
metoden flip i klassen Life. Implementera metoden newGeneration, men bara delvis –
lägg in ökning av generationsnumret.
Spara klassen Life och rätta eventuella kompileringsfel.
5.
Fortsätt med klassen med main-metoden. Implementera satser i main-metoden så att rätt
saker utförs när man klickar med musen; om man klickar i en ruta ska en individ skapas
eller tas bort (med metoden flip). Om man klickar på Next-knappen ska generationsnumret ändras. Om man trycker på Quit-knappen ska programmet avslutas.
Kör programmet och kontrollera att det fungerar som det ska.
Laboration 8 – matris, spelet life
6.
33
Nu återstår att implementera färdigt metoden newGeneration i klassen Life. Lägg gärna
till en intern (privat) metod som beräknar antal grannar till en ruta. Metoden newGeneration
blir kortare och mer lättläst då.
Tänk på att i metoden newGeneration ska alla förändringar vid en generationsväxling
utföras samtidigt över hela spelplanen. Enklast åstadkommer du detta genom att deklarera en hjälpmatris där du lagrar den nya spelplanen. I slutet av metoden kopierar du
hjälpmatrisen till den riktiga spelplanen. Alternativt kan du använda ett hjälpbräde (ett
annat LifeBoard-objekt) där du lagrar den nya spelplanen. Även i detta fall måste du
avsluta med att kopiera hjälpbrädet till den riktiga spelplanen.
Testa programmet på åtminstone följande fyra exempel:
Exempel 1 (två konfigurationer erhålls omväxlande)
Exempel 2 (i generation 7 är alla döda)
Exempel 3 (antalet individer växer, i generation 15 erhålls en stabil konfiguration)
Prova också följande:
Mer att läsa om ”Conway’s Game of Life” och fler exempel att prova finns på nätet.
Använd t. ex. sökorden "Conway game of life".
Laboration 9 – arv
34
Laboration 9 – arv
Mål: Du ska lära dig mera om att skriva och använda klasser som är strukturerade med hjälp av
arv.
Förberedelseuppgifter
• Studera avsnitt 9.1-9.6 i läroboken.
• Läs avsnittet Bakgrund.
• Tänk igenom följande frågor och se till att du kan svara på dem:
1. Varför är det lämpligt att använda arv i problemet med de olika figurerna (superklassen Shape och subklasserna Square, Triangle samt Circle)?
2. Vad är en abstrakt metod?
3. I en konstruktor i en subklass måste man se till att en av superklassens konstruktorer
blir utförd. Varför? Hur åstadkommer man detta?
Bakgrund
I ritprogram kan man rita figurer som man sedan kan behandla på olika sätt. Man kan till
exempel ändra storlek på figurerna, flytta dem och ta bort dem.
Här beskrivs ett extremt enkelt ritprogram. Det finns bara tre slags figurer: kvadrater, liksidiga trianglar och cirklar. Det enda användaren kan göra är att flytta omkring figurerna i ritfönstret
genom att först klicka på en figur och sedan klicka på den nya positionen.
Ritfönstret har följande utseende:
I ritprogrammet beskrivs de gemensamma egenskaperna hos figurerna i en klass Shape. Denna
klass används som superklass på klasserna som beskriver specifika figurer (kvadrat, triangel och
cirkel).
public abstract class Shape {
protected int x;
protected int y;
/** Skapar en figur med läget x,y. */
protected Shape(int x, int y) {
this.x = x;
this.y = y;
}
Laboration 9 – arv
35
/** Ritar upp figuren i fönstret w. */
public abstract void draw(SimpleWindow w);
/** Raderar bilden av figuren, flyttar figuren till newX,newY
och ritar upp den på sin nya plats i fönstret w. */
public void moveToAndDraw(SimpleWindow w, int newX, int newY) {
java.awt.Color savedColor = w.getLineColor();
w.setLineColor(java.awt.Color.WHITE);
draw(w);
x = newX;
y = newY;
w.setLineColor(savedColor);
draw(w);
}
/** Undersöker om punkten xc,yc ligger "nära" figuren. */
public boolean near(int xc, int yc) {
return Math.abs(x - xc) < 10 && Math.abs(y - yc) < 10;
}
}
I programmet håller man reda på figurerna som man skapar genom att man lägger in dem i
en lista (ett objekt av klassen ShapeList). I följande program skapar man fem figurer, lägger in
dem i listan och ritar upp dem:
import se.lth.cs.window.SimpleWindow;
public class ShapeTest {
public static void main(String[] args) {
SimpleWindow w = new SimpleWindow(600, 600, "ShapeTest");
ShapeList shapes = new ShapeList();
shapes.insert(new Square(100, 300, 100));
shapes.insert(new Triangle(400, 200, 100));
shapes.insert(new Circle(400, 400, 50));
shapes.insert(new Square(450, 450, 50));
shapes.insert(new Square(200, 200, 35));
shapes.draw(w);
}
}
Parametrarna till konstruktorerna är figurens läge (x och y) och storlek (sidlängd eller radie).
Klassen ShapeList har följande specifikation:
/** Skapar en tom lista. */
ShapeList();
/** Lägger in figuren s i listan. */
void insert(Shape s);
/** Ritar upp figurerna i listan i fönstret w. */
void draw(SimpleWindow w);
/** Tar reda på en figur som ligger nära punkten xc,yc; ger null om
ingen sådan figur finns i listan. */
Shape findHit(int xc, int yc):
Operationen findHit används för att ta reda på vilken figur som användaren pekat och klickat
på. Detta hanteras av klassen CommandDispatcher, som ansvarar för programmets kommunika-
Laboration 9 – arv
36
tion med användaren. Klassen har följande uppbyggnad:
import se.lth.cs.window.SimpleWindow;
public class CommandDispatcher {
private SimpleWindow w;
private ShapeList shapes;
public CommandDispatcher(SimpleWindow w, ShapeList shapes) {
this.w = w;
this.shapes = shapes;
}
public void mainLoop() {
while (true) {
// användaren klickar på en figur
// användaren klickar på en ny position
// figuren flyttas till den nya positionen
}
}
}
Datorarbete
Råd: i nedanstående uppgifter är det lämpligt att börja med uppgift 1 till 4 men bara hantera kvadrater, så att man ser att allt fungerar. Komplettera sedan programmet med cirklar och
trianglar.
1.
Öppna projektet lab9. Där finns den färdiga klassen klassen Shape i filen Shape.java. Skriv
tre subklasser till Shape: Square, Triangle och Circle. Lägg klasserna i separata filer i
projektet lab9 (Square.java, Triangle.java, Circle.java). I subklasserna måste du definiera
vad som avses med ”läget” hos en figur. Koordinaterna x och y kan för en kvadrat ange
övre vänstra hörnet, för en triangel nedre vänstra hörnet, för en cirkel medelpunkten. Man
ska kunna bestämma figurens storlek med en parameter till konstruktorn.
När man ska rita en cirkel är det enklast att tänka sig cirkeln som en regelbunden
månghörning med många hörn. I lösningen till en av övningsuppgifterna i kapitel 9 i
läroboken finns en metod som ritar en cirkel.
2.
Skapa och implementera klassen ShapeList med hjälp av en ArrayList<Shape>.
3.
Klassen ShapeTest finns i filen ShapeTest.java. Tag bort kommentartecknen i main-metoden
och testkör programmet.
4.
Skapa och implementera klassen CommandDispatcher (enligt ovan). Modifiera också mainmetoden i ShapeTest så att ett CommandDispatcher-objekt skapas och operationen mainLoop
utförs. Testkör det nya programmet.
5.
(Frivillig uppgift.) Ändra programmet så att man inte behöver använda insert-satser i
main-metoden för att lägga in figurer i listan. I stället ska uppgifter om figurerna som
ska skapas läsas från en fil. I projektkatalogen finns en fil shapedata.txt som specificerar
samma figurer som i det tidigare exemplet.