in Uncategorized

Treasure Hunt – Matplotlib Animation

Player starts from a marked start position(denoted 2 in matrix) and traverses possible open doors(0s) and try to reach the treasure position(4). Player will have to retreat if the door is closed(1) in the path and seek another path through an open door(0).

Positions, start(2), treasure(4), open(0) doors and closed(1) doors are chosen at random in the NxN labyrinth matrix. Choose a value of N and ratio of open to closed doors to start the simulation

import numpy as np
from matplotlib import pyplot as plt
import matplotlib.animation as animation
from IPython.display import HTML
#Initial values for simulation

N=15 #size of the labyrinth (N x N matrix)
ratio= 0.7 #Ration of open doors vs closed doors

Build Labyrinth

P=2 #value denoting start position in matrix
D=4 #value denoting treasure position in matrix

#create labyrith matrix
#start with all open doors (value 0)
ar =np.zeros((1,N*N -2), dtype=int)
# add closed positions(value 1)
ar[0,int((N*N)  * ratio):] = 1
# Add start and treasure positions
ar=np.append(ar, [P,D])

#Shuffle all positions
np.random.shuffle(ar)

#Make as N x N matrix
ar = ar.reshape(N,N)
print(f"Labyrinth:\n\n {ar}")
Labyrinth:

 [[1 0 0 1 0 1 0 0 0 1 0 0 0 0 1]
 [1 1 0 0 1 1 1 0 0 0 1 0 0 0 0]
 [0 0 1 0 0 0 1 0 0 0 0 0 0 0 0]
 [0 0 0 0 1 1 1 1 1 0 0 0 0 1 0]
 [1 0 1 0 1 0 0 1 0 0 0 0 0 0 0]
 [0 0 1 0 0 0 0 0 0 0 1 1 0 1 0]
 [0 0 1 0 0 0 1 0 0 0 0 1 0 0 0]
 [1 2 1 1 0 1 0 0 0 0 0 1 0 1 0]
 [0 0 1 0 1 0 0 0 1 0 0 0 0 0 4]
 [0 0 0 1 0 0 0 0 0 1 0 0 0 0 1]
 [0 0 1 0 0 0 0 0 1 1 0 0 0 0 0]
 [0 0 1 0 0 0 1 0 1 0 0 0 1 0 0]
 [1 0 1 0 0 1 0 0 1 0 1 0 0 0 1]
 [1 0 0 0 1 0 0 0 0 1 0 0 0 1 0]
 [1 1 0 1 1 0 0 0 1 0 0 1 0 1 0]]
# Find the start position by looking up the position of P
Ppos=(0,0)
Dpos=(0,0)
for i in range(0, ar.shape[0]):
    for j in range(0, ar.shape[1]):
        if ar[i,j] ==P:
            Ppos=(i,j)
            break

print(f"Start position: {Ppos}")
Start position: (7, 1)
#Define function to traverse path

#Find possible next positions around current pos
#Checks boundaries. Looks around in clockwise direction
def find_pos_around(pos):
    r,c=pos[0],pos[1]
    apos=[]
    if c+1 < N:
        apos.append((r,c+1))
    if r+1 < N:
        apos.append((r+1,c))
    if c-1 > -1:
        apos.append((r,c-1))
    if r-1 > -1:
        apos.append((r-1,c))
    return apos

#Is the position already visited
def is_visited(pos):
    return pos in visit_index

#Is the position a closed door
def is_obstacle(pos):
    return ar[pos[0], pos[1]] ==1

def is_treasure(pos):
    return ar[pos[0], pos[1]] ==D

#update new position
def at_new_pos(pos):
    global counter
    visit_index[pos] =counter
    counter += 1
    hotpath.append(pos)

#capture traversed path
def log_trail(pos):
    trackX.append(pos[0])
    trackY.append(pos[1])
    hX=[]
    hY=[]
    for p in hotpath:
        hX.append(p[0])
        hY.append(p[1])
    hotTrack.append([hX,hY])

#retreat from a position
def pop_pos(pos):
    hotpath.pop()

#Move to next position
def moveto_next_pos(pos,opos):
    #print(f"Now:{pos}")
    log_trail(pos)
    at_new_pos(pos)
    found =False
    if is_treasure(pos):
        found =True
    else:
        around_pos = find_pos_around(pos)
        for npos in around_pos:
            if is_visited(npos) or is_obstacle(npos):
                continue
            else:
                found=moveto_next_pos(npos, pos)
                log_trail(pos) ##back from child
                if found:
                    break
    if not found:
        pop_pos(pos)
    return found

Traverse the labyrinth

#
counter =0
visit_index={} #tracks if a position previously visited
hotpath=[] #tracks the last traversed path
trackX=[] #x coordinates of traversed positions including retreated ones; for plotting
trackY=[] #y coordinates of traversed positions including retreated ones; for plotting
hotTrack=[] #coordinates of hotpath; for plotting

#Move to start position P from None and start traversing
found=moveto_next_pos(Ppos, None)
if found:
    print(f"Voila!\n\nFound Path:\n{hotpath}")
else:
    print(f"No Way!\n\n Last Path:\n{hotpath}")
Voila!

Found Path:
[(7, 1), (8, 1), (9, 1), (10, 1), (11, 1), (12, 1), (13, 1), (13, 2), (13, 3), (12, 3), (12, 4), (11, 4), (11, 5), (10, 5), (10, 6), (10, 7), (9, 7), (9, 6), (9, 5), (8, 5), (8, 6), (8, 7), (7, 7), (7, 8), (7, 9), (7, 10), (8, 10), (8, 11), (8, 12), (8, 13), (8, 14)]

Animate the paths

# X coordinates of labyrith
X= np.zeros((N*N,),dtype=int) 
# Y coordinates of labyrith
Y= np.zeros((N*N,),dtype=int) 
# Pos values in the labyrith, line open, closed, start and treasuree)
T= np.zeros((N*N,),dtype=int) 

#Build X, Y and T from labyrith matrix
pos=0
for i in range(0,ar.shape[0]):
    for j in range(0,ar.shape[1]):
        X[pos]=i
        Y[pos]=j
        T[pos]=ar[i,j]
        pos += 1
%%capture
#Plot the labyrinth as scatter
#Animate the traversed paths in yellow lines
#Animate the hot path in green line

#plt.rcParams['animation.ffmpeg_path'] = '/usr/bin/ffmpeg'

colormap = np.array([ 'g','r', 'b','c','m','c']) #color map of positions
sizemap = np.array([150,150,600,600,800]) #Size indicative of positions

def update_plot(frame):
    trailP.set_data(trackX[0:frame], trackY[0:frame])
    hotP.set_data(hotTrack[frame][0],hotTrack[frame][1])
    return trailP

fig = plt.figure(figsize=(10,10))
fig.suptitle("Treasure Hunt")
plt.scatter(X,Y, c=colormap[T], s=sizemap[T])

trailP =plt.plot([], [], color='y')[0]
hotP=plt.plot([], [], color='g', lw=3)[0]

anim=animation.FuncAnimation(fig, update_plot, 
                             frames=len(trackX), interval=500, repeat=False)
Writer = animation.writers['ffmpeg']
writer = Writer(fps=20, metadata=dict(artist='Me'), bitrate=1800)
anim.save("treasure_hunt.mp4", writer=writer)
HTML(anim.to_html5_video())

Write a Comment

Comment