Föreläsning 8 SLUMPTAL, SIMULERING + INTRODUKTION TILL VEKTORER
Från laboration 3 till 4 I laboration 3 har du implementerat klasser implementerat metoder i klasserna I laboration 4 kommer du att implementera en klass, och välja attribut själv använda slumptal implementera en algoritm för ett enkelt gissningsspel Denna vecka: även läsperiodens sista övning (5) introduktion till vektorer Gå gärna på fler övningstillfällen!
Slumptal och simulering SE BILDERNA FRÅN FÖRELÄSNING 7
Slumptal klassen Random Standardklassen java.util.random (ett urval av metoder): /** En slumptalsgenerator med slumptalsfrö seed. */ Random(long seed); /** En slumptalsgenerator med slumpmässigt frö. */ Random(); /** Slumpmässigt heltal i intervallet [0,n). */ int nextint(int n); /** Slumpmässigt reellt tal i intervall [0,1.0). */ double nextdouble(); http://docs.oracle.com/javase/8/docs/api/java/util/random.html
Metoden nextint Observera att ett anrop av nextint(6) ger ett heltal mellan 0 och 5. För att få ett slumptal mellan 1 och 6 får vi göra så här: Random rand = new Random(); int randnbr = rand.nextint(6) + 1;
Exempel med slumptal singla slant Random rand = new Random(); if (rand.nextdouble() < 0.5) { System.out.println("krona"); else { System.out.println("klave");
Övning slumptal tippa 1, X eller 2 Sannolikhet för 1 ska vara 55%, X ska vara 15%, 2 ska vara 30%. Random rand = new Random(); double nbr = rand.nextdouble(); String res; if (nbr < 0.55) { res = "1 ; Fyll i resten själva
Klassen Die public class Die { private static Random rand = new Random(); private int pips; // antal prickar som visas /** Skapar en tärning. */ public Die() { roll(); // så att pips får ett värde 1..6 /** Kastar tärningen. */ public void roll() { pips = 1 + rand.nextint(6); /** Tar reda på resultatet av det senaste kastet. */ public int getresult() { return pips;
Klassen Die kommentarer Slumptalsgeneratorn rand är ett statiskt attribut. Det betyder att rand hör till själva klassen Die och inte till något enskilt tärningsobjekt. Alla tärningsobjekt delar på samma slumptalsgenerator. Man får då en bättre fördelning av slumptalen jämfört med om varje tärning hade sin egen slumptalsföljd. Ett anrop av nextint(6) ger ett heltal mellan 0 och 5. För att få ett slumptal mellan 1 och 6 får vi göra så här: int randnbr = rand.nextint(6) + 1; För att tärningen ska få ett vettigt startvärde anropas metoden roll inuti konstruktorn. Ett annat (sämre) alternativ hade varit att tilldela attributet pips värdet 1 (t.ex.).
Anropa metoder på objektet självt För att tärningen ska få ett vettigt startvärde anropas metoden roll inuti konstruktorn: /** Skapar en tärning. */ public Die() { roll(); Normalt anger man med punktnotation vilket objekt en metod ska utföras på. Det behövs inte i det här fallet. Metoden roll är deklarerad i den här klassen och utförs på det aktuella objektet. Satsen roll() är här ekvivalent med this.roll().
Tärningsspel kasta tills tärningarna visar lika public static int rolluntilequal() { Die d1 = new Die(); Die d2 = new Die(); d1.roll(); d2.roll(); int turns = 1; while (d1.getresult()!= d2.getresult()) { d1.roll(); d2.roll(); turns ++; return turns;
Statiska attribut och metoder Statiska attribut finns bara i en upplaga för varje klass. Man kommer åt en statisk storhet med Klassnamn.namn, inte med referens.namn. Man skapar alltså inget objekt, utan använder klassen direkt. Exempel: double x = Math.pow(10, 4); double area = Math.PI * 20 * 20; Inuti klassen Math ser det ut så här: public class Math { public static final double PI = 3.14159265358979323846; public static double sin(double x) { // beräkning av sinus för x...
Tärningsspelet, kommentarer Vi utgår här från att tärningarna alltid måste kastas (med roll) innan deras värden kan användas (med getresult). Först måste vi alltså kasta tärningarna en gång, för att få två värden att starta med. Därefter upprepas samma sak direkt igen, inuti while-loopen. Eftersom vi vet att vi måste kasta tärningen minst en gång i vilket fall som helst, är do-while-loopen ett bra alternativ.
Samma tärningsspel, men med do-while public static int rolluntilequal() { Die d1 = new Die(); Die d2 = new Die(); int turns = 0; do { d1.roll(); d2.roll(); turns ++; while (d1.getresult()!= d2.getresult()); return turns; I do-while-satsen körs alltid kodblocket mellan { minst en gång!
Programexempel: tärningsspelet hundra Varje spelare slår tärningen ett antal gånger, tills hen antingen uppnår 100 poäng eller slår en etta. Om tärningen visar en etta nollställs spelarens poäng och det är nästa spelares tur att spela. Om tärningen visar något annat än en etta adderas tärningens poäng till spelarens. Spelarna turas om att försöka tills någon lyckas uppnå 100 poäng. Skriv ett program som genomför en omgång av detta spel, där en spelare försöker uppnå 100 poäng enligt ovan.
Spelet hundra public static int game() { Die die = new Die(); int sum = 0; do { die.roll(); if (die.getresult()!= 1) { sum = sum + die.getresult(); while (sum < 100 && die.getresult()!= 1); if (die.getresult() == 1) { sum = 0; return sum; Metoden returnerar antingen ett värde >= 100 eller 0. Genom att använda do-while behöver vi bara ha med die.roll() en gång. Men vi måste kolla efter värdet 1 flera gånger! Hur gör vi detta enklare?
break Nyckelordet break kan användas i loopar. break bryter loopen direkt. Exekveringen fortsätter efter loopen. Observera att break alltid bara bryter den närmaste loopen. Om vi har flera loopar inuti varandra är det bara den "innersta" loopen i förhållande till break som bryts. Man kan också avbryta med return. Men då avbryts hela metoden som man är inuti (oavsett loopar eller vad den innehåller i övrigt)
Spelet hundra, med break-sats public static int game() { Die die = new Die(); int sum = 0; do { die.roll(); if (die.getresult() == 1) { sum = 0; break; sum = sum + die.getresult(); while (sum < 100); return sum; Med break avbryts do-whileloopen direkt, och vi slipper undersöka villkoret fler gånger.
Spelet hundra, med extra return-sats public static int game() { Die die = new Die(); int sum = 0; do { die.roll(); if (die.getresult() == 1) { return 0; sum = sum + die.getresult(); while (sum < 100); return sum; Med return 0 avbryts inte bara do-while-loopen, utan hela metoden.
Större exempel: simulering av spelet hundra Vad är sannolikheten att vinna en omgång i spelet? (Dvs. vad är sannolikheten att man når 100 poäng utan att slå en enda etta?) (Klurigt matematiskt-statistiskt problem.)
Vektorer (introduktion)
Exempel med vektor vad gör programmet? public class ReverseNumbers { public static void main(string[] args) { System.out.println("Skriv ett n-värde och " + "därefter n heltal:"); Scanner scan = new Scanner(System.in); int n = scan.nextint(); int[] v = new int[n]; for (int i = 0; i < v.length; i++) { v[i] = scan.nextint(); for (int i = v.length - 1; i >= 0; i--) { System.out.println(v[i]);
Deklarera vektorer (eng. arrays) elementens typ Markerar att det är en vektor och inte en vanlig int-variabel. int[] v; vektorns namn Vektorn finns inte ännu utan måste skapas. v är en referensvariabel som kan referera till en vektor med int- element. v
Skapa vektorer elementens typ vektorns namn antal element v = new int[5]; Antal element måste anges. Elementen får automatiskt startvärden. Ofta deklarerar och skapar man vektorn på samma gång: int[] v = new int[5]; v [0] 0 [1] 0 [2] 0 [3] 0 [4] 0
Att använda enskilda element vektorns namn v[0] = 42; index Ett vektorelement fungerar som en vanlig variabel. Index måste vara inom gränserna 0.. antal element-1
Ta reda på vektorns längd for (int i = 0; i < v.length; i++) { v[i] = scan.nextint(); Tänk på att elementen numreras från 0 och uppåt (till skillnad från i Matlab )
Vektorer är objekt v [0] 42 [1] 3 [2] 13 [3] 50 [4] 7 Vektorer är ett slags objekt i Java. v refererar till vektorn (vilket framgår av bilden ovan). Ofta ritar man en enklare bild av vektorn: v 0 1 2 3 4 42 3 13 50 7
Övning: referenstilldelning Komplettera bilden så att den visar minnessituationen efter det att följande rader exekverats: int[] a = new int[3]; a[0] = 7; a[1] = 8; a[2] = 9; int[] b = a; a [0] [1] [2]
Övning: kopiera en vektor Komplettera programkoden så att en ny vektor med samma innehåll som a skapas. int[] a = new int[3]; a[0] = 7; a[1] = 8; a[2] = 9; int[] b = a [0] [1] [2] 7 8 9 b [0] [1] [2] 7 8 9
Vektorer med objekt Vektorn vertices med plats för tre Point-referenser: Point[] vertices = new Point[3]; vertices [0] null [1] null [2] null Observera att vi inte har skapat några punktobjekt ännu, bara en vektor med plats för punkter. Varje vektorelement är en referensvariabel av typen Point.
Vektorer med objekt Point[] vertices = new Point[3]; vertices[0] = new Point(10,10); vertices[1] = new Point(50,10); vertices[2] = new Point(30,40); vertices 0 1 2 x 10 y 10 x 50 y 10 x 30 y 40
Exempel: hantera alla punkterna Vektorn vertices innehåller tre punkter, som utgör hörnen i en triangel. Flytta punkterna i vektorn: for (int i = 0; i < vertices.length; i++) { vertices[i].move(10, 20); Rita triangeln: SimpleWindow w = new SimpleWindow(600, 600, Triangle"); w.moveto(vertices[0].getx(), vertices[0].gety()); for (int i = 1; i < vertices.length; i++) { w.lineto(vertices[i].getx(), vertices[i].gety()); w.lineto(vertices[0].getx(), vertices[0].gety());
Vektor för att representera en polygon Antag att vi vill hantera polygoner med ett godtyckligt antal hörnpunkter. Då får vi gissa hur stor vektor vi behöver för punkterna: vertices 0 1 2 3 4 5 6 7 null null null null x 50 x 70 y 50 y 300 x 350 y 350 x 320 y 200 Det behövs också en variabel som håller reda på hur många punkter vi satt in i vektorn: n 4
Sätta in element i vektorn Vi sätter in en ny punkt efter de andra punkterna i polygonen: vertices[n] = new Point(200, 40); n++; 0 1 2 3 4 5 6 7 vertices null null null x 50 x 70 y 50 y 300 x 350 y 350 x 320 y 200 x 200 y 40 n 5
Ta bort element mitt i vektorn Antag att vi ska ta bort punkten på plats pos i vektorn vertices. Om ordningen mellan punkterna inte spelar någon roll kan vi göra så här: Täpp till hålet i vektorn genom att flytta sista elementet till plats pos. Uppdatera n eftersom antal punkter minskat med 1. vertices[pos] = vertices[n - 1]; vertices[n - 1] = null; n--;
Före borttagning av punkten med index 1 vertices 0 1 2 3 4 5 6 7 null null null x 50 x 70 y 50 y 300 x 350 y 350 x 320 y 200 x 200 y 40 n pos 5 1
Efter borttagning av punkten med index 1 vertices 0 1 2 3 4 5 6 7 null null null null x 50 x 70 y 50 y 300 x 350 y 350 x 320 y 200 x 200 y 40 n pos 4 1 5
Ta bort element mitt i vektorn, forts Eftersom punkterna i vektorn vertices representerar en polygon så spelar ordningen mellan punkterna roll. Vi gör så här istället: Täpp till hålet i vektorn genom att flytta alla element efter pos ett steg till vänster. Uppdatera n eftersom antal punkter minskat med 1. for (int i = pos; i < n - 1; i++) { vertices[i] = vertices[i + 1]; vertices[n - 1] = null; n--;
Före borttagning av punkten med index 1 vertices 0 1 2 3 4 5 6 7 null null null x 50 x 70 y 50 y 300 x 350 y 350 x 320 y 200 x 200 y 40 n pos 5 1
Efter borttagning av punkten med index 1 0 1 2 3 4 5 6 7 vertices null null null null x 50 y 50 x 350 y 350 x 320 y 200 x 200 y 40 n pos 4 1 5
Passar en vektor för detta? I exemplet på föregående bilder måste vi gissa hur stor vektor vi behöver. Vad händer om vi vill sätta in fler än 8 punkter? Vi behöver dessutom hålla reda på antal punkter vi satt in. För problem där antal element varierar är det enklare att använda den färdiga klassen ArrayList (behandlas senare i kursen). Ett ArrayList-objekt använder internt en vektor och har färdiga metoder för att sätta in element i listan, ta bort element etc.
Åter till exemplet public class ReverseNumbers { public static void main(string[] args) { System.out.println("Skriv ett n-värde och " + "därefter n heltal:"); Scanner scan = new Scanner(System.in); int n = scan.nextint(); int[] v = new int[n]; for (int i = 0; i < v.length; i++) { v[i] = scan.nextint(); for (int i = v.length - 1; i >= 0; i--) { System.out.println(v[i]);
Övning: vektor Skriv kod för att: Deklarera och skapa en vektor numbers, med plats för 10 stycken element av typen double. Tilldela alla element värdet 1.0. numbers [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
Åter till main-metoden public class Example { public static void main(string[] args) { System.out.println( Hej allesammans! ); Programmet är en klass Main-metoden är en metod som andra (men har en speciell uppgift) Main-metoden är statisk (precis som metoderna i Math) Main-metodens parameter är en vektor av strängar