- By
**enid** - Follow User

- 74 Views
- Uploaded on

Download Presentation
## PowerPoint Slideshow about 'Implementing the 8-puzzle Design' - enid

**An Image/Link below is provided (as is) to download presentation**

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript

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();

...

}

solve() Pseudocode Revisited

Recall the pseudocode for SolverInfo::solve():

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

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;

...

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.

A Better Approach

Wrap each of the methods StateInfo::blankUp(), StateInfo::blankDown(), etc., in a new Action object.

Put each of these Actions 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.

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.

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

. . .

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%

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.

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;

}

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;

}

...

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;

}

CalcInfo Modification

This requires:

Being able to treat functions as arguments

Being able to return functions as function values

Suppose we want to remove the arithmetic details

from CalcInfo, to be handled by another class:

Integer CalcInfo::calculate(ArithFun fun) {

return the result>

}

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);

};

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.

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?

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;

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.

Functions Passed as Arguments in C/C++

The argument fun is of type void *

We must cast it to the proper type before using it:

Declare a local variable f of the proper type,

Cast fun to f,

Apply f to the operands and return the result.

Integer CalcInfo::calculate(ArithFun fun) {

return the result>

}

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)

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 *.

Recall Possible Implementation of StateInfo Class

class StateInfo {

private:

...

public:

...

State blankUp();

State blankDown();

State blankLeft();

State blankRight();

...

}

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);

...

}

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

. . .

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();

};

ActionInfo Class Constructor

ActionInfo::ActionInfo(String n,

State (*fun) (State state)) {

name = n;

actionFun = fun;

}

Q: Who calls the ActionInfo constructor?

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.

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.

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);

. . .

}

...

Executing the Action

When the Action object is found, it applies its stored,

static, tile-moving method to the current state:

State ActionInfo::execute(State state) {

return (*actionFun)(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.

Download Presentation

Connecting to Server..