import pprint import operator import numpy as np import math from copy import copy, deepcopy import profile piece=[[0,0,0],[0,1,0],[0,2,0],[0,3,0],[1,2,0]] sizeofcube=5 def init_cube(size=sizeofcube): return [[[0 for x in range(0,size)] for y in range(0,size)] for z in range(0,size)] def move_start_position(piece,index): return [np.subtract(x, piece[index]) for x in piece] def draw_cube(cube): from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt fig = plt.figure() ax = fig.gca(projection='3d') ax.set_aspect('equal') ax.set_xlabel('x', fontsize=10) ax.set_ylabel('y', fontsize=10) ax.set_zlabel('z', fontsize=10) ma=np.array(cube) ax.voxels(ma, edgecolor="k") plt.show() def set_cube_vals(cursors,cube,value): for cursor in cursors: cube[cursor[0]][cursor[1]][cursor[2]]=value def is_valid(piece,position): global sizeofcube upper_x=sizeofcube-position[0] upper_y=sizeofcube-position[1] upper_z=sizeofcube-position[2] for (x,y,z) in piece: if x<-position[0] or x>upper_x: return False if y<-position[1] or y>upper_y: return False if z<-position[2] or z>upper_z: return False return True def put_piece_in_cube(piece,cube,position,index): if is_valid(piece,position): # cursors = [np.add(position,p) for p in piece] # for cursor in cursors: cursors=[] for (x,y,z) in piece: cursor=[(x+position[0]),(y+position[1]),(z+position[2])] cursors.append(cursor) try: if cube[cursor[0]][cursor[1]][cursor[2]]!=0: return False except: return False set_cube_vals(cursors, cube, index) return True else: return False def remove_piece_in_cube(piece,cube,position): cursors = [np.add(position,p) for p in piece] set_cube_vals(cursors, cube, 0) def rotate_vector(vector,axis,angle): x,y,z=vector angle=math.radians(angle) if axis == "z": return (int(round((x*math.cos(angle)) - (y*math.sin(angle)))),int(round((x*math.sin(angle)) + (y*math.cos(angle)))),z) if axis == "y": return (int(round(x*math.cos(angle) + z*math.sin(angle))),y,int(round(-x*math.sin(angle) + z*math.cos(angle)))) if axis == "x": return (x,int(round(y*math.cos(angle) - z*math.sin(angle))),int(round(y*math.sin(angle) + z*math.cos(angle)))) def rotate_piece(piece,axis,angle): return [rotate_vector(x, axis, angle) for x in piece] def shift_piece(piece,anchor_index): anchor=piece[anchor_index] return [np.subtract(p,anchor) for p in piece] def generate_rotations(piece): all_rotations=set() for i in range(0,4): for j in range(0,4): for k in range(0,4): for p in range(0,len(piece)): rotated_piece=rotate_piece(rotate_piece(rotate_piece(shift_piece(piece,p),"x",k*90),"y",j*90),"z",i*90) all_rotations.add(tuple(rotated_piece)) return frozenset(all_rotations) def find_empty_spot(cube): for z in range(0,sizeofcube): for y in range(0,sizeofcube): for x in range(0,sizeofcube): if cube[x][y][z]==0: return (x,y,z) return None def printstats(): global stat_counter global stats stat_counter=stat_counter+1 if stat_counter%10000==0: print(stat_counter) for x in stats: print("{}:{}".format(x,stats[x])) if x>5: break def parallel_pool_init(): global stats global solutions stats=dict() solutions=list() def parallel_solve(cube): global all_rotations all_rotations=generate_rotations(piece) pieces=set(all_rotations.copy()) first_position=(0,0,0) while len(pieces)>0: piece=pieces.pop() if put_piece_in_cube(piece, cube, first_position, index): solve(cube, 2,): def solve(cube,index): global stats global solutions global all_rotations pieces=set(all_rotations.copy()) # print("{}:find empty spot#########################".format(index)) empty_pos=find_empty_spot(cube) if empty_pos==None: pprint.pprint(cube) draw_cube(cube) solutions.append(cube) return False else: (x,y,z)=empty_pos while len(pieces)>0: #use copy of cube without my parts piece=pieces.pop() if put_piece_in_cube(piece, cube, (x,y,z), index): # print("{}:found fitting piece {} ({} left)".format(index,piece,len(pieces))) stats[index]=len(pieces) if solve(cube, index+1): return True else: remove_piece_in_cube(piece, cube, (x,y,z)) #nothing fits return fail return False # maxindex=0 # stat_counter=0 # stats=dict() # last_stats=dict() def main(): parallel_solve(init_cube()) if __name__ == '__main__': # profile.run('main()') main()