Anvendelser I Leg og spil 1 Plan Leg

  • Slides: 59
Download presentation
Anvendelser I Leg og spil 1

Anvendelser I Leg og spil 1

Plan • Leg og spil Ordkvadrater Tomandsspil (Kryds-og-bolle) • Stakke og oversættere Check af

Plan • Leg og spil Ordkvadrater Tomandsspil (Kryds-og-bolle) • Stakke og oversættere Check af parentesstrukturer En simpel kalkulator Indlæsning og beregning af aritmetiske udtryk 2

Ordkvadrater Problem: Givet et kvadrat bestående af bogstaver samt en ordbog. Find alle de

Ordkvadrater Problem: Givet et kvadrat bestående af bogstaver samt en ordbog. Find alle de ord i kvadratet, der optræder i ordbogen. Ordene læses vandret, lodret eller diagonalt i enhver retning (i alt 8 retninger). Eksempler: tank, an, en, real, te, anke, nota, ral, ro, et, ark, kok 3

Løsningsalgoritmer Ineffektiv algoritme: for ethvert ord W i ordbogen for enhver række R for

Løsningsalgoritmer Ineffektiv algoritme: for ethvert ord W i ordbogen for enhver række R for enhver søjle C for enhver retning D afgør om W findes i række R, søjle C og retning D Antag R = C = 32 og W = 40, 000 Antal ordsammenligninger i indre løkke: 40, 000*R*C*8 = 327, 680, 000 4

Forbedret algoritme: for enhver række R for enhver søjle C for enhver retning D

Forbedret algoritme: for enhver række R for enhver søjle C for enhver retning D for enhver ordlængde L afgør om de L tegn i række R, søjle C og retning D findes som et ord i ordbogen Antal check i indre løkke (antag Lmax = 20): R*C*8*L = 32*32*8*20 = 163, 840 Hvis hvert opslag i ordbogen foretages med binær søgning, foretages maksimalt 163, 840 * ( log 240, 000 + 1) = 163, 840 * 16 = 2, 621, 440 ordsammenligninger. For eksemplet her er algoritmen blevet cirka 125 gange hurtigere. 5

Yderligere forbedret algoritme: for enhver række R for enhver søjle C for enhver retning

Yderligere forbedret algoritme: for enhver række R for enhver søjle C for enhver retning D for enhver ordlængde L afgør om de L tegn i række R, søjle C og retning D findes som et ord i ordbogen hvis de ikke udgør et præfiks for noget ord i ordbogen, så break; // ud af den inderste løkke Om de L tegn udgør et præfiks for et ord i ordbogen kan afgøres ved binær søgning. 6

Implementering i Java int solve. Puzzle() { int matches = 0; for (int r

Implementering i Java int solve. Puzzle() { int matches = 0; for (int r = 0; r < rows; r++) for (int c = 0; c < columns; c++) for (int rd = -1; rd <= 1; rd++ ) for (int cd = -1; cd <= 1; cd++) if (rd != 0 || cd != 0 ) matches += solve. Direction(r, c, rd, cd); return matches; } 7

int solve. Direction(int r, int c, int rd, int cd) { int num. Matches

int solve. Direction(int r, int c, int rd, int cd) { int num. Matches = 0; String chars = "" + the. Board[r][c]; for (int i = r + rd, j = c + cd; i >= 0 && j >= 0 && i < rows && j < columns; i += rd, j += cd) { chars += the. Board[i][j]; int index = prefix. Search(the. Words, chars); if (!the. Words[index]. starts. With(chars)) break; if (the. Words[index]. equals(chars)) { num. Matches++; System. out. println("Found " + chars + " at " + r + " " + c + " to " + i + " " + j ); } } return num. Matches; } 8

int prefix. Search(String[] a, String chars) { int low = 0; int high =

int prefix. Search(String[] a, String chars) { int low = 0; int high = a. length - 1; while (low < high) { int mid = (low + high) / 2; if (a[mid]. compare. To(chars) < 0) low = mid + 1; else high = mid; } return low; } eller int prefix. Search(String[] a, String chars) { int idx = Arrays. binary. Search(chars); return idx >= 0 ? idx : -(idx + 1); } 9

Spil 10

Spil 10

Kryds-og-bolle (Engelsk: Tic-tac-toe) . . Bolle vinder . . . Uafgjort . . .

Kryds-og-bolle (Engelsk: Tic-tac-toe) . . Bolle vinder . . . Uafgjort . . . Kryds vinder 11

public class Tic. Tac. Toe { public static final int HUMAN static final int

public class Tic. Tac. Toe { public static final int HUMAN static final int COMPUTER = 1; int EMPTY = 2; = 0; public static final int HUMAN_WIN static final int DRAW = 1; int UNCLEAR = 2; COMPUTER_WIN = 3; = 0; public static final public static final int public Tic. Tac. Toe() { clear. Board( ); } public Best choose. Move(int side) {. . . } public boolean play. Move(int side, int row, int column) {. . . } public void clear. Board() {. . . } public boolean board. Is. Full() {. . . } boolean is. AWin(int side) {. . . } private int[][] board = new int[3][3]; private void place(int row, int column, int piece) {. . . } private boolean square. Is. Empty(int row, int column) {. . . } private int position. Value() {. . . } } 12

class Best { int row, column; int val; public Best(int v, int r, int

class Best { int row, column; int val; public Best(int v, int r, int c) { val = v; row = r; column = c; } public Best(int v) { this(v, 0, 0); } } 13

Minimax strategien 1. Hvis stillingen er en slutstilling, så returner dens værdi. 2. Ellers,

Minimax strategien 1. Hvis stillingen er en slutstilling, så returner dens værdi. 2. Ellers, hvis det er computeren (Max) til at trække, så returner den maksimale værdi af alle de stillinger, der fremkommer ved at udføre et træk. Værdierne beregnes rekursivt. 3. Ellers, hvis det er mennesket (Min) til at trække, så returner den minimale værdi af alle de stillinger, der fremkommer ved at udføre et træk. Værdierne beregnes rekursivt. 14

public Best choose. Move(int side) { int best. Row = 0, best. Column =

public Best choose. Move(int side) { int best. Row = 0, best. Column = 0; int value, opp; if ((value = position. Value()) != UNCLEAR) return new Best(value); if (side == COMPUTER) { opp = HUMAN; value = HUMAN_WIN; } else { opp = COMPUTER; value = COMPUTER_WIN; } for (int row = 0; row < 3; row++) for (int column = 0; column < 3; column++) if (square. Is. Empty(row, column)) { place(row, column, side); Best reply = choose. Move(opp); place(row, column, EMPTY); if (side == COMPUTER && reply. val > value || side == HUMAN && reply. val < value) { value = reply. val; best. Row = row; best. Column = column; } } return new Best(value, best. Row, best. Column); } 15

Minimax strategien udfører megen overflødig søgning C 1 C 2 C 3 maksimer uafgjort

Minimax strategien udfører megen overflødig søgning C 1 C 2 C 3 maksimer uafgjort H 2 A H 2 B uafgjort H 2 C H 2 D minimer Beskæring: C 2 kan aldrig blive bedre end “uafgjort”. 16

Alpha-beta-beskæring Trækket H 2 A kaldes en gendrivelse af trækket C 2. Der er

Alpha-beta-beskæring Trækket H 2 A kaldes en gendrivelse af trækket C 2. Der er et træk (C 1), der er lige så godt - eller bedre. alpha: Den hidtil bedste værdi opnået af computeren. beta: Den hidtil bedste værdi opnået af mennesket. Beskæring sker (1) hvis mennesket opnår en værdi, der er mindre end eller lig med alpha. (2) hvis computeren opnår en værdi, der er større end eller lig med beta. 17

public Best choose. Move(int side, int alpha, int beta) { int best. Row =

public Best choose. Move(int side, int alpha, int beta) { int best. Row = 0, best. Column = 0; int value, opp; if ((value = position. Value()) != UNCLEAR) return new Best(value); if (side == COMPUTER) { opp = HUMAN; value = alpha; } else { opp = COMPUTER; value = beta; } Outer: for (int row = 0; row < 3; row++) for (int column = 0; column < 3; column++) if (square. Is. Empty(row, column)) { place(row, column, side); Best reply = choose. Move(opp, alpha, beta); place(row, column, EMPTY); if (side == COMPUTER && reply. val > value || side == HUMAN && reply. val < value) { value = reply. val; if (side == COMPUTER) alpha = value; else beta = value; best. Row = row; best. Column = column; if (alpha >= beta) break Outer; } } return new Best(value, best. Row, best. Column); } 18

Driver-rutine Best choose. Move(int side) { return choose. Move(side, HUMAN_WIN, COMPUTER_WIN); } 19

Driver-rutine Best choose. Move(int side) { return choose. Move(side, HUMAN_WIN, COMPUTER_WIN); } 19

Effekten af alpha-beta-beskæring Beskæringen er størst, når algoritmen i enhver stilling altid undersøger det

Effekten af alpha-beta-beskæring Beskæringen er størst, når algoritmen i enhver stilling altid undersøger det bedste træk først. I praksis er antallet af knuder, der bliver undersøgt ved brug af alpha-beta-beskæring O( ), hvor N er det antal knuder, der ville blive undersøgt uden brug af alpha-beta-beskæring. På den samme tid kan der søges dobbelt så dybt. 20

Beskæring ved hjælp af tabel Undgå genberegninger ved at gemme evaluerede stillinger i en

Beskæring ved hjælp af tabel Undgå genberegninger ved at gemme evaluerede stillinger i en tabel. To søgninger resulterer i samme stilling. Benyt en transpositionstabel i form af en hashtabel (Hash. Map). 21

class Position { int[][] board; int value; Position(int the. Board[][]) { board = new

class Position { int[][] board; int value; Position(int the. Board[][]) { board = new int[3][3]; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) board[i][j] = the. Board[i][j]; } public boolean equals(Object rhs) { for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (board[i][j] != ((Position) rhs). board[i][j]) return false; return true; } public int hash. Code() { int hash. Val = 0; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) hash. Val = hash. Val * 4 + board[i][j]; return hash. Val; } } 22

public Best choose. Move(int side, int alpha, int beta, int depth) { int best.

public Best choose. Move(int side, int alpha, int beta, int depth) { int best. Row = 0, best. Column = 0; int value, opp; Position this. Position = new Position(board); if ((value = position. Value()) != UNCLEAR) return new Best(value); if (depth == 0) transpositions. clear(); else if (depth >= 3 && depth <= 5) { Integer lookup. Val = (Integer) transpositions. get(this. Position); if (lookup. Val != null) return new Best(lookup. Val. int. Value()); }. . . choose. Move(opp, alpha, beta, depth + 1); . . . if (depth <= 5) transpositions. put(this. Position, new Integer(value)); return new Best(value, best. Row, best. Column); } 23

Effekten af beskæringerne på kryds-og-bolle Med alpha-beta reduceres antallet af undersøgte stillinger i udgangsstillingen

Effekten af beskæringerne på kryds-og-bolle Med alpha-beta reduceres antallet af undersøgte stillinger i udgangsstillingen fra cirka 500, 000 til cirka 18, 000. Med en transpositionstabel reduceres antallet yderligere til cirka 9, 000. 24

En generel pakke til tomandsspil med perfekt information package two. Person. Game; public abstract

En generel pakke til tomandsspil med perfekt information package two. Person. Game; public abstract class Position { public boolean max. To. Move; public abstract Array. List successors(); public abstract int value(); public boolean unclear() { return false; } public int alpha_beta(int alpha, int beta, int max. Level); public Position best. Successor() { return best. Successor; } private Position best. Successor; } 25

public int alpha_beta(int alpha, int beta, int max. Level) { Array. List successors; if

public int alpha_beta(int alpha, int beta, int max. Level) { Array. List successors; if ((max. Level <= 0 && !unclear()) || (successors = successors()). is. Empty()) return value(); for (int i = 0; alpha < beta && i < successors. size(); i++) { Position successor = (Position) successors. get(i); int value = successor. alpha_beta(alpha, beta, max. Level - 1); if (max. To. Move && value > alpha) { alpha = value; best. Successor = successor; } else if (!max. To. Move && value < beta) { beta = value; best. Successor = successor; } } return max. To. Move ? alpha : beta; } 26

Reduktion af kode (negamax) public int alpha_beta(int alpha, int beta, int max. Level) {

Reduktion af kode (negamax) public int alpha_beta(int alpha, int beta, int max. Level) { Array. List successors; if ((max. Level <= 0 && !unclear()) || (successors = successors()). is. Empty()) return (max. To. Move ? 1 : -1) * value(); for (int i = 0; alpha < beta && i < successors. size(); i++) { Position successor = (Position) successors. get(i); int value = -successor. alpha_beta(-beta, -alpha, max. Level-1); if (value > alpha) { alpha = value; best. Successor = successor; } } return alpha; } 27

import two. Person. Game. *; public class Tic. Tac. Toe. Position extends Position {

import two. Person. Game. *; public class Tic. Tac. Toe. Position extends Position { public Tic. Tac. Toe. Position(int row, int column, Tic. Tac. Toe. Position predecessor) {. . . } public Array. List successors() { Array. List successors = new Array. List(); if (!is. Terminal()) for (int row = 0; row < 3; row++) for (int column = 0; column < 3; column++) if (board[row][column] == '. ') successors. add( new Tic. Tac. Toe. Position(row, column, this)); return successors; } public int value() { return is. AWin('O') ? 1 : is. AWin('X') ? -1 : 0; } public boolean unclear() { return value() == 0; } public boolean board. Is. Full() {. . . } public boolean is. AWin(char symbol) {. . . } public boolean is. Terminal() {. . . } public void print() {. . . } } int row, column; char[][] board = new char[3][3]; 28

Stakke og oversættere 29

Stakke og oversættere 29

Check af parentesstrukturer Problem: Givet en streng indeholdende parenteser. Afgør om parenteserne ”balancerer”, d.

Check af parentesstrukturer Problem: Givet en streng indeholdende parenteser. Afgør om parenteserne ”balancerer”, d. v. s. om der til hver venstreparentes svarer en højreparentes, og der til hver højreparentes svarer en venstreparentes. For eksempel balancerer parenteserne i “[()]”, ikke i “[(])”. men I det følgende forsimples problemet ved at antage, at strengen udelukkende indeholder parenteser. 30

Kun én type parenteser Hvis der kun er én type parenteser, f. eks. ’(’

Kun én type parenteser Hvis der kun er én type parenteser, f. eks. ’(’ og ’)’, er løsningen simpel. Vi kan kontrollere balancen med en tæller. boolean balanced(String s) { int balance = 0; for (int i = 0; i < s. length(); i++) { char c = s. char. At(i); if (c == '(') balanced++; else if (c == ')') { balance--; if (balance < 0) return false; } } return balance == 0; } 31

Flere typer af parenteser Hvis derimod er flere typer af parenteser, kan problemet ikke

Flere typer af parenteser Hvis derimod er flere typer af parenteser, kan problemet ikke løses ved tællere. Men vi kan let kontrollere balancen med en stak. Algoritme: 1. Lav en tom stak. 2. Sålænge strengen ikke er læst, så læs det næste tegn. a. Hvis tegnet er en startparentes, så læg det på stakken. b. Hvis tegnet er en slutparentes, og stakken er tom, så giv en fejlmeddelelse. c. Ellers, afstak det øverste tegn. Hvis dette ikke er en startparentes svarende til den læste slutparentes, så giv en fejlmeddelelse. 3. Hvis stakken ikke er tom, så giv en fejlmeddelelse. 32

Eksempel parenteser: (, ), [, ], { og } Streng s = "([]}" (

Eksempel parenteser: (, ), [, ], { og } Streng s = "([]}" ( [ ( ( ( [ ] } Fejl! 33

class Char. Stack { void push(char ch) { stack[++top] = ch; } char pop()

class Char. Stack { void push(char ch) { stack[++top] = ch; } char pop() { return stack[top--]; } boolean is. Empty() { return top == -1; } char[] stack = new char[100]; int top = -1; } 34

Javakode boolean balanced(String s) { Char. Stack stack = new Char. Stack(); for (int

Javakode boolean balanced(String s) { Char. Stack stack = new Char. Stack(); for (int i = 0; i < s. length(); i++) { char c = s. char. At(i); if (c == '(' || c == '[' || c == '{') stack. push(c); else if (stack. is. Empty() || (c == ')' && stack. pop() != '(')) || (c == ']' && stack. pop() != '[')) || (c == '}' && stack. pop() != '{')) return false; } } return stack. is. Empty(); } 35

Indlæsning og beregning af aritmetiske udtryk Beregn udtrykket 1*2+3*4 Værdi = (1 * 2)

Indlæsning og beregning af aritmetiske udtryk Beregn udtrykket 1*2+3*4 Værdi = (1 * 2) + (3 * 4) = 2 + 12 = 14. Simpel beregning fra venstre mod højre kan ikke benyttes. Vi må tage højde for, at multiplikation har hørere præcedens end addition (* binder stærkere end +). Det er nødvendigt at gemme mellemresultater. 36

Associativitet Hvis to operatorer har samme præcedens, afgør deres associativitet beregningsrækkefølgen. Udtrykket 4 -

Associativitet Hvis to operatorer har samme præcedens, afgør deres associativitet beregningsrækkefølgen. Udtrykket 4 - 3 - 2 beregnes som (4 - 3) - 2, minus associerer fra venstre mod højre. fordi Udtrykket 4 ^ 3 ^ 2, hvor ^ betegner potensopløftning, beregnes som 4 ^ (3 ^ 2), fordi ^ associerer fra højre mod venstre. 37

Parenteser Beregningsrækkefølgen kan klarlægges ved hjælp af parenteser. Eksempel: 1 -2 -4*5^3*6/7^2 ^2 beregnes

Parenteser Beregningsrækkefølgen kan klarlægges ved hjælp af parenteser. Eksempel: 1 -2 -4*5^3*6/7^2 ^2 beregnes som (1 -2)-(((4*(5^3))*6)/(7^(2^2))) Parenteserne hjælper, men det er uklart, hvorledes beregningerne kan automatiseres. 38

Postfix-notation Den normale notation for aritmetiske udtryk kaldes for infixnotation (operatorerne står imellem sine

Postfix-notation Den normale notation for aritmetiske udtryk kaldes for infixnotation (operatorerne står imellem sine operander, f. eks. 3 + 4). Beregningerne kan forenkles ved omskrivning til postfixnotation (operatorerne står efter sine operander, f. eks. 3 4 +). 1 -2 -4^5*3*6/7^2 ^2 (infix) omskrives til 12 -45^3*6*722^^/- (postfix) Postfix-notation er parentesfri. 39

Beregning af postfix-udtryk ved hjælp af en stak 12 -45^3*6*722^^/- 1 1 6 3072

Beregning af postfix-udtryk ved hjælp af en stak 12 -45^3*6*722^^/- 1 1 6 3072 -1 6 18432 -1 * 2 1 2 7 18432 -1 7 (postfix) -1 - 4 -1 4 5 4 -1 5 2 7 18432 -1 2 2 2 7 18432 -1 2 4 7 18432 -1 ^ 1024 -1 ^ 3 1024 -1 3 3072 -1 * 2401 18432 -1 ^ 7 -1 / -8 - 40

class Calculator { static int value. Of(String str) { Int. Stack s = new

class Calculator { static int value. Of(String str) { Int. Stack s = new Int. Stack(); for (int i = 0; i < str. length(); i++) { char c = str. char. At(i); if (Character. is. Digit(c)) s. push(Character. get. Numeric. Value(c)); // only one digit else if (!Character. is. Whitespace(c)) { int rhs = s. pop(), lhs = s. pop(); switch(c) { case '+': s. push(lhs + rhs); break; case '-': s. push(lhs - rhs); break; case '*': s. push(lhs * rhs); break; case '/': s. push(lhs / rhs); break; case '^': s. push((int) Math. pow(lhs, rhs)); break; } } } return s. pop(); } } 41

Omformning fra infix til postfix ved hjælp af en stak (Dijkstras vigesporsalgoritme) Infix-streng operander

Omformning fra infix til postfix ved hjælp af en stak (Dijkstras vigesporsalgoritme) Infix-streng operander Postfix-streng operatorer Operatorstak 42

Omformning fra infix til postfix 1 -2 -4^5*3*6/7^2 ^2 1 12 -45^3* 12 12

Omformning fra infix til postfix 1 -2 -4^5*3*6/7^2 ^2 1 12 -45^3* 12 12 -4 12 - (infix) 12 -4 - - ^ - - 2 - 4 ^ 12 -45^ ^ - * - 5 * 12 -45^3*6*722^^/- 12 -45^3*6*7 12 -45^3*6*72 ^ ^ * - * - / - / - / - 3 * 6 / 7 ^ 2 43

Syntaksanalyse Mål: Et program til indlæsning og beregning af aritmetiske udtryk. Løs et lettere

Syntaksanalyse Mål: Et program til indlæsning og beregning af aritmetiske udtryk. Løs et lettere problem først: Læs en streng og undersøg, om den udgør et lovligt aritmetisk udtryk. 44

Grammatik for aritmetiske udtryk Benyt en grammatik til at beskrive aritmetiske udtryk: <expression> :

Grammatik for aritmetiske udtryk Benyt en grammatik til at beskrive aritmetiske udtryk: <expression> : : = <term> | <term> + <expression> | <term> - <expression> <term> : : = <factor> | <factor> * <term> | <factor> / <term> <factor> : : = <number> | (<expression>) Grammatikken er beskrevet ved produktionsregler og består af (1) nonterminale symboler: expression, term, factor og number. (2) terminale symboler: +, -, *, /, (, ) og cifre. (3) metasymboler: : : =, <, >, og |. 45

Syntaksanalyse En streng er et aritmetisk udtryk, hvis det ved hjælp af produktionsreglerne er

Syntaksanalyse En streng er et aritmetisk udtryk, hvis det ved hjælp af produktionsreglerne er muligt at udlede strengen ud fra expression, dvs. ud fra expression i en række skridt nå frem til strengen ved i hvert skridt at erstatte et nonterminal-symbol med et af alternativerne på højresiden af en produktion for dette symbol. Syntakstræ for (3*5+4/2)-1 expression term - expression factor term ( expression ) factor term + expression number factor * factor term number factor / factor 3 5 1 number 4 2 46

Syntaksdiagrammer term: expression: term factor + * - / factor: number ( expression )

Syntaksdiagrammer term: expression: term factor + * - / factor: number ( expression ) 47

Syntaksanalyse ved rekursiv nedstigning (top-down parsing) Et rekursivt Java-program til syntaksanalyse kan konstrueres direkte

Syntaksanalyse ved rekursiv nedstigning (top-down parsing) Et rekursivt Java-program til syntaksanalyse kan konstrueres direkte ud fra syntaksdiagrammerne. void expression() { term(); while (token == PLUS || token == MINUS) { get. Token(); term(); } } static final int PLUS = 1, MINUS = 2, MULT = 3, DIV = 4, LPAR = 5, RPAR = 6, NUMBER = 7, EOS = 8; int token; 48

void term() { factor(); while (token == MULT || token == DIV) get. Token();

void term() { factor(); while (token == MULT || token == DIV) get. Token(); factor(); } } { void factor() { if (token == NUMBER) ; else if (token == LPAR) { get. Token(); expression(); if (token != RPAR) error("missing right paranthesis"); } else error("illegal factor: " + token); get. Token(); } 49

String. Tokenizer str; void parse(String s) { str = new String. Tokenizer(s, "+-*/() ",

String. Tokenizer str; void parse(String s) { str = new String. Tokenizer(s, "+-*/() ", true); get. Token(); expression(); } Eksempel på kald: parse("(3*5+4/2)-1"); 50

void get. Token() { String s; try { s = str. next. Token(); }

void get. Token() { String s; try { s = str. next. Token(); } catch(No. Such. Element. Exception e) { token = EOS; return; } if (s. equals(" ")) get. Token(); else if (s. equals("+")) token = PLUS; else if (s. equals("-")) token = MINUS; else if (s. equals("*")) token = MULT; else if (s. equals("/")) token = DIV; else if (s. equals("(")) token = LPAR; else if (s. equals(")")) token = RPAR; else { try { Double. parse. Double(s); token = NUMBER; } catch(Number. Format. Exception e) { error("number expected"); } } } 51

Beregning af aritmetiske udtryk Beregning kan opnås ved få simple ændringer af syntaksanalyseprogrammet. Analysemetoderne

Beregning af aritmetiske udtryk Beregning kan opnås ved få simple ændringer af syntaksanalyseprogrammet. Analysemetoderne skal returnere med deres tilhørende værdi (i stedet for void). double value. Of(String s) { str = new String. Tokenizer(s, "+-*/() ", true); get. Token(); return expression(); } Eksempel på kald: double r = value. Of("(3*5+4/2)-1"); 52

double expression() { double v = term(); while (token == PLUS || token ==

double expression() { double v = term(); while (token == PLUS || token == MINUS) if (token == PLUS) { get. Token(); v += term(); } else { get. Token(); v -= term(); } return v; } double term() { double v = factor(); while (token == MULT || token == DIV) if (token == MULT) { get. Token(); v *= factor(); } else { get. Token(); v /= factor(); } return v; } 53

double factor() { double v; if (token == NUMBER) v = value; else if

double factor() { double v; if (token == NUMBER) v = value; else if (token == LPAR) { get. Token(); v = expression(); if (token != RPAR) error("missing right paranthesis"); } else error("illegal factor: " + token); get. Token(); return v; } 54

void get. Token() { String s; try { s = str. next. Token(); }

void get. Token() { String s; try { s = str. next. Token(); } catch(No. Such. Element. Exception e) { token = EOS; return; } if (s. equals(" ")) get. Token(); else if (s. equals("+")) token = PLUS; else if (s. equals("-")) token = MINUS; else if (s. equals("*")) token = MULT; else if (s. equals("/")) token = DIV; else if (s. equals("(")) token = LPAR; else if (s. equals(")")) token = RPAR; else { try{ value = Double. parse. Double(s); token = NUMBER; } catch(Number. Format. Exception e) { error("number expected"); } } } 55

Ugeseddel 7 30. oktober - 6. november • Læs kapitel 12 og 13 •

Ugeseddel 7 30. oktober - 6. november • Læs kapitel 12 og 13 • Løs følgende opgaver Opgave 23: 10. 2 (1 point) Opgave 24: 11. 2 (1 point) Opgave 25: 11. 3 (2 point) Opgave 26: Se de næste sider (3 point, ikke-obligatorisk) Afleveringsfrist: tirsdag den 13. november 56

fortsættes 57

fortsættes 57

fortsættes 58

fortsættes 58

59

59