Depth First Search Python Game Solver - python

I have a basic maze game in python "*" are walls, "W" water buckets which allow you to travel through fire "F" (if you have none you lose), "A" is the player and " " is air and "X" and "Y" are start and endpoints. There are also numbers from 1 - 9 which have 1 other matching number so the player can teleport. Example map:
*X**********
* 1 W F*
* FFFF 1 *
**********Y*
So I have a graph (dictionary) where I go through each character in the maze and find their neighbours like {"0,0": [None, "0,1", None, "0,1"]}
{"node": "LeftNeighbour", "RightNeighbour", "NeighbourAbove", "NeighbourBelow"}
and I am using coordinates "x,y" to denote neighbours.
Then the DFS code is ...
visited = []
def DFS_recursive(graph, node, nodeToFind):
global visited
for neighbour in graph[node]:
if neighbour == nodeToFind:
visited.append(neighbour)
break
if neighbour not in visited and neighbour != None:
# get x and y by breaking up the string
x = ""
y = ""
yFlag = False
for char in neighbour:
if char == ",":
yFlag = True
elif yFlag == False:
x += str(char)
else:
y += str(char)
x, y = int(x), int(y)
if grid[y][x].display == "*": # if the neighbour's display property is a wall, append the neighbour but don't call the function again ...
visited.append(neighbour)
else:
visited.append(neighbour)
DFS_recursive(graph, neighbour, nodeToFind)
So this works until I add teleport pad code.
if neighbour == (number from 1 - 9):
find the coordinates of the other teleport pad and make the coordinates the new node
DFS_recursive(graph, newNode, nodeToFind)
And yes I haven't added in the "nodeToFind" bit yet, couldn't quite get that to work so I added a separate function to deal with that. Probably should remove the parameter but anyway that's not the point.
So 1. Not sure if this is the right way to go about it (am new to programming)
and 2. No idea how to handle the teleport pads.
Thanks in advance!

Related

Python game of life generates wrong structures

I'm trying to program the game of Life in python. I keep getting the wrong structure generated after generation and pinpointed my mistake to the fuction bellow.
What I want the program to do:
It should iterate through an array to determine if the cell is going to be alive or dead in next generation and places them in an array "cells"
INPUT: (.-dead cell x- Alive cell)
...
xxx
...
OUTPUT
.x.
.x.
.x.
What is happening now:
The program iterates through cells and changes them. Then it uses the new values instead of the original ones to determine if the next cell is alive.
INPUT:
...
xxx
...
OUTPUT
.xx
x.x
...
Additional info:
Both arrays have a frame of permanently dead cells around.
def nextGen(matrice):
cells = matrice
size = np.shape(matrice)
for i in range(1,size[0]-1):
for j in range(1,size[1]-1):
if matrice[i][j] > 0:
alive = True
else:
alive = False
neighbours = 0
neighbours += matrice[i-1,j+1]
neighbours += matrice[i-1,j]
neighbours += matrice[i-1,j -1]
neighbours += matrice[i,j+1]
neighbours += matrice[i,j -1]
neighbours += matrice[i+1,j+1]
neighbours += matrice[i+1,j]
neighbours += matrice[i+1,j -1]
if alive:
if neighbours != 2 and neighbours !=3:
cells[i,j] = 0
#print("Cell has died", i, j, "Neighbours: ", neighbours)
else:
if neighbours == 3:
cells[i,j] = 1
#print("Cell was born", i, j,"Neighbours: ", neighbours)
neighbours = 0
return cells
The problem was as #user2357112 suggested that cells = matrice doesn't make a copy.
To fix that I needed to change it to cells = np.copy(matrice) .

(Traversal) How to solve this question in python?

Write a function traverse() that takes in a list tb of n strings each containing n lower case characters
(a-z).
tb represents a square table with n rows and n columns. The function returns a string st generated by the procedure below that traverses the grid starting from the top left cell and ending at the bottom right cell.
At every step, the procedure moves either horizontally to the right or vertically down, depending on which of the two cells has a \smaller" letter (i.e., a letter that appears earlier in the alphabetical order).
The letter in the visited cell is then added to st. In case of ties, either direction can be taken.
When the right or bottom edges of the table are reached, there is obviously only a unique next cell to move to. As an example, traverse(["veus", "oxde", "oxlx", "hwuj"]) returns "veudexj"
so the table would look like this:
v o o h
e x x w
u d l u
s e x j
I am new in python and I wrote this code ... but it only prints "veuexj" I would say the problem is in this line if new_list[a - 1][b - 1] == new_list[a - 1][-2]: which force the parameter to skip the 'd' character. #And I don't know how to solve it.
def traverse(tb_list):
new_list = tb_list.copy()
st = new_list[0][0]
parameter = ''
handler = 1
for a in range(1, len(new_list)):
for b in range(handler, len(new_list[a])):
if new_list[a - 1][b - 1] == new_list[a - 1][-2]:
parameter = new_list[a][b]
elif new_list[a - 1][b - 1] > min(new_list[a - 1][b], new_list[a][b - 1]):
parameter = min(new_list[a - 1][b], new_list[a][b - 1])
elif new_list[a - 1][b - 1] < min(new_list[a - 1][b], new_list[a][b - 1]):
parameter = min(new_list[a - 1][b], new_list[a][b - 1])
st += parameter
handler = b
return st
print(traverse(["veus", "oxde", "oxlx", "hwuj"]))
You can try something like this (explanation added as comments):
def traverse(tb_list):
lst = tb_list.copy() #Takes a copy of tb_list
lst = list(zip(*[list(elem) for elem in lst])) #Transposes the list
final = lst[0][0] #Sets final as the first element of the list
index = [0,0] #Sets index to 0,0
while True:
x = index[0] #The x coordinate is the first element of the list
y = index[1] #The y coordinate is the second element of the list
if x == len(lst) - 1: #Checks if the program has reached the right most point of the table
if y == len(list(zip(*lst))) - 1: #Checks if program has reached the bottommost point of the table
return final #If both the conditions are True, it returns final (the final string)
else:
final += lst[x][y+1] #If the program has reached the right most corner, but not the bottommost, then the program moves one step down
index = [x, y+1] #Sets the index to the new coordinates
elif y == len(list(zip(*lst))) - 1: #Does the same thing in the previous if condition button in an opposite way (checks if program has reached bottommost corner first, rightmost corner next)
if x == len(lst) - 1:
return final
else:
final += lst[x + 1][y] #If the program has reached the bottommost corner, but not the rightmost, then the program moves one step right
index = [x + 1, y]
else: #If both conditions are false (rightmost and bottommost)
if lst[x+1][y] < lst[x][y+1]: #Checks if right value is lesser than the bottom value
final += lst[x+1][y] #If True, then it moves one step right and adds the alphabet at that index to final
index = [x+1,y] #Sets the index to the new coords
else: #If the previous if condition is False (bottom val > right val)
final += lst[x][y+1] #Moves one step down and adds the alphabet at that index to final
index = [x,y+1] #Sets the index to the new coords
lst = ["veus", "oxde", "oxlx", "hwuj"]
print(traverse(lst))
Output:
veudexj
I have added the explanation as comments, so take your time to go through it. If you are still not clear with any part of the code, feel free to ask me. Any suggestions to optimize/shorten my code are most welcome.

Return part of list in which I matched mouse position to coordinates in python

I'm making a chess program and as such need the program to tell me what piece I have clicked on. So far it tells me if I've clicked on any piece at all, by matching rounded mouse x and y coordinates to a list of current piece coordinates. However, the program doesn't know what exact piece I've clicked, and I'm wondering if using a while loop I can make the loop end when a piece is found, and print/store the section of the list I was on when I found a matching piece to my mouse coords.
Currently I've got this code, which should be a good starting point for my problem
if event.type == pygame.MOUSEBUTTONDOWN:
mousepos = pygame.mouse.get_pos()
#rounddown80 is a function to round down mouse coords to multiple of 80
roundedmouse1 = roundup80(mousepos[0])
roundedmouse2 = roundup80(mousepos[1])
#print(roundedmouse1,roundedmouse2)
mousecoords = [roundedmouse1,roundedmouse2]
#print(mousecoords)
foundpiece = False
while foundpiece == False:
for x in piecespositions:
if x[0] == mousecoords[0] and x[1] == mousecoords[1]:
print("Great job you clicked a piece")
foundpiece = True
And my piecepositions list looks like
piecespositions = [queenblackpos,kingblackpos,bishop1blackpos,bishop2blackpos,knight1blackpos,knight2blackpos,
etc for all pieces, and queenblackpos for example would be [80,160]
You can keep track of what piece you are on inside the while loop, either in for i in range(0,len(piecepositions)) or with a variable that increases.
For example something like this:
while foundpiece == False:
index=0 #Reset index before checking all pieces
for x in piecespositions:
if x[0] == mousecoords[0] and x[1] == mousecoords[1]:
print("Great job you clicked a piece")
foundpiece = True
found_pos=x #store position of the piece that was found
index=index+1 #Keep adding to index to know which piece was found
pygame.display.flip() #Update the window
print (f"Piece found in {index}: {found_pos}") #print the position of the piece as well as what is its index in the list.
This will store the position of the piece that was found in found_pos and keep track of which piece is being checked at the moment using index var. After the while loop ends it prints out the position of the piece and the index of that piece in the list.
Do note though, during the while loop the script will be "stuck" until the while is finished, so it will be unable to update the window during the piece check therefore the game will freeze. So to solve this, you have to add pygame.display.flip() inside the while.
I did something like this. Hope that it will help You:
square_s = 160 # square(tile) size - you can pass your value
letters = ["A", "B", "C", "D", "E", "F", "G", "H"] # letters used in pos symbols
# match each tile on board to the right cords symbol and value(x, y)
def matchSqrCords(sqr_s, letters):
positions = [] # matched positions
for y in range(8): # for each row on the board
for x in range(8): # for each column(tile in a row) on the board
pos = ["", 0, 0] # curr position
pos[0] += letters[y] # add letter prefix to pos symbol
pos[0] += str(x + 1) # add number prefix to pos symbol
pos[1] = sqr_s*(x + 1) # calc max x range of a tile
pos[2] = sqr_s*(y + 1) # calc max y range of a tile
positions.append(pos) # add matched pos to list
return positions # return list with matched positions
def checkPosition(given_cords, cords, sqr_s):
# check if typed values are on the board
if given_cords[0] > sqr_s * 8 or given_cords[1] > sqr_s * 8:
return "Cords not on the board!"
else:
for cord in cords: # check all cords
# check if given cords x value is in range of curr cord
if given_cords[0] <= cord[1] and given_cords[0] > cord[1] - sqr_s:
# check if given cords y value is in range of curr cord
if given_cords[1] <= cord[2] and given_cords[1] > cord[2] - sqr_s:
return cord[0] # return symbol of the found cord
matched_pos = matchSqrCords(square_s, letters=letters)
print(checkPosition([192, 569], matched_pos, square_s))

the story of a tree hackerrank solution error

Found this problem in hackerrank and have failed to pass some testcases.
One day Bob drew a tree, with n nodes and n-1 edges on a piece of paper. He soon discovered that parent of a node depends on the root of the tree. The following images shows an example of that:
Learning the fact, Bob invented an exciting new game and decided to play it with Alice. The rules of the game is described below:
Bob picks a random node to be the tree's root and keeps the identity of the chosen node a secret from Alice. Each node has an equal probability of being picked as the root.
Alice then makes a list of g guesses, where each guess is in the form u v and means Alice guesses that parent(v) = u is true. It's guaranteed that an undirected edge connecting u and v exists in the tree.
For each correct guess, Alice earns one point. Alice wins the game if she earns at least k points (i.e., at least k of her guesses were true).
Alice and Bob play q games. Given the tree, Alice's guesses, and the value of k for each game, find the probability that Alice will win the game and print it on a new line as a reduced fraction in the format p/q.
Solution:
There is a tree with some edges marked with arrows. For every vertex in a tree you have to count how many arrows point towards it.For one fixed vertex this may be done via one DFS. Every arrow that was traversed during DFS in direction opposite to its own adds 1.If you know the answer for vertex v, you can compute the answer for vertex u adjacent to v in O(1).
It's almost the same as for v, but if there are arrows u->v or v->u, their contributions are reversed.Now you can make the vertex u crawl over the whole graph by moving to adjacent vertices in the second DFS.
Problem: It is not able to pass all the test cases. I did sanity testing of the code and found no problem but I am not getting any clue why this is not working in hackerrank platform.
import sys
def gcd(a, b):
if not b:
return a
return gcd(b, a%b)
def dfs1(m, guess, root, seen):
'''keep 1 node as root and calculate how many arrows are pointing towards it'''
count = 0
for i in m[root]:
if seen[i][root] != 1 and seen[root][i] != 1:
seen[i][root] = 1
seen[root][i] = 1
count += (1 if guess[root][i] == 1 else 0) + dfs1(m, guess, i, seen)
return count
def dfs2(m, guess, root, seen, cost, k):
'''now make every node as root and calculate how many nodes
are pointed towards it; If u is the root node for which
dfs1 calculated n (number of arrows pointed towards the root)
then for v (adjacent node of u), it would be n-1 as v is the
made the parent now in this step (only if there is a guess, if
there is no guess then it would be not changed)'''
win = cost >= k
for i in m[root]:
if seen[i][root] != 1 and seen[root][i] != 1:
seen[i][root] = 1
seen[root][i] = 1
win += dfs2(m, guess, i, seen, cost - (1 if guess[root][i] == 1 else -guess[i][root]), k)
return win
q = int(raw_input().strip())
for a0 in xrange(q):
n = int(raw_input().strip())
m = {}
guess = [[0 for i in range(n+1)] for i in range(n+1)]
seen = [[0 for i in range(n+1)] for i in range(n+1)]
for a1 in xrange(n-1):
u,v = raw_input().strip().split(' ')
u,v = [int(u),int(v)]
if u not in m:
m[u] = []
m[u].append(v)
if v not in m:
m[v] = []
m[v].append(u)
g,k = raw_input().strip().split(' ')
g,k = [int(g),int(k)]
for a1 in xrange(g):
u,v = raw_input().strip().split(' ')
u,v = [int(u),int(v)]
guess[u][v] = 1
cost = dfs1(m, guess, 1, seen)
seen = [[0 for i in range(n+1)] for i in range(n+1)]
win = dfs2(m, guess, 1, seen, cost, k)
g = gcd(win, n)
print("{0}/{1}".format(win/g, n/g))
One possibility is that the code is correct but you are getting a stack overflow.
There can be 100,000 nodes and if these are all connected in a line your depth first search recursion will fail.
If this is true, then converting the DFS code from a recursive to an iterative formulation (by keeping a stack of things to try in an array) should help.
Another possibility is that there could be a guess such as 1,2 and a guess such as 2,1. In this case I am not sure that the score updating code would work:
win += dfs2(m, guess, i, seen, cost - (1 if guess[root][i] == 1 else -guess[i][root]), k)
perhaps this would work better:
win += dfs2(m, guess, i, seen, cost - guess[root][i] + guess[i][root], k)

Count the number of possible paths through a grid

There is a robot at the top-left corner of an N*M grid. The robot can move up, down, left and right, but cannot visit the same cell more than once in each traversal. How do I find the total number of ways the robot can reach the bottom-right corner?
(the robot does not need to visit every cell for a path to be valid)
I think there is a recursive solution to this but I can't get it somehow.
Here's what I've got so far:
def initialize(row, cols):
grid = [ [ 0 for c in range(cols) ] for r in range(rows) ]
pos_r, pos_c = 0, 0
grid[pos_r][pos_c] = 1 # set start cell as visited
dst_x, dst_y = len(grid)-1, len(grid[0])-1 # coords of bottom-right corner
print move_robot(grid, dst_x, dst_y, pos_r, pos_c)
def move_robot(grid, dst_x, dst_y, pos_r, pos_c, prev_r=None, prev_c=None):
num_ways = 0
if reached_dst(dst_x, dst_y, pos_r, pos_c):
undo_move(grid, pos_r, pos_c)
undo_move(grid, prev_r, prev_c)
return 1
else:
moves = get_moves(grid, pos_r, pos_c)
if len(moves) == 0:
undo_move(grid, prev_r, prev_c)
return 0
for move in moves:
prev_r = pos_r
prev_c = pos_c
pos_r = move[0]
pos_c = move[1]
update_grid(grid, pos_r, pos_c)
num_ways += move_robot(grid, dst_x, dst_y, pos_r, pos_c, prev_r, prev_c)
return num_ways
if __name__ == '__main__':
initialize(4, 4)
I left out some function definitions for brevity. Get_moves retrieves the all legal moves, checking whether each move would still be on the board and whether the cell has already been visited. Update_grid sets the specified cell to '1', which means visited. Undo_move does the opposite, setting the specified cell to '0'.
I get the right answer for the simplest possible case (2*2 grid), but for larger grids the output is always too low. What's wrong with my code, and is there a simpler way of doing this?
The recursion is pretty straight forward but one should be careful to create copies of the matrix while recursing in order to receive good results:
from copy import copy, deepcopy
def calc(i, j, mat):
if i < 0 or j < 0 or i >= len(mat) or j >= len(mat[0]):
return 0 # out of borders
elif mat[i][j] == 1:
return 0 # this cell has already been visited
elif i == len(mat)-1 and j == len(mat[0])-1:
return 1 # reached destination (last cell)
else:
mat[i][j] = 1 # mark as visited
# create copies of the matrix for the recursion calls
m1 = deepcopy(mat)
m2 = deepcopy(mat)
m3 = deepcopy(mat)
m4 = deepcopy(mat)
# return the sum of results of the calls to the cells:
# down + up + right + left
return calc(i+1, j, m1) + calc(i-1, j, m2) + calc(i, j+1, m3) + calc(i, j-1, m4)
def do_the_robot_thing(m, n):
# an un-visited cell will be marked with "0"
mat = [[0]*n for x in xrange(m)]
return calc(0, 0, mat)
print(do_the_robot_thing(3, 3))
OUTPUT:
12

Categories

Resources