Sea Cucumber - Advent of Code 2021 Day 25

 

Birmingham, UK

The final Advent of Code problem for 2021 only required a one part solution. We are given the positions of sea cucumbers that can move in one of two directions. All single direction moves happen simultaneously. The target position needs to have been previously un-occupied i.e. sea cucumbers cannot move into a spot that is anticipated to become vacant in the current step


We can move the sea cucumbers via a single pass of the data, but doing so would require us to maintain some state. This would ensure moves into previously unoccupied spots. 

An alternative is to first determine all the possible moves, and then execute them.

In the function below newPos is a lambda that accepts the x,y position of a sea cucumber and returns the potential new position. It also accepts the direction in which the sea cucumber can move. The code first determines all the sea cucumbers that can be moved and then proceeds to reposition them.

def moveSeaCucumbers(dir,newPos):
    
    # figure out what can be moved
    canMove = [ (x,y) for (x,y) in scPositions[dir] \
        if newPos(x,y) not in scPositions['>'] \
            and newPos(x,y) not in scPositions['v']  ]

    # move
    for (x,y) in canMove:
        scPositions[dir].remove((x,y))
        scPositions[dir].add(newPos(x,y))
    
    return len(canMove)

Learnings

While I have used anonymous functions in Java and Node.js, I hadn't encountered the need to use a lambda in Python yet. Quite interestingly, Python supports the declaration of an anonymous function via the lambda keyword, while also supporting the passing of named functions via a function call. 

I first invoke the move of sea cucumbers that face east, followed by those that face south.  Both calls use different lambdas that reposition either the x or y co-ordinates. These steps are repeated until no more moves are possible.

counter = 0
moves = -1
while moves != 0:
    moves = moveSeaCucumbers('>', lambda x,y: ((x+1)%w,y) )
    moves += moveSeaCucumbers('v', lambda x,y: (x,(y+1)%h) )
    counter +=1 

print(scPositions)
print("count",counter)