I am working on a python tetris game that my proffessor assigned for the final project of a concepts of programming class. I have got just about everything he wanted to work on it at this point but I am having a slight problem with one part of it. Whenever I start moving pieces left and right I keep getting "index out of range error". This only happens when it is up against a piece. Here are the culprits that are giving me grief.
def clearRight(block=None):
global board, activeBlock, stackedBlocks
isClear = True
if(block == None):
block = activeBlock
if(block != None):
for square in block['squares']:
row = square[1]
col = square[0]+1
if(col >= 0 and stackedBlocks[row][col] !=None):
isClear=False
return isClear
def clearLeft(block=None):
global board, activeBlock, stackedBlocks
isClear = True
if(block == None):
block = activeBlock
if(block != None):
for square in block['squares']:
row = square[1]
col = square[0]-1
if(col >= 0 and stackedBlocks[row][col] !=None):
isClear=False
return isClear
I am not looking to get anyone to fix it for me, I'm only looking for tips on how to fix it myself. Thanks in advance for any help that is given.
There a typo that would cause that problem in the first method.
When you're checking each cell in the block shifted one right, you don't check if they are off the grid.
if (col >= 0 and ...)
probably should be
if (col < num_cols and ...)
I also agree with CrazyDrummer, make a generic clear function
Spoilers ...
def clear(x_offset, block=None):
if not block:
block = activeBlock
if not block: return True
for x,y in block:
x += x_offset
if not (0 <= x < num_cols) or stackedBlocks[x, y]:
return False
return True
Look at what's different when you're getting the exception. Try printing out program state information to help you zero in. There's only one place where you access an array with variable indexes, so you can narrow your search radius a bit.
Separate suggestion: Make a generic clear that takes determines what direction you want to clear from by the parameters.
I highly recommend the book debugging rules!, it will aid you in searching out and properly fixing problems. :D
Related
I need a loop over all of my clans, which are instances of a class. Each clan needs to be assigned a position, a x and a y coordinate. Preferably as two lists or as a single tuple (but no idea how I specify that). This is how it works for the 1st clan. Afterwards I always have to check, if the position is already assigned. If so, you have to search for a new position until it is free.
I then coded my class like this:
width = 20
height = 20
no_of_clans = 50
import random
class clan:
def __init__(self, index, position_list):
self.index = index
self.position_list = position_list
def index(no_of_clans):
return list(range(1, no_of_clans +1))
def position_list(self):
for i in range(1, no_of_clans +1):
positions = ()
if i ==1: #i can do it either like this
positions = [(random.randint(0, width)), (random.randint(0, height))]
positions.append(x,y)
else: #or like this, I do not know, which one is better, both are running
x = (random.randint(0, width))
y = (random.randint(0, height))
#check if x and y not already used
#assert
positions.append(x,y)
return positions
print(positions)
how can I assign positions randomly when also using 0.5 steps? I always get an error message.
I never get a list of my positions back, but I do not know what I did wrong.
I know those are probably fairly basic questions but I am quite new to python an already searched for 5h today and I really do ot know where to start anymore. I would be really happy if someon could help me. Thank you so much in advance <3
I found the answer to my original question in this post:
Coordinates of the edges of a honeycomb grid in python
Will update if I am finished with the class-thing :)
I am writing some Python code and I needed to change the logic of the code when I realized I can't come to a neat and efficient code solution.
So my first version is the following:
#set ranges
range_a=150
range_b=178
range_c=20
#add elements
for x in range(0, range_a):
# ...do something...
add_element_a()
for y in range(0, range_b):
# ...do something...
add_element_b()
for z in range(0, range_c):
# ...do something...
add_element_c()
As you can see I was adding the elements by type, first for type_a, then for type_b, and in the end for type_c. Now I would like to create a while-loop or something in order to add them alternating.
For example, we start by adding one from type_a and then one from type_b and etc. and we do it until we reach a range for a certain type, and then we continue for the rest of them.
I know it could be seen as a basic problem, but I am looking for an efficient solution?
Here is the second version which I find too complicated and was wondering if there is a more efficient way to do it:
filled_a = False
filled_b = False
filled_c = False
while(!(filled_a & filled_b & filled_c) == True)):
if (counter_a < range_a):
add_element_a()
counter_a++
if(counter_a==range_a): filled_a=True
if (counter_b < range_b):
add_element_b()
counter_b++
if(counter_b==range_b): filled_b=True
if (counter_c < range_c):
add_element_a()
counter_c++
if(counter_c==range_c): filled_c=True
Iterate according to the greatest range and check which range still wasn't exhausted:
#set ranges
range_a=150
range_b=178
range_c=20
#add elements
for i in range(max(range_a, range_b, range_c)):
if i < range_a:
add_element_a()
if i < range_b:
add_element_b()
if i < range_c:
add_element_c()
Such one of sulutions you can try this:
class RangeCounter:
def __init__(self, range_type):
self.range_type = range_type
def add_element(self):
# implement your addition logic here
pass
range_a= RangeCounter(150)
range_b= RangeCounter(178)
range_c= RangeCounter(20)
range_list = [range_a, range_b, range_c]
for range_type in range_list:
range_type.add_element()
I am trying to solve 8 puzzle problem in python given here in this assignment -https://www.cs.princeton.edu/courses/archive/fall12/cos226/assignments/8puzzle.html
My goal state is a little different from what is mentioned in the assignment -
#GOAL STATE
goal_state = [[0,1,2],[3,4,5],[6,7,8]]
The buggy part, it seems, is the isSolvable function. It is implemented correctly but while testing the board, it considers the goal state to be the one in which relative order is maintained and blank can be anywhere. So it might be the case that a board is solvable but it might not lead to the current defined goal state. So I am unable to think of a method in which I can test for all the possible goal states while running the solver function *
Also, my solver function was wrongly implemented. I was only considering the neighbor which had the minimum manhattan value and when I was hitting a dead end, I was not considering other states. This can be done by using a priority queue. I am not exactly sure as to how to proceed to implement it. I have written a part of it(see below) which is also kind of wrong as I not pushing the parent into the heap. Kindly provide me guidance for that.
Here is my complete code -
https://pastebin.com/q7sAKS6a
Updated code with incomplete solver function -
https://pastebin.com/n4CcQaks
I have used manhattan values to calculate heuristic values and hamming value to break the tie.
my isSolvable function, manhattan function and solver function:
isSolvable function -
#Conditions for unsolvability -->
#https://www.geeksforgeeks.org/check-instance-8-puzzle-solvable/
def isSolvable(self):
self.one_d_array = []
for i in range(0,len(self.board)):
for j in range(0,len(self.board)):
self.one_d_array.append(self.board[i][j])
inv_count = 0
for i in range(0,len(self.one_d_array)-1):
for j in range(i+1, len(self.one_d_array)):
if (self.one_d_array[i] != 0 and self.one_d_array[j] != 0 and self.one_d_array[i] > self.one_d_array[j]):
inv_count = inv_count + 1
if(inv_count % 2 == 0):
print("board is solvable")
return True
else:
print("board is not solvable")
return False
Manhattan function
def manhattan_value(self,data=None):
manhattan_distance = 0
for i in range(0,len(data)):
for j in range(0,len(data)):
if(data[i][j] != self.goal_state[i][j] and data[i][j] != 0):
#correct position of the element
x_goal , y_goal = divmod(data[i][j],3)
manhattan_distance = manhattan_distance + abs(i-x_goal) + abs(j-y_goal)
return manhattan_distance
Updated Solver function
#implement A* algorithm
def solver(self):
moves = 0
heuristic_value = []
prev_state = []
curr_state = self.board
output = []
heap_array = []
store_manhattan_values = []
if(curr_state == self.goal_state):
print("goal state reached!")
print(curr_state)
print("number of moves required to reach goal state --> {}".format(moves))
else:
while(True):
min_heuristic_value = 99999999999
min_pos = None
moves = moves + 1
output = self.get_neighbours(curr_state)
for i in range(len(output)):
store_manhattan_values.append([self.manhattan_value(output[i]),i])
#print(store_manhattan_values)
for i in range(len(store_manhattan_values)):
heapq.heappush(heap_array,store_manhattan_values[i])
#print(heap_array)
#print(heapq.heappop(heap_array)[1])
#if(moves > 1):
# return
return
Please refer to the PASTEBIN link for complete code and all the references (https://pastebin.com/r7TngdFc).
Updated code with incomplete solver function -
https://pastebin.com/n4CcQaks
In the given link for my code (based on my tests and debugging so far) -
These functions are working correctly - manhatten_value, hamming_value, append_in_list, get_neighbours
What does these functions do -
isSolvable - tells if the board can be solved or not
manhattan_value - calculates the manhattan value of the board passed to it.
hamming_value - calculates the hamming value of the board passed to it.
append_in_list - helper function for getting neighbours. It swaps values then save the resultant state in an array and then reswaps them to return to original position for further swapping and getting other possible states.
get_neighbours - gets all the possible neighbors which can be formed by swapping places with blank element(0 element).
solver - implements the A* algorithm
I am unable to find my mistake. Kindly guide me in this problem. Thank you in advance for your help!
I am apologizing in advance as I am unable to produce a minimal version of my code for this problem. I can not think of any way to use all the functions and produce a minimal version of the code.
(Note, this answer is different than the earlier revision about which many of the comments below were relating to.)
I don't see how the current code implements a queue. It seems like the while loop in the solver picks one new board state each time from a list of possible moves, then considers the next list generated by this new board state.
On the other hand, a priority queue, from what I understand, would have all the (valid) neighbours from the current board state inserted into it and prioritised such that the next chosen board state to be removed from the queue and examined will be the one with highest priority.
(To be completely sure in debugging, I might add a memoisation to detect if the code ends up also revisiting board states -- ah, on second thought, I believe the stipulation in the assignment description that the number of current moves be added to the priority assignment would rule out the same board state being revisited if the priority queue is correctly observed, so memoisation may not be needed.)
So, I'm brand new to programming, and this is frustrating me! What I want to do is be able to import a 4x8 text file, and turn the text into a 2D list so that I can swap two characters. For example, if the imported text file looks like this:
OOOOOOOO
OOOXOOOO
OOOOOOOO
OOOOOOOO
then I would like to be able to change the position of the X (the row/column location) when user input is entered, such that an O will get put in its place to preserve formatting. So, for exapmle, the program will prompt the user for their input and if the user enters "up," then the X will move one space up.
OOOXOOOO
OOOOOOOO
OOOOOOOO
OOOOOOOO
I want it to repeatedly prompt for a new move after each time one is made, and display the new grid each time (so you can see the X in its new position each time you enter a movement).
This is all I have so far. I know I need to first find the X, but I really don't know how to. I'm stuck here. Any help is appreciated.
#Global variables for the movements
UP = 8
DOWN = 2
RIGHT = 6
LEFT = 4
#Dimensions of grid
ROWS = 4
COLUMNS = 8
def start():
filename = input("Enter the name of the Start Positions file: ")
textFile = open(filename)
aMaze = [line.strip() for line in textFile]
for r in range(ROWS):
for c in range(COLUMNS):
print(aMaze[r][c], end="")
print()
def moveType():
while (True):
try:
move = input("ENTER YOUR MOVE: ")
except ValueError:
print("unimportant error message")
continue
if ((int(move)) in (DOWN, LEFT, RIGHT, UP)):
playerMove(move)
continue
else:
print("unimportant error message")
continue
return(move)
def playerMove(move):
move = (int(move))
if (move == DOWN):
#need help here
elif (move == UP):
#and here
elif (move == LEFT):
#don't know what i'm doing
elif (move == RIGHT):
#also here
start()
moveType()
This is a perfect opportunity to learn about abstraction. To solve your problem, think about the sub problems you could solve (with functions) that would make your final problem easier.
In your specific instance, wouldn't it be easier to write a program to find the Cartesian coordinates of where X is? With an (x,y) coordinate, you could then make a function to turn that coordinate (likely stored as a tuple) into a 2d array where that coordinate is an X an everything else is a zero.
Hint 1:
x =0
y =0
for row in numrows:
for col in numcols:
if array[row][col] == X
y = row
x = col
Hint 2:
for row in numrows:
for col in numcols:
if col is x and row is y:
place X
else:
place O
Note: if this were an application where you wanted to eek out every bit of performance, you certainly would not need to iterate through your array every time to find X. You could (and should) opt to store the location of X and then use two accesses into your array to flip X's and O's. But seeing as this is likely one of your first problems you are solving this is of course not a concern.
Hope this helps! Good luck starting to code!
I am doing a Sudoku puzzle solver for homework, but am encountering some difficulty. The code right now cycles past the solution, although it does reach it for easy puzzles, and for harder puzzles, it gets stuck with several 9's for no apparent reason. I would appreciate any help on this. (check_cell determines if the placement is valid or not.)
Is backtracking implemented correctly in this code, and if not, how would that be fixed?
How can I stop the solver from freezing? It solves around 3 rows and then freezes, changing most of the values to 9s.
Some code:
def solve_helper(self, row, col):
# Try placing a number in each column of current row
board = self.the_board
if board[row][col] != 0:
?????
elif board[row][col] == 0:
for i in range(1,10):
print("Setting value at i with ") + str (i) + (" located at " ) + str(row) + str(col)
self.set_cell(row, col, i)
self.guesses = self.guesses + 1
if self.check_cell(row, col):
if self.solve_helper(row, col): return True
else:
self.set_cell(row, col, 0)
else:
return self.mover(row,col)
return False
def mover(self, row, col):
if col + 1 != 9:
return self.solve_helper(row, (col+1))
elif row + 1 != 9:
print "Moving to row" + str(row + 1)
return self.solve_helper((row+1),0)
else:
print "SOLUTION FOUND"
return True
The trouble you're having is that some of your recursive calls are not returning the results properly, so your solution, when it is found, gets forgotten about a few levels up the recursive stack. Here's the first fix that you need, adding return to the recursive calls made in mover:
def mover(self, row, col):
if col + 1 != 9:
return self.solve_helper(row, (col+1)) # added return
elif row + 1 != 9:
print "Moving to row" + str(row + 1)
return self.solve_helper((row+1),0) # here too
else:
print "SOLUTION FOUND"
return True
You also need something similar in the special case of your solve_helper function where you skip over pre-solved cells. The end of the function should be:
else:
return self.mover(row, col) # added return
return False
Edit:
Ok, I've found a few more issues in the code. Two of them are logic issues with the solver, and one is a display issue that doesn't cause any real problems other than looking strange during the solving.
The issues:
First, you're latest code has solve_helper calling itself, rather than calling mover. This makes it take an extra function call before moving (though I think it may not actually break the solver).
Second, if solve_helper sets a cell to 9, but then in backtracked to (after some later cells couldn't be solved), the 9 doesn't get reset to zero before backtracking further.
And lastly, the display issue. Setting cells to 0 doesn't stop their old value from being displayed. This looked a lot like the issue in #2, (with 9s being left behind after backtracking) but in fact it is only cosmetic.
The first issue is easy to fix. Just change the solve_helper call to a mover call instead. That's actually what you had in the original code you put in the question. Calling solve_helper directly doesn't actually get the wrong result (since solve_helper will skip the already filled out cell the second time), but it adds an unnecessary extra function call to each level of your recursion.
The second issue is a little more complicated, and this is where you are getting stuck on some boards. What you need to do is move the line that does self.set_cell(row, col, 0) out of the else block it is currently in. In fact, you can actually move it outside of the loop entirely, if you want (since it only really is necessary if you're backtracking after none of the values for the current cell worked). Here is what I think this is the best arrangement of the for loop (also moving the return False statement up):
for i in range(1,10):
print("Setting value ") + str (i) + (" at " ) + str(row) + ", " + str(col)
self.set_cell(row, col, i)
self.guesses = self.guesses + 1
if self.check_cell(row, col):
if self.mover(row, col):
return True
print "Backtracking"
self.set_cell(row, col, 0)
return False
Finally, fixing the display issue requires two changes. First, get rid of the conditional in set_cell. You want to update the display always. Next, in update_textfield, move the delete call outside of the if block so that it always happens (leave the insert under the if). This makes it so that setting a cell to zero will erase the previous value, but not make it display an actual 0 character (it will show nothing).
I think this should do it. Note that the algorithm you're using is still pretty slow. Solving a board I found on the internet in a quick Google search took 122482 guesses and more than 5 minutes, but it did finally work. Other boards (especially those that require 8s or 9s in the first few open spaces) may take even longer.