python (passing parameters to functions) - python

I'm not really new to python but I came across this problem that has just puzzled me.
So I was solving the maze runner problem, using A* and then was finding the hardest possible maze for a given dimension. For this purpose, I created a function called generateHardMaze() that is called from the main function and takes an attribute newMaze.
Now here is where things get weird, when I change the value of newMaze in the if condition within the while loop the hardMaze value changes without the code entering the second if condition. I'm not really sure why this happening was hoping someone could help me.
I'm using pycharm as my IDE and python3.6.* if that makes any difference.
I'm sure this isn't how oops works but I'm thinking this is a python thing. Has anyone ever come across anything like this? If yes please sympathize.
Thanks in advance.
def solveMazeAManH(newMaze,rows,cols):
startTime = time.time()
backTrackPriority = []
setup_cells(rows, cols)
# start and end points of the maze
start = (0, 0)
end = (rows - 1, cols - 1)
current = start
print("The path to be take is: ")
print(current)
frinLength = 0
# traversing the neighbours
while current != end:
unvisited.remove(current)
neighboursDFSandA(newMaze, current, rows, cols)
heuristic = calManhattanDis(current, end) # finding the heuristic for every traversal
try:
if not currentNeighbours:
if not backTrackPriority:
print("No path available!")
return 0
else:
while not currentNeighbours:
current = nextPopMan(backTrackPriority, end)
backTrackPriority.remove(current)
neighboursDFSandA(newMaze, current, rows, cols)
neighbor = leastPathChildMan(heuristic, current, end)
backTrackPriority.append(current)
current = neighbor
print(current)
frinLength += 1
except:
print("No path Found!")
return 0
return frinLength
endTime = time.time()
print("The time taken to solve the maze using A* with manhattan distance: ")
print(startTime - endTime)
def generateHardMaze(newMazes):
rows = len(newMazes)
cols = len(newMazes[0])
hardMaze = newMaze
print("Solving the original maze!")
fringLength = solveMazeAManH(newMazes, rows, cols)
print("Creating new harder Maze:")
pFlag = True
pCout = 0
while pFlag:
count = 0
flag = True
while flag:
point = choice(setup_cells(rows, cols))
if (newMazes[point[0]][point[1]] == 1):
newMazes[point[0]][point[1]] = 0
else:
newMazes[point[0]][point[1]] = 1
if (fringLength < solveMazeAManH(newMazes, rows, cols)):
print("Harder Maze--------------------")
hardMaze = newMaze
fringLength = solveMazeAManH(newMazes, rows, cols)
count = 0
else:
count += 1
if count >= 10:
flag = False
print("one")
newMazes = creatMaze(rows)
pCout += 1
if pCout >= 100:
pFlag = False
print(hardMaze)

Related

What is the best way to generate random ships in an array in Python?

Recently, I've been working on a battleship game for my CS2 class. The focus of this project is to create a board game using arrays, and I decided to create a battleship. I have most of the code, but I cannot figure out how to get ships to get randomly generated on a 10x10 array without the ships being...
A. The wrong length
B. Looping around the array
Below is the function I currently have.
def createShips(board):
shipLen = [5,4,3,3,2]
shipAvalible = 5
directionposibilities = ["vertical", "horizontal"]
j = 0
for i in range(shipAvalible):
boatMade = False
#REGULAR VAR STATMENTS
direction = random.choice(directionposibilities)
col = randint(0,9)
row = randint(0,9)
while boatMade == False:
if direction == "vertical":
buildCount = 0
if col + int(shipLen[i]) <= 11:
colission = False
for i in range(0, int(shipLen[i])):
buildCount += 1
if board[int(row-i)][int(col)-1] == "X":
if colission:
pass
else:
colission = True
if colission:
col = randint(0,9)
row = randint(0,9)
else:
for j in range(buildCount):
board[int(row-j)][int(col)-1] = "X"
boatMade = True
else:
col = randint(0,9)
row = randint(0,9)
if direction == "horizontal":
if col + int(shipLen[i]) <= 10:
colission = False
buildCount = 0
for i in range(0, int(shipLen[i])):
buildCount += 1
if board[int(row)][int(col)+i-1] == "X":
if colission:
pass
else:
colission = True
if colission:
col = randint(0,9)
row = randint(0,9)
else:
for j in range(buildCount):
board[int(row)][int(col)+j-1] = "X"
boatMade = True
else:
col = randint(0,9)
row = randint(0,9)
shipAvalible = shipAvalible - 1
return(board)
board = [["■"] * 10 for x in range(10)]
print(createShips(board))
If you have any idea why this may not work please let me know!
P.S. I am using another function that prints the array nicely, if you would like that for convenience, it is seen below:
def showBoard(board):
print(" A B C D E F G H I J")
print(" ------------------------------")
rownumb = 1
for r in board:
if rownumb == 10:
space = ""
else:
space = " "
print("%d|%s|" % (rownumb, space + "|".join(r)))
rownumb += 1
Edit: #Eumel was a bit faster and said it better here
First of all, you have a inner and outer loop with the variable i, which might not actually interfere but it makes it harder to read the code. Consider renaming one of the variables.
When you create a vertical ship, you check the col rather than the row for index error, and does so against a value of 11 instead of your board size 10.
In the vertical case you build the ship "backwards" from the selected position, even though you checked that your board could fit the ship in the positive direction (And you place it in a column to the left). These negative values makes it such that your ships can wrap around.
In the horizontal case you are indexing a bit strange again where board[int(row)][int(col)+i-1] this gives that when i=0 you place your ship an index further to the left than intended, again causing the ship to wrap when col=0.
Further more, you could remove a few redundant if statements and duplicate lines of code, by moving:
direction = choice(directionposibilities)
col = randint(0, 9)
row = randint(0, 9)
Inside the while loop.
Ok lets go over this:
length check
if col + int(shipLen[i]) <= 9: since arrays start at 0 in python the maximum index for a 10x10 board is 9, therefore you need to chek against 9 instead of 11
loop variables
for k in range(0, int(shipLen[i])): using the same variable name for the outer and inner loop (while working in this specific case) is really bad form
collision check
if board[row+k][col] == "X": you want to build the ships "forwards" so you use row+k, you can also forego int conversions when you only use integers to begin with
collsion check 2
if colission: pass else: colission = True This whole block can be shortened to collision = True break since you dont need to keep checking for multiple collisions
buildcount
for j in range(buildCount): unless you get a collision (then you wouldnt be in this branch) buildCount is always the same as shipLen[i] so it can be completly removed from your code
boat building
board[row+j][col] = "X": same as before we build forwards
honorable mentions
shipAvailable = len(shipLen) you could also remove this part completly and iterate over your ships directly in your out for loop
Instead of radoomising your direction row and col on every break condition you could randomize it once at the start of your while loop
j = 0 unlike C you dont have to define your variables before using them in a loop, this statement does nothing

Speeding Up Python Code Time

start = time.time()
import csv
f = open('Speed_Test.csv','r+')
coordReader = csv.reader(f, delimiter = ',')
count = -1
successful_trip = 0
trips = 0
for line in coordReader:
successful_single = 0
count += 1
R = interval*0.30
if count == 0:
continue
if 26 < float(line[0]) < 48.7537144 and 26 < float(line[2]) < 48.7537144 and -124.6521017 < float(line[1]) < -68 and -124.6521017 < float(line[3]) < -68:
y2,x2,y1,x1 = convertCoordinates(float(line[0]),float(line[1]),float(line[2]),float(line[3]))
coords_line,interval = main(y1,x1,y2,x2)
for item in coords_line:
loop_count = 0
r = 0
min_dist = 10000
for i in range(len(df)):
dist = math.sqrt((item[1]-df.iloc[i,0])**2 + (item[0]-df.iloc[i,1])**2)
if dist < R:
loop_count += 1
if dist < min_dist:
min_dist = dist
r = i
if loop_count != 0:
successful_single += 1
df.iloc[r,2] += 1
trips += 1
if successful_single == (len(coords_line)):
successful_trip += 1
end = time.time()
print('Percent Successful:',successful_trip/trips)
print((end - start))
I have this code and explaining it would be extremely time consuming but it doesn't run as fast as I need it to in order to be able to compute as much as I'd like. Is there anything anyone sees off the bat that I could do to speed the process up? Any suggestions would be greatly appreciated.
In essence it reads in 2 lat and long coordinates and changes them to a cartesian coordinate and then goes through every coordinate along the path from on origin coordinate to the destination coordinate in certain interval lengths depending on distance. As it is doing this though there is a data frame (df) with 300+ coordinate locations that it checks against each one of the trips intervals and sees if one is within radius R and then stores the shortest on.
Take advantage of any opportunity to break out of a for loop once the result is known. For example, at the end of the for line loop you check to see if successful_single == len(coords_line). But that will happen any time the statement if loop_count != 0 is False, because at that point successful_single will not get incremented; you know that its value will never reach len(coords_line). So you could break out of the for item loop right there - you already know it's not a "successful_trip." There may be other situations like this.
have you considered pooling and running these calculations in parallel ?
https://docs.python.org/2/library/multiprocessing.html
Your code also suggests the variable R,interval might create a dependency and requires a linear solution

Project Euler Project 67 - Python

I am doing the Project Euler #67 in Python. My program, which worked for Project 18, does not work for Project 67.
Code (excludes the opening of the file and the processing of information):
for i in range(len(temp)):
list1 = temp[i]
try:
list2 = temp[i+1]
trynum1 = list1[lastinput] + max(list2[lastinput],list2[lastinput+1])
try:
trynum2 = list1[lastinput+1] + max(list2[lastinput+1],list2[lastinput+2])
if trynum1 > trynum2:
outputlist.append(list1[lastinput])
else:
outputlist.append(list1[lastinput+1])
lastinput += 1
except IndexError:
outputlist.append(list1[0])
except IndexError:
if list1[lastinput] > list1[lastinput+1]:
outputlist.append(list1[lastinput])
else:
outputlist.append(list1[lastinput+1])
Variables:
temp is the triangle of integers
outputlist is a list which stores the numbers chosen by the program
I know the answer is 7273, but my program finds 6542. I cannot find an error which causes the situation. Please may you help me on it.
Logic
My approach to this program is to find one number (list1[lastinput]) and add it up with the larger number of the two below it (trynum1), compare with the number to the right of the first number (list1[lastinput+1]), adding the larger number of two below it (trynum2). I append the larger one to the output list.
This approach is logically flawed. When you're in row 1, you don't have enough information to know whether moving right or left will lead you to the largest sum, not with only a 2-row lookahead. You would need to look all the way to the bottom to ensure getting the best path.
As others have suggested, start at the bottom and work up. Remember, you don't need the entire path, just the sum. At each node, add the amount of the better of the two available paths (that's the score you get in taking that node to the bottom). When you get back to the top, temp[0][0], that number should be your final answer.
I thought day and night about problem 18 and I solved it, the same way I solved this one.
P.S. 100_triangle.txt is without 1st string '59'.
# Maximum path sum II
import time
def e67():
start = time.time()
f=open("100_triangle.txt")
summ=[59]
for s in f:
slst=s.split()
lst=[int(item) for item in slst]
for i in range(len(lst)):
if i==0:
lst[i]+=summ[i]
elif i==len(lst)-1:
lst[i]+=summ[i-1]
elif (lst[i]+summ[i-1])>(lst[i]+summ[i]):
lst[i]+=summ[i-1]
else:
lst[i]+=summ[i]
summ=lst
end = time.time() - start
print("Runtime =", end)
f.close()
return max(summ)
print(e67()) #7273
Though starting from the bottom is more efficient, I wanted to see if I could implement Dijkstra's algorithm on this one; it works well and only takes a few seconds (didn't time it precisely):
from math import inf
f = open("p067_triangle.txt", "r")
tpyramid = f.read().splitlines()
f.close()
n = len(tpyramid)
pyramid = [[100 - int(tpyramid[i].split()[j]) for j in range(i+1)] for i in range(n)]
paths = [[inf for j in range(i+1)] for i in range(n)]
paths[0][0] = pyramid[0][0]
def mini_index(pyr):
m = inf
for i in range(n):
mr = min([i for i in pyr[i] if i >= 0]+[inf])
if mr < m:
m, a, b = mr, i, pyr[i].index(mr)
return m, a, b
counter = 0
omega = inf
while counter < n*(n+1)/2:
min_weight, i, j = mini_index(paths)
if i != n-1:
paths[i+1][j] = min( paths[i+1][j], min_weight + pyramid[i+1][j])
paths[i+1][j+1] = min( paths[i+1][j+1], min_weight + pyramid[i+1][j+1])
else:
omega = min(omega, min_weight)
paths[i][j] = -1
counter += 1
print(100*n - omega)
Here is my solution. Indeed you have to take the bottom - up approach.
Result confirmed with PE. Thanks!
def get_triangle(listLink):
triangle = [[int(number) for number in row.split()] for row in open(listLink)]
return triangle
listOfLists = get_triangle('D:\\Development\\triangle.txt')
for i in range(len(listOfLists) - 2, -1, -1):
for j in range(len(listOfLists[i])):
listOfLists[i][j] += max(listOfLists[i+1][j], listOfLists[i+1][j+1])
print(listOfLists[0][0])

What is wrong wtih my Insertion Sort Code

I am trying to write code that is an insertion sort. I am trying to get the code to take 2 values and put them into a new list while sorting it. So far it just puts the values into the list without them being sorted, i'm not quite sure why
pos = 0
pos2 = 1
go = True
while go == True:
for i in range(len(ex)-1):
stack.append(ex[pos])
print(stack)
stack.append(ex[pos2])
print(stack)
if stack[pos] > stack[pos2]:
stack[pos], stack[pos2] = stack[pos2], stack[pos]
print(stack)
pos = pos + 2
pos2 = pos2 + 2
I know it's not efficient, but it is based off code i made for a bubble sort which does
go = True
add = 0
while go == True:
for i in range(len(ex)-1):
if ex[i] > ex[i+1]:
go = True
ex[i], ex[i+1] = ex[i+1], ex[i] #flips the numbers in the list
print(ex)
add = add + 1
if add >= len(ex):
go = False
EDIT
I have changed it drastically, but there is still a problem. It only swaps the values once, even if it needs to be swapped multiple times to be in the right place. Here is the code
pos = 0
while pos < len(ex)-1:
for i in range(len(ex)-1):
stack.append(ex[i])
print(stack)
if stack[i-1] > stack[i]:
stack[i-1], stack[i] = stack[i], stack[i-1]
pos = pos + 1
else:
pos = pos + 1
You have to compare ex[pos] with ex[pos2] then you append the right element first :
if ex[pos] > ex[pos2]:
stack[pos].append(ex[pos2])
else stack[pos].append(ex[pos])
print(stack)
Here is the pseudo code for a classic insertion sort from https://visualgo.net/sorting a great resource for learning sorting algorithms:
mark first element as sorted
for each unsorted element
'extract' the element
for i = lastSortedIndex to 0
if currentSortedElement > extractedElement
move sorted element to the right by 1
else: insert extracted element
And here is how you could implement insertion sort in python:
def insertion_sort(l):
for i in range(1, len(l)):
j = i-1
key = l[i]
while (l[j] > key) and (j >= 0):
l[j+1] = l[j]
j -= 1
l[j+1] = key
return l
Once you understand the basic insertion sort you should be able to understand where you went wrong in your implementation in that you are not properly storing stack[pos] in your implementation.

Python: List not searching diagonally

I am implementing a Python version of the game Othello / Reversi. However, my algorithm seems to be having trouble when searching in the southwest direction.
Here are some important functions to understand how my current code works:
def _new_game_board(self)->[[str]]:
board = []
for row in range(self.rows):
board.append([])
for col in range(self.columns):
board[-1].append(0)
return board
def _is_valid_position(self, turn:list)->bool:
'''return true if the turn is a valid row and column'''
row = int(turn[0]) - 1
column = int(turn[1]) - 1
if row >= 0:
if row < self.rows:
if column >= 0:
if column < self.columns:
return True
else:
return False
def _is_on_board(self, row:int, col:int)->bool:
'''returns true is coordinate is on the board'''
if row >=0:
if row < self.rows:
if col >=0:
if col < self.columns:
return True
def _searchNorthEast(self)->None:
'''Search the board NorthEast'''
print("NorthEast")
row = self.move_row
column = self.move_column
should_be_flipped = list()
row += 1
column -= 1
if self._is_on_board(row, column):
print("column searching NorthEast on board")
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
while True:
row += 1
column -= 1
if self._is_on_board(row, column):
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
continue
elif self.board[row][column] == self.turn:
self._to_be_flipped.extend(should_be_flipped)
break
else:
break
else:
self._to_be_flipped.extend(should_be_flipped)
else:
pass
def _searchSouthWest(self)->None:
'''Search the board SouthWest'''
print("in SouthWest")
row = self.move_row
column = self.move_column
should_be_flipped = list()
row -= 1
column += 1
if self._is_on_board(row, column):
print("column searching SouthWest on board")
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
while True:
row -= 1
column += 1
if self._is_on_board(row, column):
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
continue
elif self.board[row][column] == self.turn:
self._to_be_flipped.extend(should_be_flipped)
break
else:
break
else:
self._to_be_flipped.extend(should_be_flipped)
else:
pass
def _move_is_valid(self, turn:list)->bool:
'''Verify move is valid'''
self._to_be_flipped = list()
self._opponent = self._get_opposite(self.turn)
if self._is_valid_position(turn):
self.move_row = int(turn[0]) - 1
self.move_column = int(turn[1]) - 1
self._searchRight()
self._searchLeft()
self._searchUp()
self._searchDown()
self._searchNorthWest()
self._searchNorthEast
self._searchSouthEast()
self._searchSouthWest()
if len(self._to_be_flipped) > 0:
return True
else:
return False
Now let's say the current board looks like the following:
. . . .
W W W .
. B B .
. B . .
Turn: B
and the player makes a move to row 1 column 4, it says invalid because it does not detect the white piece in row 2 column 3 to be flipped. All my other functions are written the same way. I can get it to work in every other direction except in this case.
Any ideas why it is not detecting the piece in this diagonal direction?
Don't Repeat Yourself. The _search* methods are extremely redundant which makes it difficult to see that the signs in
row -= 1
column += 1
are correct. Since you've given only two directions (NE, SW) and no documentation of the board orientation, I cannot tell if the signs agree with the board layout or even agree with themselves.
The _search* methods are also too long and should be divided into multiple functions, but that's a secondary concern.
I agree with msw about not repeating stuff. It is tempting to go ahead and do what you can once you see it, but generalizing will save you the headaches of debugging.
Here is some pseudocode that should give the general idea. I might not be able to finagle working with your code, but hopefully this shows how to reduce repetitive code. Note it doesn't matter if -1 is up or down. The board class is simply a 2x2 array of (open square/player 1's piece/player 2's piece,) along with whose turn it is to move.
# x_delta and y_delta are -1/0/1 each based on which of the up to 8 adjacent squares you are checking. Player_num is the player number.
def search_valid(x_candidate, y_candidate, x_delta, y_delta, board, player_num):
y_near = y_candidate + y_delta
x_near = x_candidate + x_delta
if x_near < 0 or x_near >= board_width:
return False
if y_near < 0 or y_near >= board_width:
return False # let's make sure we don't go off the board and throw an exception
if board.pieces[x_candidate+x_delta][y_candidate+y_delta] == 0:
return False #empty square
if board.pieces[x_candidate+x_delta][y_candidate+y_delta] == player_num:
return False #same color piece
return True #if you wanted to detect how many flips, you could use a while loop
Now a succinct function can loop this search_valid to see whether a move is legal or not e.g.
def check_valid_move(x_candidate, y_candidate, board, player_num):
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if not x and not y:
continue # this is not a move. Maybe we don't strictly need this, since board.pieces[x_candidate+x_delta][y_candidate+y_delta] == player_num anyway, but it seems like good form.
if search_valid(x_candidate, y_candidate, dx, dy, board, player_num):
return True
return False
A similar function could actually flip all the opposing pieces, but that's a bit trickier. You'd need a while function inside the for loops. But you would not have to rewrite code for each direction.

Categories

Resources