Friday, December 2, 2011

Puzzle finding shortest path

The first line has the number of rows in the nucleus (N), then the number of columns (M), then the length of Danny Dendrite's genome (X). Following that are N lines, each of which has M characters: an ‘o’ represents an empty square and an ‘x’ represents a filled square.

Print for him a path, consisting of a list of positions, starting anywhere in the nucleus, where:

- Each position is empty
- Each successive position is only 1 nm away from the one before it
- The path passes through each position in the nucleus at most once
- The number of positions visited is equal to the length of Danny Dendrite's genome (the starting and ending positions both count).

#
# P.T.
#
# https://dnanexus.com/careers/puzzles
#
#

import networkx # needs ver 1.6
import matplotlib.pyplot as plt

#input
rawData = """5 4 8
oxoo
xoxo
ooxo
xooo
oxox"""

def getNeighbours(row, col, maxRow, maxCol):
""">>> getNeighbours(1,1)
[[1, 0], [1, 2], [0, 1], [2, 1]]
"""
left = [row - 1, col]
right = [row + 1, col]
top = [row, col - 1]
bottom = [row, col + 1]

neighbours = [top, bottom, left, right]

if (top[1] < 0 or top[1] >= maxCol):
neighbours.remove(top)
if bottom[1] < 0 or bottom[1] >= maxCol:
neighbours.remove(bottom)
if left[0] < 0 or left[1] >= maxRow:
neighbours.remove(left)
if right[0] < 0 or right[0] >= maxRow:
neighbours.remove(right)

return neighbours

def isOk(node):
"""'o' isOk, 'x' is not"""
if (node == 'o'):
return True
else:
return False

# parse
#infile = [line.rstrip() for line in open('in').readlines()]
infile = [line.rstrip() for line in rawData.split('\n')]
[nrow, ncol, plen] = infile[0].split(' ')
nrow = int(nrow)
ncol = int(ncol)
plen = int(plen)
data = infile[1:]

# construct graph from input
G = networkx.Graph()
hash = '%s,%s'
print nrow, data, len(data)
assert len(data) == nrow
for row in range(nrow):
line = data[row]
assert len(line) == ncol
for col in range(ncol):
node = data[row][col]

#print 'node=', node, 'row=', row, 'col=', col

if (not isOk(node)):
continue

G.add_node(hash % (row,col))
neighbours = getNeighbours(row, col, nrow, ncol)

#print neighbours

for x,y in neighbours:

#print '?? x=', x, 'y=', y

if (not isOk(data[x][y])):
continue

#print 'x=', x, 'y=', y

G.add_edge(hash % (row,col), hash % (x,y))

print("Nodes\n%s" % G.nodes())
print("Edges\n%s" % G.edges())

# find shortest paths
paths = networkx.shortest_path(G)
for src in paths.keys():
for dest in paths[src].keys():
if len(paths[src][dest]) < plen:
continue
print("Path src=%s to dest=%s\n%s" % (src, dest, paths[src][dest]))

#print("Connected\n%s" % networkx.connected_components(G))

# visualize
networkx.draw(G)
plt.savefig("path.png")

No comments: