ChatGPT -- Embracing the Puzzle
My unyielding quest in cube reconstruction
Puzzles have an inexplicable charm that lures us in, igniting a fire within to conquer their enigmatic challenges, regardless of our skill level. As someone who admits to struggling with puzzles, I find myself irresistibly drawn to new endeavors, driven by the pursuit of discovery and triumph. My latest venture took the form of a cube reconstruction puzzle, a perplexing test of spatial awareness. Even after glimpsing an image of the final solution, I couldn’t resist the allure of attempting to solve this captivating enigma. In this blog post, I’ll share my journey of embracing the cube reconstruction puzzle, with the dynamic Jupyter Notebook as my trusted companion to document my attempts and learn from each failure. If in a hurry, skim to the end
The Enchantment of Puzzles
Puzzles, in all their forms, hold an allure that captivates the human mind. From jigsaw puzzles to Sudoku, each challenge beckons us to explore and uncover the hidden pieces of the puzzle. There’s a unique joy in the act of problem-solving, even when faced with daunting hurdles.
Introducing Jupyter Notebook
When I encountered the cube reconstruction puzzle, I knew I needed a methodical approach to tackle its complexities and keep track of my progress. Jupyter Notebook, with its interactive and flexible environment, emerged as the perfect tool to document my journey.
Jupyter Notebook: My Trusted Puzzle-Solving Companion
Jupyter Notebook offers an intuitive interface that seamlessly blends code, text, and visualizations. Its dynamic nature allows me to experiment with different strategies, visualize the cube’s reconstruction in real-time, and iterate on my attempts.
The Journey Begins: Markdown and Code
With Jupyter Notebook as my digital canvas, I embarked on my cube reconstruction adventure. Markdown allowed me to structure my thoughts and observations, while Python code snippets brought the cube’s reconstruction to life within each cell.
Trials and Errors
Despite having seen an image of the final solution, the cube reconstruction puzzle proved to be an intriguing challenge. My early attempts were met with frustration and repeated failures, but I refused to be discouraged.
Embracing the Learning Process
Each failed attempt became a valuable learning opportunity. Jupyter Notebook served as a repository of insights, encouraging me to analyze my mistakes and identify potential improvements.
The Beauty of Perseverance
With Jupyter Notebook as my faithful companion, I persevered through the intricacies of the cube reconstruction puzzle. I explored different approaches, fine-tuned my strategies, and embraced the beauty of iteration.
Celebrating Small Victories
Though the final solution remained elusive, I celebrated every small victory along the way. Each successfully placed cube piece brought a sense of accomplishment, motivating me to push forward.
Conclusion: Embrace the Puzzle
In conclusion, my journey with the cube reconstruction puzzle has been an ode to the joy of embracing challenges, regardless of expertise. The cube puzzle symbolizes the beauty of the learning process and the determination to conquer the unknown.
Jupyter Notebook proved to be an invaluable tool, guiding me through the complexities of the cube reconstruction puzzle and documenting my exploration. Its dynamic environment allowed me to adapt, grow, and relish the experience.
So, if you find yourself irresistibly drawn to a puzzle, even if you consider yourself bad at it, I encourage you to embrace the challenge. Let Jupyter Notebook be your trusted ally, guiding you through the maze of puzzle-solving with curiosity and perseverance.
Remember, the journey itself is a triumph, and every puzzle is an opportunity for growth and discovery.
Happy puzzle-solving!
The text above is the answer from ChatGPT prompted with:
“Make a blog post explaining how I cannot stop myself to try solving a puzzle even though I am quite bad at it. My latest fail: a cube reconstruction puzzle (even after seeing an image of the final solution). Introduce a Jupyter notebook.”
For the Python code ChatGPT has needed quite a bit of coaxing and even then, I could only use the answers for inspiration.
import numpy as np
from itertools import product
import plotly.graph_objects as go
from functools import reduce
import plotly.io as pio
pio.renderers.default='notebook'
# representation of the pieces in 3D as a colection of 4 or 5 cubes
# each piece is a 4x3 or 5x3 numpy matrix (useful for computing rotations and positions)
npieces=[np.array(p) for p in
[[[0,0,0],[1,0,0],[1,1,0],[1,-1,0]],
[[0,0,0],[0,1,0],[1,0,0],[2,0,0]],
[[0,0,0],[0,-1,0],[1,0,0],[1,0,1]],
[[0,0,0],[1,0,0],[1,1,0],[1,-1,0],[0,0,1]],
[[0,0,0],[1,0,0],[1,1,0],[1,-1,0],[1,1,1]],
[[0,0,0],[0,-1,0],[1,0,0],[1,1,0],[1,0,1]]]]
# Rotation about X-axis (90 degrees)
rotation_x_90_matrix = np.array([[1, 0, 0],
[0, 0, -1],
[0, 1, 0]])
# Rotation about Y-axis (90 degrees)
rotation_y_90_matrix = np.array([[0, 0, 1],
[0, 1, 0],
[-1, 0, 0]])
# Rotation about Z-axis (90 degrees)
rotation_z_90_matrix = np.array([[0, -1, 0],
[1, 0, 0],
[0, 0, 1]])
# make a list with all orientations (18) and all possible positions (27)
rotations = []
coordinates=[]
for (i,j,k) in product(range(3),repeat=3):
coordinates.append(np.array([i,j,k]))
m=np.dot(np.linalg.matrix_power(rotation_x_90_matrix, i),np.linalg.matrix_power(rotation_y_90_matrix, j))
m=np.dot(m,np.linalg.matrix_power(rotation_z_90_matrix, k))
rotations.append(m)
rotation_matrices = np.array(rotations)
rotation_matrices = np.unique(rotation_matrices, axis=0)
# acceptable coordinates of pieces
# for each piece a number of rotated and moved configurations (positions) are constructed
# only pieces and positions that stay inside a cube of side 3 are accepted
configs=[[c for cc in coordinates for c in g+cc if not np.any(c<0) and not np.any(c>2)]
for g in [np.transpose(np.dot(rotation_matrices,pi.T),(0,2,1)) for pi in npieces]]
# The first piece is not rotated, only moved. This eliminates equivalent solutions
configs[0]=[c for cc in coordinates for c in [npieces[0]]+cc if not np.any(c<0) and not np.any(c>2)]
# The positions of individual cubes are transformed to tuples (in order to check for overlaps using set operations)
tconfigs=[[[tuple(poz.tolist()) for poz in conf] for conf in piece] for piece in configs]
print('Numbers of acceptable positions for each piece:' )
print([len(c) for c in tconfigs],' In total ', '{:,}'.format(reduce(lambda x, y: x * y, [len(c) for c in tconfigs])))
Numbers of acceptable positions for each piece: [6, 108, 144, 72, 72, 72] In total 34,828,517,376
# simple backtracking
def back(cubes,level,solution):
if level==6:
print('Solution:')
for piece in solution:
print(piece)
print('\n')
solutions.append(solution)
else:
for config in tconfigs[level]:
g=cubes+config
# at each step we advance if there is no overlap
if len(set(g))==len(g):
back(g,level+1,solution+[config])
solutions=[]
back([],0,[])
Solution: [(0, 1, 2), (1, 1, 2), (1, 2, 2), (1, 0, 2)] [(0, 2, 0), (0, 1, 0), (0, 2, 1), (0, 2, 2)] [(2, 0, 1), (1, 0, 1), (2, 0, 2), (2, 1, 2)] [(1, 1, 0), (2, 1, 0), (2, 2, 0), (2, 0, 0), (1, 1, 1)] [(0, 1, 1), (0, 0, 1), (0, 0, 0), (0, 0, 2), (1, 0, 0)] [(1, 2, 1), (1, 2, 0), (2, 2, 1), (2, 2, 2), (2, 1, 1)]
print("The reconstructed cube with each piece made of spheres of different colors")
print("Remark the L shaped piece in red")
fig = go.Figure()
for centers,color in zip(solutions[0],['blue','red','green','yellow','magenta','black']):
fig.add_trace(go.Scatter3d(
x=[c[0]+.5 for c in centers],
y=[c[1]+.5 for c in centers],
z=[c[2]+.5 for c in centers],
mode='markers',
marker=dict(
size=70,
symbol='circle',
# opacity=0.9,
line=dict(width=1, color=color),
colorscale='Viridis', # You can change the colorscale if desired
)
))
# Set layout for the plot
fig.update_layout(
scene=dict(aspectmode='cube'),
scene_camera=dict(eye=dict(x=-1.8, y=-1.8, z=-0.4)), # Adjust the camera position
width=600,
height=600,showlegend=False,
scene_xaxis_showticklabels=False, # Remove x-axis labels
scene_yaxis_showticklabels=False, # Remove y-axis labels
scene_zaxis_showticklabels=False,
)
# Show the plot
fig.show()