Aabshaar
Aabshaar

Reputation: 25

How to append multiple items to a nested-list? How do you successfully approach a variation of a river-crossing problem?

I am attempting to solve this riddle similar to the Wolf, goat and cabbage problem, and trying to represent it in a graph format (with nodes and edges representing all potential paths).

This is the problem:

2 circus families have got an act where one family, consisting of a mother, father and daughter, are on the left hand side of a flying trapeze and the other family, with two brothers and a sister, are on the right hand side of the flying trapeze. Each person begins by hanging from their own individual swing and there is an empty swing separating the two families as follows:

Mother, Father, Daughter, Empty, Sister, Younger Brother, Older Brother

It is only possible a person to swing from their swing to an empty swing that is either adjacent to their current swing or that is separated from their position by a single individual from either family. The aim of the trick is for both families to swap sides. No member of the family is allowed to swing backwards at any stage. What is the sequence of moves which will result in the trick being performed successfully?

I labelled the family on the left as family 'A' and the family on the right as 'B', and empty as 'É', and started with the first position, trying to graph all the possible permutations that could exist.

Right now I tried to do only the first possible move (moving to an adjacent empty swing), but I seem to be running into some technical problem I have no idea why it is.

I am trying to make the list of possible steps at each step.

This is what I have.

iC=['A','A','A','E','B','B','B']
newC=[]

for x in range(0,7):
    if iC[x]=='E':
        if iC[x-1]=='A' and iC[x+1]=='B':
            iC[x-1]='E'
            iC[x]='A'
            newC.append(iC)
            iC[x-1]='A'
            iC[x]='B'
            iC[x+1]='E'
            newC.append(iC)
        elif iC[x-1]=='A':
            iC[x-1]='E'
            iC[x]='A'
            newC.append(iC)
        elif iC[x+1]=='B':
            iC[x+1]=='E'
            iC[x]=='B'
            newC.append(iC)
        break

print(newC)

I am trying to append a new item into a new list but it changes the item instead. Could it because the append is in the if statement twice and just changes the appended item? Is there a more efficient way of doing this? Thanks any help would be appreciated :)

Upvotes: 0

Views: 83

Answers (1)

Vroomfondel
Vroomfondel

Reputation: 2898

For easier handling I renamed the artists 1,2,3 for the family on the left and -3,-2,-1 for the family on the right, and 0 for the empty swing. This way a test for the correct final order is simply a test on monotony: [-3,-2,-1,0,1,2,3]

The algorithm is separated in two functions, test_order tests if the final order is reached. If not, it tries to produce all following orders via possible_swings and recurses into itself with each of them. If the final order is reached it writes it out and returns success to its parent call which in turn knows that it can output its own order. You get the steps in reverse order therefore. I leave it as an exercise to you to rewrite the program to produce the "correct" order (hint: start with the end situation).

One interesting thing to note is that this riddle looks like it is mirror-symmetrical in its solution, i.e. the steps can be replayed back and forth with just the names of the elements exchanged. Does anyone have a deeper insight?

def possible_swings(trapezes,empty_nr):
    def swing(a): # swing from a to empty_nr
        tmp_trapezes = trapezes[:]
        tmp_trapezes[empty_nr] = tmp_trapezes[a]
        tmp_trapezes[a] = 0
        return (tmp_trapezes,a)
    
    r_trapezes = []
    
    if empty_nr >= 2 and trapezes[empty_nr-2] > 0:
        r_trapezes.append(swing(empty_nr-2))
    if empty_nr >= 1 and trapezes[empty_nr-1] > 0:
        r_trapezes.append(swing(empty_nr-1))
    if empty_nr < len(trapezes)-2 and trapezes[empty_nr+2] < 0:
        r_trapezes.append(swing(empty_nr+2))
    if empty_nr < len(trapezes)-1 and trapezes[empty_nr+1] < 0:
        r_trapezes.append(swing(empty_nr+1))
    return r_trapezes

def is_monotonic(li):
     return all([li[i]<li[i+1] for i in range(len(li)-1)])
    
def test_order(trapezes,empty_nr):
    if empty_nr == 3 and is_monotonic(trapezes):
        print(trapezes)
        return True
    else:
        for next_swing,next_empty in possible_swings(trapezes,empty_nr):
            if test_order(next_swing,next_empty):
                print(trapezes)
                return True
    return False

print(test_order([1,2,3,0,-3,-2,-1],3))

EDIT:

is_monotonic is running through the given array (0 up to length-1) and returns True if it finds strictly monotonic increasing elements. In our case this indicates the final order the riddle wants the two families to arrive at.

test_order tests the current order and, as I explained up there, produces all subsequent orders which are possible with the next allowed swing. This is a tree search, depth first: from the current order on the trapezes there follows a number of "next" orders. If the riddle can be solved we must finally arrive at the sought order, on the way pruning all non-resolving tree descents.

Upvotes: 1

Related Questions