# 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
ar =np.zeros((1,N*N -2), dtype=int)
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):
for j in range(0, ar.shape):
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,pos
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

def is_visited(pos):
return pos in visit_index

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

def is_treasure(pos):
return ar[pos, pos] ==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)
trackY.append(pos)
hX=[]
hY=[]
for p in hotpath:
hX.append(p)
hY.append(p)
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
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):
for j in range(0,ar.shape):
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],hotTrack[frame])
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')
hotP=plt.plot([], [], color='g', lw=3)

anim=animation.FuncAnimation(fig, update_plot,
frames=len(trackX), interval=500, repeat=False)

Writer = animation.writers['ffmpeg']
anim.save("treasure_hunt.mp4", writer=writer)
HTML(anim.to_html5_video())