def genkids(self): new = set() if len(self.cords) < 4: for cord in self.cords: for i in [[0, 1], [1, 0], [0, -1], [-1, 0]]: new.add((cord[0] + i[0], cord[1] + i[1])) for item in self.cords: new.discard(item) if new: for i in new: temp = [] for k in self.cords: temp.append(k) temp.append(i) self.child.append(TreePoint(temp)) self.child[-1].genkids() else: for i in range(1, 18): for cord in self.cords: tempcords = [] for k in self.cords: temp = [-cord[0] + k[0], -cord[1] + k[1]] if temp not in utils.generate_shape(i): break else: self.id = i
def setPieceId(self, shapeId, CopyT, row, col, M, pieceId): shape = utils.generate_shape(shapeId) for [y, x] in shape: CopyT[y + row][x + col] = 0 M[y + row][x + col] = (shapeId, pieceId) pieceId += 1 return CopyT, M, pieceId
def check_piece_validity(target, r, c): #check for pieces that fit in the target area valid_pieces = [] #create list for valid pieces for shape_id in range(4, 20): #check each of 16 shapes with ids 4-19 shape = utils.generate_shape( shape_id ) #define shape from utils as a linear transformation using 4 coordinate pairs piece = [[y + r, x + c] for [y, x] in shape] #define piece as 4 coordinate pairs #check piece validity valid = False #set default piece validity piece_neighbour_counts = [ ] #create list for neighbour count for each occupied square of a piece for j, k in piece: #for each coordinate if j < 0 or j >= height or k < 0 or k >= width: #no negative numbers otherwise will look from end of list break else: if target[j][ k] == 1: #check if the coordinate square is occupied piece_neighbour_counts.append( neighbour_count_matrix[j][k]) if piece.index([j, k]) == 3: valid = True else: break #one of the squares is not occupied, go to next piece if valid: valid_pieces.append( [piece, shape_id, sum(piece_neighbour_counts)]) #store valid shape ids sorted(valid_pieces, key=lambda piece: piece[2]) return valid_pieces
def check_placement(partial_sol, limit_tetris, placement): if limit_tetris[placement['shapeID']] == 0: return False for sq_row, sq_col in utils.generate_shape(placement['shapeID']): row = placement['row'] + sq_row col = placement['col'] + sq_col if partial_sol[row][col] is not None: return False return True
def canitfit(shapeid, pos): shape = utils.generate_shape(shapeid) #print(shape) #print(shapeid) for sq in shape: output = [100, "a", "a"] a = doesitfit2(shapeid, (pos[0] - sq[0], pos[1] - sq[1])) #print (pos[0]-sq[0],pos[1]-sq[1]) #print("does it fit2 returns", a) if a != False and a < output[0]: output = (a, (pos[0] - sq[0], pos[1] - sq[1]), shapeid) return output #Unused at the moment
def shapepos( shapeid, pos ): # takes the shape id and the starting possition and returns a list of the true cordinates output = [] shape = utils.generate_shape(shapeid) for square in shape: testpos = [pos[0] + square[0], pos[1] + square[1]] #getting position of the point of shape output.append(testpos) #if testpos[0] * testpos[1] < 0: # return False Code that used to debug stuff but was not worth it return output
def place_shape_and_update_target_matrix(): shape_id = shape_id_with_lowest_sum_result offsets_of_tiles_in_shape = utils.generate_shape(shape_id) start_coord = first_non_0_coord for tile_offset in offsets_of_tiles_in_shape: updating_target_matrix[start_coord[0] + tile_offset[0]][start_coord[1] + tile_offset[1]] = 0 my_solution_matrix_np[start_coord[0] + tile_offset[0]][start_coord[1] + tile_offset[1]] = ( shape_id, placement_counter)
def shape_id_with_lowest_sum( ): # has no way of breaking the tie between two equal summed shapes lowest_sum_so_far = 9999999999 lowest_shape_id_so_far = 0 for shape_id in list_of_shapes_that_fit_inside_cutout_result: # calculate sum of shape in weight matrix offsets_of_tiles_in_shape = utils.generate_shape(shape_id) shape_sum = 0 for tile_offset in offsets_of_tiles_in_shape: tile_value = value_of_tile_at_offset(first_non_0_coord, tile_offset) shape_sum = shape_sum + tile_value if shape_sum < lowest_sum_so_far: lowest_sum_so_far = shape_sum lowest_shape_id_so_far = shape_id return lowest_shape_id_so_far
def list_of_shapes_that_fit_inside_cutout(): result = [] shape_items = number_of_allowed_shapes.items() for shape_id, number_of_instances_of_shape_allowed in shape_items: if not (first_non_0_value >= shape_origins_values[shape_id] and number_of_instances_of_shape_allowed != 0): continue offsets_of_tiles_in_shape = utils.generate_shape(shape_id) shape_fails_test = False for tile_offset in offsets_of_tiles_in_shape: tile_value = value_of_tile_at_offset(first_non_0_coord, tile_offset) if tile_value <= 0: shape_fails_test = True break if shape_fails_test is False: result.append(shape_id) return result
def identifyCandidateShapes(self, CopyT, height, width, row, column): candidateShapes = [] for m in self.shapeIds: valid = True shape = utils.generate_shape( m ) #import from utils the generate shape which is called by generate target. piece = [[y + row, x + column] for [y, x] in shape] for [r, c] in piece: if r < 0 or c < 0 or r >= height or c >= width: valid = False break #break terminates the current loop and resumes execution at the next statement if CopyT[r][c] == 0: #using boolean conditions. valid = False break if valid == True: candidateShapes.append(m) return candidateShapes
def set_tiles_of_shape_to_0(shape_id, start_coord): shape_rel_coords = utils.generate_shape(shape_id) for coord in shape_rel_coords: weight_matrix[start_coord[0] + coord[0]][start_coord[1] + coord[1]] = 0
def Tetris(target, limit_tetris): tetronimos = [0] + [utils.generate_shape(x) for x in range(1, 20)] width = len(target[0]) # The width of the target matrix height = len(target) solution_matrix = deepcopy(target) total_shapes = 0 for shape in limit_tetris: total_shapes += limit_tetris[shape] for y in range(len(solution_matrix)): for x in range(len(solution_matrix[y])): if not solution_matrix[y][x]: solution_matrix[y][x] = (0, 0) pieceID = 1 for y in range(len(target)): for x in range(len(target[y])): if target[y][x]: biggest_score = 0 best_shape = 0 coord_scores = calc_coord_scores(target, x, y) if coord_scores != {}: results = [] for shapeID in limit_tetris: if limit_tetris[shapeID] > 0: if total_shapes > 2500: weighting = (limit_tetris[shapeID] / total_shapes) else: weighting = 1 weighting = (limit_tetris[shapeID] / total_shapes) shape_score = weighting * score_fit( shapeID, tetronimos, coord_scores) if shape_score > biggest_score: biggest_score = shape_score best_shape = shapeID if biggest_score > 0: pieceID = place(best_shape, x, y, solution_matrix, pieceID, tetronimos, target, limit_tetris) total_shapes -= 1 else: solution_matrix[y][x] = (0, 0) else: solution_matrix[y][x] = (0, 0) #places an block for y in range(len(target)): for x in range(len(target[y])): if target[y][x]: for shapeID in limit_tetris: if limit_tetris[shapeID] > 0: covering = 0 for coord_mod in tetronimos[shapeID]: new_y = y + coord_mod[0] new_x = x + coord_mod[1] if new_y >= 0 and new_x >= 0 and new_y < height and new_x < width: if target[new_y][new_x] and solution_matrix[ new_y][new_x] == (0, 0): covering += 1 if solution_matrix[new_y][new_x] != (0, 0): covering = 0 break else: covering = 0 break if covering >= 3: pieceID = place(shapeID, x, y, solution_matrix, pieceID, tetronimos, target, limit_tetris) break #print('\n'.join([' '.join([str(char) for char in row]) for row in solution_matrix])) return solution_matrix
from copy import deepcopy import utils tetronimos = [0] + [utils.generate_shape(x) for x in range(1, 20)] def calc_coord_scores(target, x, y): neighbors = [[-1, 0], [0, -1], [0, 1], [1, 0]] score = 0 coords_to_check = [(0, 0), (0, 1), (0, 2), (0, 3), (1, -2), (1, -1), (1, 0), (1, 1), (1, 2), (2, -1), (2, 0), (2, 1), (3, 0)] coord_scores = {} checked_coords = [] for coord_mod in coords_to_check: score = 0 y_mod, x_mod = coord_mod cur_y = y + y_mod cur_x = x + x_mod try: if (cur_x < 0) or (cur_y < 0): raise IndexError if target[cur_y][cur_x]: for neighbor in neighbors: try: check_y, check_x = cur_y + neighbor[ 0], cur_x + neighbor[1] if not target[check_y][check_x]: score += 1
def Tetris(target, limit_tetris): # create padded target by adding a buffer of threes all around pad_target = np.pad(target, [3, 3], mode='constant', constant_values=3) pad_height = len(pad_target) pad_width = len(pad_target[0]) solution = [[(0, 0) for col in range(0, pad_width)] for row in range(0, pad_height)] moved_coords = [] one_here = [] #coordinates of ones in pad # find the coordinates of where there are ones in the target for i in range(3, pad_height - 3): for j in range(3, pad_width - 3): if pad_target[i][j] == 1: one_here.append([i, j]) i = 0 x = 0 # add a value of one_here (coordinate e.g. (3,4) to the shape's coordinates in order to change the shape's location while x < len(one_here): for i in limit_tetris: if limit_tetris[ i] >= 1: #if there is that piece in limit tetris continue shapecoords = utils.generate_shape(i) good_place1 = (0 + ((one_here[x][0]))), (0 + ((one_here[x][1]))) l = pad_target[good_place1[0]][good_place1[1]] good_place2 = (shapecoords[1][0] + ((one_here[x][0]))), (shapecoords[1][1] + ((one_here[x][1]))) #adds the coordinate of a block in a shape to where there is a one m = pad_target[good_place2[0]][good_place2[1]] if m == 1: # check if that block also fits in a shape good_place3 = (shapecoords[2][0] + ((one_here[x][0]))), (shapecoords[2][1] + ((one_here[x][1]))) n = pad_target[good_place3[0]][good_place3[1]] if n == 1: good_place4 = (shapecoords[3][0] + ( (one_here[x][0]))), (shapecoords[3][1] + ((one_here[x][1]))) o = pad_target[good_place4[0]][good_place4[1]] if o == 1 and l == 1: moved_coords.append(good_place1) pad_target[good_place1[0]][good_place1[1]] = 2 #two means i've place a piece there instead of just making it empty moved_coords.append(good_place2) pad_target[good_place2[0]][good_place2[1]] = 2 moved_coords.append(good_place3) pad_target[good_place3[0]][good_place3[1]] = 2 moved_coords.append(good_place4) pad_target[good_place4[0]][good_place4[1]] = 2 moved_coords.append(i) del one_here[ x] #faster to include this function for some reason limit_tetris[i] -= 1 x += 1 x = 0 #optimising: # good_place1 = 0 good_place2 = 0 good_place3 = 0 good_place4 = 0 while x < len(one_here): for a in limit_tetris: if limit_tetris[a] >= 1: optimshapes = utils.generate_shape(a) good_place1 = (0 + ((one_here[x][0]))), (0 + ((one_here[x][1]))) l = pad_target[good_place1[0]][good_place1[1]] good_place2 = (optimshapes[1][0] + ((one_here[x][0]))), (optimshapes[1][1] + ((one_here[x][1]))) m = pad_target[good_place2[0]][good_place2[1]] good_place3 = (optimshapes[2][0] + ((one_here[x][0]))), (optimshapes[2][1] + ((one_here[x][1]))) n = pad_target[good_place3[0]][good_place3[1]] good_place4 = (optimshapes[3][0] + ((one_here[x][0]))), (optimshapes[3][1] + ((one_here[x][1]))) o = pad_target[good_place4[0]][good_place4[1]] if (l == 1 and m == 1 and n == 1 and o == 1) or ( l == 1 and m == 0 and n == 1 and o == 1) or (l == 1 and m == 1 and n == 1 and o == 0) or (l == 1 and m == 1 and n == 0 and o == 1): moved_coords.append(good_place1) pad_target[good_place1[0]][good_place1[1]] = 2 #two means i've place a piece there instead of just making it empty moved_coords.append(good_place2) pad_target[good_place2[0]][good_place2[1]] = 2 moved_coords.append(good_place3) pad_target[good_place3[0]][good_place3[1]] = 2 moved_coords.append(good_place4) pad_target[good_place4[0]][good_place4[1]] = 2 moved_coords.append(a) del one_here[ x] #faster to include this function for some reason limit_tetris[a] -= 1 x += 1 x = 0 moved_coords = [ moved_coords[i:i + 5] for i in range(0, len(moved_coords), 5) ] #splits moved coords up into a list of lists, where moved_coords[i] is a list of 4 coordinates and a piece id value # change the (0,0) in solution to place a random piece in piece_idfor j in (0, len(piece_id)): for i in range(0, len(moved_coords)): for j in range(0, 4): solution[moved_coords[i][j][0]][moved_coords[i][j][1]] = ( moved_coords[i][4], i + 1) shrunken_solution = solution[3:-3] shrunken_solution = [i[3:-3] for i in shrunken_solution] return shrunken_solution
def Tetris(target, limit_tetris): ########## SETUP ######### n = 1 #piece ID shapeID = 0 #shapeID J = deepcopy(target) # Array for placing in weights #blank solution: M = deepcopy(target) for i in range(len(M)): for j in range(len(M[0])): M[i][j] = (0, 0) def weighting(): for a in range(len(J)): for b in range(len(J[0])): try: weight = 0 if J[a - 1][b] >= 1: weight += 1 if J[a + 1][b] >= 1: weight += 1 if J[a][b + 1] >= 1: weight += 1 if J[a][b - 1] >= 1: weight += 1 J[a][b] = weight except IndexError: pass ####problem is that have to do "try except" for all if statements - actually probably not? #need to call weighting early in code and then overwrite J with 0s in the place a piece was just placed when placed return J weighting() #setting up J for the first time ##########main loop to place pieces############ ##an approach of going piece by piece finding a spot for each one as you go while not all(value == 0 for value in limit_tetris.values() ): ##loops as long as there are still pieces left to place for key in limit_tetris: #for each type of piece in the dictionary print("Key: {0}".format(key)) if limit_tetris[ key] != 0: #if there's a piece of that type left then... print("Wooo!!! I'm here! The key is {0}. n = {1}.".format( key, n)) print(limit_tetris) shape = utils.generate_shape(key) for i in range(len(M)): #check each space in the grid for j in range(len(M[0])): #check each space in the grid print( "I'm here! The key is {0}, i = {1} and j = {2}. PieceID = {3}. ShapeID = {4}" .format(key, i, j, n, shapeID)) ##if weight =3 if J[i][j] < 3: break if target[i][j] == 1 and limit_tetris[key] != 0: print("I've got here now!") try: # To fix index error if target[i + shape[1][0]][ j + shape[1] [1]] == 1 and target[i + shape[2][0]][ j + shape[2] [1]] == 1 and target[i + shape[3][0]][ j + shape[3] [1]] == 1: #check if the shape fits print( "Results from checking if shape fits: ({0}, {1}), ({2}, {3}), ({4}, {5}), ({6}, {7})" .format(i, j, i + shape[1][0], j + shape[1][1], i + shape[2][0], j + shape[2][1], i + shape[3][0], j + shape[3][1])) if j + shape[1][1] < 0 or j + shape[2][ 1] < 0 or j + shape[2][1] < 0: print("Negative index error") break ###debugging shapeID = limit_tetris[key] ###end of debugging #place shape into M: M[i][j] = (key, n) M[i + shape[1][0]][j + shape[1][1]] = (key, n) M[i + shape[2][0]][j + shape[2][1]] = (key, n) M[i + shape[3][0]][j + shape[3][1]] = (key, n) n += 1 #increase pieceID #remove the 1s from target: target[i][j] = 0 target[i + shape[1][0]][j + shape[1][1]] = 0 target[i + shape[2][0]][j + shape[2][1]] = 0 target[i + shape[3][0]][j + shape[3][1]] = 0 #remove the piece from the limit_tetris print(limit_tetris[key]) limit_tetris[key] = limit_tetris[key] - 1 #replace shape in J with 0s J[i][j] = 0 J[i + shape[1][0]][j + shape[1][1]] = 0 J[i + shape[2][0]][j + shape[2][1]] = 0 J[i + shape[3][0]][j + shape[3][1]] = 0 #redo J with new weightings weighting() except IndexError: pass for i in range(len(J)): print(J[i]) return M
def apply_placement(partial_sol, limit_tetris, placement, piece_id): for sq_row, sq_col in utils.generate_shape(placement['shapeID']): row = placement['row'] + sq_row col = placement['col'] + sq_col partial_sol[row][col] = (placement['shapeID'], piece_id)