Part 3: Transitions

Now we have a state (this is what we made in the last part). Given a state, we want to produce the children. In problem solving settings like this, the set of children are not known until you apply some rules or algorithms. In other words, the important question is: what is the logic to get the possible legal children? Illegal children would be things like having 3 people in the boat, etc.

We will break this down into a few parts:

  1. What are and how do we represent the possible moves?
  2. How can we apply a move to a state to make a new state?
  3. When are states illegal and how can you tell?

Possible Moves

What are a set of possible moves that can be done at every state?

Fill in the code below to return a list of all possible next moves. Assuming that we represented the state in Part 2 as a tuple, each move should also be a tuple which represents the changes in the state. For example, one move could be to move 1 missionary across the river by themself. In that case, the representation part for the missionaries would change and so would the side the boat was on.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class MCState:
    ### MC is missionaries and cannibals
    ### The init function is going to be whatever we decided from the previous part!


    def get_possible_moves(self):
        ## get all possible moves
        pass

root_state = MCState.root_state()


print(root_state.get_possible_moves())

Possible States

Given a function which gives us the possible moves, write a function which returns the next states. Don’t wrory about whether or not it’s legal yet.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class MCState:
    ### MC is missionaries and cannibals

    def __init__(self, state_vars, num_moves=0, parent=None):
        ### The init function is going to be whatever we decided from the previous part!


    def get_possible_moves(self):
        ## get all possible moves. this should be the code from above!
        pass

    def get_next_states(self):
        ## using possible move, get next states

        moves = self.get_possible_moves
        all_states = list()
        for move in moves:
            new_state_vars = "what would this be?"
            print("- Applied move: {}")
            print("- Getting state vars: {}".format(new_state_vars)

            ## notice the number of moves is increasing by 1
            ## also notice we are passing self to our child.
            new_state = MCState(new_state_vars, self.num_moves+1, self)
            all_states.append(new_state)

        return all_states

Exercise Extension: Better printing of states

Python lets us specify two functions that should return strings. These functions are called whenever you print out the variable. Although there are two functions and they are used in slightly different situations, we are going to have them return the same thing.

For this extension, add this to your state class so that it makes more sense when you print it out.

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class MCState:
    ### MC is missionaries and cannibals

    def __init__(self, state_vars, num_moves=0, parent=None):
        ### The init function is going to be whatever we decided from the previous part!

    def __str__(self):
        return "MCState; {} moves deep".format(self.num_moves)

    def __repr__(self):
        return str(self)

Exercise Extension: Using Properties

Another shortcut in python is the property decorator. It looks like the class method, but lets you reference functions as variables. These functions can never take arguments, so you are restricted to functions that just return stuff.

For this extension, convert things that can be properties. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class MCState:
    ### MC is missionaries and cannibals

    def __init__(self, state_vars, num_moves=0, parent=None):
        ### The init function is going to be whatever we decided from the previous part!


    @property
    def possible_moves(self):
        ## get all possible moves. this should be the code from above!
        ## this is now a property. notice how it is called below
        pass

root = MCState.root()

print(root.possible_moves)