Download presentation
Presentation is loading. Please wait.
Published byKenneth Jeffery Montgomery Modified over 9 years ago
1
Implementing the 8-puzzle Design (no corresponding text chapter)
2
Possible Implementation of StateInfo Class Suppose your StateInfo class for the 8-puzzle looks like: class StateInfo { private:... public:... State blankUp(); State blankDown(); State blankLeft(); State blankRight();... }
3
solve() Pseudocode Revisited void solve() current = get start state from problem final = get final state from problem alist = get action list from problem count = 0 while current is not final do display current action = get action from user if action is valid then new = apply action to current current = new increment count else issue message display current and count congratulate Recall the pseudocode for SolverInfo::solve() :
4
Possible Implementation of solve() Suppose the pseudocode in bold were implemented as follows:... String actionName = promptActionName(); if (strcmp(actionName,"up") == 0) newState = currentState->blankUp(); else if (strcmp(actionName,"down") == 0) newState = currentState->blankDown(); else if (strcmp(actionName,"left") == 0) newState = currentState->blankLeft(); else if (strcmp(actionName,"right") == 0) newState = currentState->blankRight(); else cout << "action " << actionName << " is not recognized." << endl;...
5
Problems With The Implementation Recall a design goal for this program: Only the ProblemInfo and StateInfo classes should know any details about the problem domain The SolverInfo class should be applicable to domains other than the 8-puzzle Does the solve() method, as implemented, meet this goal? No. We therefore introduce the classes Action and ActionList to act as a layer of abstraction between the solver and the domain.
6
A Better Approach Wrap each of the methods StateInfo::blankUp(), StateInfo::blankDown(), etc., in a new Action object. Put each of these Action s onto an ActionList object to which the solver has access. Provide a method in the ActionList class that will search for and return the Action corresponding to the string entered by the user. Provide a method in the Action class that will execute its tile-moving operation on a given State.
7
A Better Implementation of solve()... String actionName = promptActionName(); Action action = actionList->findAction(actionName); if (action == NULL) { cout << "action " << actionName << " is not recognized." << endl; } else { State newState = action->execute(currentState);... }... Now there are no references to any details that indicate the domain is the 8-puzzle.
8
Recall the ActionInfo Class Data: Name (up, down, left, right) Operation to perform the action--What, an operation as data?? Operations: Create a new action Execute the action operation ...
9
Operations As Data in C++ Suppose we want a program calc to behave like this: 64% calc add 25 2 The result is 27 65% calc sub 25 2 The result is 23 66% calc mult 25 2 The result is 50 67% calc div 25 2 The result is 12 68%
10
Strategy Develop a class called CalcInfo that has: Two integer values as data fields A constructor with two integer arguments A method calculate with a string argument, either ``add'', ``sub'', ``mult'', or ``div''. This method does the right calculation on its operands based on its argument. Get the operation and operands from the command line. Create a CalcInfo object with the operands. Invoke the calculate method on the object with the operation as argument.
11
Main Program for calc int main(Integer argc, StringArray operands) { String oper = operands[1]; Integer x = atoi(operands[2]); Integer y = atoi(operands[3]); Calc c = new CalcInfo(x, y); Integer result = c->calculate(oper); cout << "The result is " << result << endl << endl; }
12
One Implementation of CalcInfo class CalcInfo { private: Integer operand1; Integer operand2; public: CalcInfo(Integer x, Integer y); Integer calculate(String operation); }; CalcInfo::CalcInfo(Integer x, Integer y) { operand1 = x; operand2 = y; }...
13
One Implementation of CalcInfo (cont'd)... Integer CalcInfo::calculate(String operation) { if (strcmp(operation, "add") == 0) return (operand1 + operand2); else if (strcmp(operation, "sub") == 0) return (operand1 - operand2); else if (strcmp(operation, "mult") == 0) return (operand1 * operand2); else if (strcmp(operation, "div") == 0) return (operand1 / operand2); else return 0; }
14
CalcInfo Modification Suppose we want to remove the arithmetic details from CalcInfo, to be handled by another class: Integer CalcInfo::calculate(ArithFun fun) { <Apply fun to the operands and return the result> } This requires: Being able to treat functions as arguments Being able to return functions as function values
15
A New Class: ArithmeticInfo This class will contain the functions (methods) for doing arithmetic that will be passed to the CalcInfo::calculate method: class ArithmeticInfo { public: static Integer add (Integer a, Integer b); static Integer sub (Integer a, Integer b); static Integer mult (Integer a, Integer b); static Integer div (Integer a, Integer b); ArithFun getFun(String oper); };
16
Notes on Class ArithmeticInfo " The arithmetic methods are static because they are associated with the whole class and not class instances: A nonstatic method is called using the obj->method(...) syntax, but In this case there is no obj involved, because the method is passed to another object, where it is called as if it were a straight C function. The ArithmeticInfo::getFun(...) method determines the right static method to pass, given a string parameter. It is not static because we are going to ask an ArithmeticInfo object to invoke it.
17
ArithmeticInfo::getFun Method ArithFun ArithmeticInfo::getFun(String oper) { if (strcmp(oper,"add") == 0) return add; else if (strcmp(oper,"sub") == 0) return sub; else if (strcmp(oper,"mult") == 0) return mult; else // assume must be "div" return div; } Note that we are returning a static method (function) name. So what is the type ArithFun ?
18
Pointer to void ( void * ) In C/C++ add, sub, etc., are function names, and thus address places in memory. " An address in C/C++ is just a pointer. To indicate a pointer to a function as the return type for ArithmeticInfo::getFun(), we use an all- encompassing type called pointer to void, or void * void * means pointer to anything, including pointer to integer, pointer to class object, or pointer to function (static method) To simplify: typedef void * ArithFun;
19
New Main Program for calc int main(Integer argc, StringArray operands) { String oper = operands[1]; Arithmetic a = new ArithmeticInfo(); ArithFun f = a->getFun(oper); Integer x = atoi(operands[2]); Integer y = atoi(operands[3]); Calc c = new CalcInfo(x, y); Integer result = c->calculate(f); cout << "The result is " << result << endl << endl; } Now we just need to change CalcInfo::calculate to accept a function as an argument, and then apply it.
20
Functions Passed as Arguments in C/C++ Integer CalcInfo::calculate(ArithFun fun) { <Apply fun to the operands and return the result> } The argument fun is of type void * " We must cast it to the proper type before using it: 1. Declare a local variable f of the proper type, 2. Cast fun to f, 3. Apply f to the operands and return the result.
21
Functions Passed as Arguments in C/C++ (cont'd) " Q: So what is the ``proper type''? A: A function with two Integer arguments that returns an Integer result: Integer (*) (Integer, Integer) This is just a type. It can be read as: ``Pointer to a function that takes two integer arguments and returns an integer as a result''. To declare a variable f of this type: Integer (*f) (Integer, Integer)
22
Final Version of CalcInfo::calculate Integer CalcInfo::calculate(ArithFun fun) { Integer (*f) (Integer, Integer); f = (Integer (*) (Integer, Integer))fun; return (*f)(operand1, operand2); } Note that f is a pointer to the function, so *f must be used to refer to the function itself. Also, the parentheses (*f) are necessary since the function operator f(..) has higher precedence than the indirection operator *.
23
Recall Possible Implementation of StateInfo Class class StateInfo { private:... public:... State blankUp(); State blankDown(); State blankLeft(); State blankRight();... }
24
New Implementation of StateInfo The tile-moving methods must be made static, since they will be passed to the ActionInfo constructor, and They must have an argument of type State, since they are static. class StateInfo { private:... public:... static State blankUp(State s); static State blankDown(State s); static State blankLeft(State s); static State blankRight(State s);... }
25
Recall the ActionInfo Class (yet again) Data: Name (up, down, left, right) Operation to perform the action Operations: Create a new action Execute the action operation ...
26
An ActionInfo Class Declaration " Q: What is the type of the action operation? A: Look at the signatures of the static tile- moving methods in StateInfo : State (*) (State, State) class ActionInfo { private: String name; State (*actionFun) (State state); public: ActionInfo(String n, State (*fun) (State state)); State execute(State state); String getName(); };
27
ActionInfo Class Constructor ActionInfo::ActionInfo(String n, State (*fun) (State state)) { name = n; actionFun = fun; } Q: Who calls the ActionInfo constructor?
28
Recall The Problem Class Problem -startState: State -finalState: State -actionList: ActionList +Problem(startTileNums: StringArray) +getStartState(): State +getFinalState(): State +getActionList(): ActionList -createActionList(): void Each action is stored in the ProblemInfo object's ActionList data variable.
29
The ActionListInfo Class An ActionListInfo object is just a collection of ActionInfo objects. In this design, it is created by the ProblemInfo class for use by the solver. " The solver gets the action list from the problem and uses it to find the action matching the user's input.
30
Recall the Implementation of solve()... String actionName = promptActionName(); Action action = actionList->findAction(actionName); if (action == NULL) { cout << "action " << actionName << " is not recognized." << endl; } else { State newState = action->execute(currentState);... }...
31
Executing the Action State ActionInfo::execute(State state) { return (*actionFun)(state); } When the Action object is found, it applies its stored, static, tile-moving method to the current state: However, note that the ActionInfo class knows nothing about the details of the state-changing methods it executes. For all it knows, it could be executing actions in domains other than the 8-puzzle.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.