💨

claude codeにtesseract書かせてみた

に公開

今回はclaude codeに作らせたシリーズの続編です。前回は3次元のフラクタル図形を書かせてみましたが、今回はtesseractを書かせてみました。

https://zenn.dev/akasan/articles/f90c2940cf1ef3

tesseractとは?

Wikipediaによると、

正八胞体(せいはちほうたい、または四次元超立方体、英語: 8-cell、オクタコロン〈英: octachoron〉、テッセラクト〈英: tesseract、テセラクトとも〉)とは、四次元正多胞体の一種で8個の立方体からなる、四次元の超立方体である。

とのことです。自分の認識では4次元上で立方体からなる謎の図形というイメージです。4次元上の図形なので3次元上で書くと不思議に感じにはなりますが、過去に何度もtesseractの動画をみたことがあったので、claude codeにこれを描画できるか試させてみました。

※ 詳しい説明はできないので、Wikipediaなどで調べてください(すいません)

https://ja.wikipedia.org/wiki/正八胞体

早速書かせてみた

今回claude codeに与えたプロンプトは以下になります。

4次元上の立方体を3次元上で表示するアニメーションをPythonで実装して。uvを使うこと(ただし、uvの初期化は完了しています)

uvを初期化した環境でclaude codeに上記のプロンプトを入れたところ以下のコードを生成しました。

hypercube_4d.py
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from mpl_toolkits.mplot3d import Axes3D
import itertools

class Hypercube4D:
    def __init__(self):
        # 4次元立方体の頂点を生成
        self.vertices_4d = np.array(list(itertools.product([1, -1], repeat=4)))
        
        # エッジの定義(ハミング距離が1の頂点ペア)
        self.edges = []
        for i in range(len(self.vertices_4d)):
            for j in range(i+1, len(self.vertices_4d)):
                # ハミング距離が1の場合はエッジ
                if np.sum(self.vertices_4d[i] != self.vertices_4d[j]) == 1:
                    self.edges.append((i, j))
    
    def rotate_4d(self, angle, plane):
        """4次元回転行列を生成"""
        rotation = np.eye(4)
        c, s = np.cos(angle), np.sin(angle)
        
        if plane == 'xy':
            rotation[0, 0] = c
            rotation[0, 1] = -s
            rotation[1, 0] = s
            rotation[1, 1] = c
        elif plane == 'xz':
            rotation[0, 0] = c
            rotation[0, 2] = -s
            rotation[2, 0] = s
            rotation[2, 2] = c
        elif plane == 'xw':
            rotation[0, 0] = c
            rotation[0, 3] = -s
            rotation[3, 0] = s
            rotation[3, 3] = c
        elif plane == 'yz':
            rotation[1, 1] = c
            rotation[1, 2] = -s
            rotation[2, 1] = s
            rotation[2, 2] = c
        elif plane == 'yw':
            rotation[1, 1] = c
            rotation[1, 3] = -s
            rotation[3, 1] = s
            rotation[3, 3] = c
        elif plane == 'zw':
            rotation[2, 2] = c
            rotation[2, 3] = -s
            rotation[3, 2] = s
            rotation[3, 3] = c
            
        return rotation
    
    def project_4d_to_3d(self, vertices_4d, distance=3):
        """4次元から3次元への透視投影"""
        w = vertices_4d[:, 3]
        scale = distance / (distance - w)
        vertices_3d = vertices_4d[:, :3] * scale[:, np.newaxis]
        return vertices_3d
    
    def project_3d_to_2d(self, vertices_3d, distance=5):
        """3次元から2次元への透視投影(オプション)"""
        z = vertices_3d[:, 2]
        scale = distance / (distance - z)
        vertices_2d = vertices_3d[:, :2] * scale[:, np.newaxis]
        return vertices_2d

class HypercubeVisualizer:
    def __init__(self):
        self.hypercube = Hypercube4D()
        self.fig = plt.figure(figsize=(12, 10))
        self.ax = self.fig.add_subplot(111, projection='3d')
        
        # アニメーション用の角度
        self.angle_xw = 0
        self.angle_yw = 0
        self.angle_zw = 0
        self.angle_xy = 0
        
        # 初期設定
        self.setup_axes()
        
    def setup_axes(self):
        """軸の設定"""
        self.ax.set_xlabel('X')
        self.ax.set_ylabel('Y')
        self.ax.set_zlabel('Z')
        self.ax.set_xlim([-2.5, 2.5])
        self.ax.set_ylim([-2.5, 2.5])
        self.ax.set_zlim([-2.5, 2.5])
        self.ax.set_title('4D Hypercube (Tesseract) Projection to 3D', fontsize=14)
        
    def update(self, frame):
        """アニメーション更新関数"""
        self.ax.clear()
        self.setup_axes()
        
        # 回転角度を更新
        self.angle_xw += 0.01
        self.angle_yw += 0.007
        self.angle_zw += 0.005
        self.angle_xy += 0.003
        
        # 4次元回転を適用
        vertices = self.hypercube.vertices_4d.copy()
        
        # 複数の平面で回転
        rot_xw = self.hypercube.rotate_4d(self.angle_xw, 'xw')
        rot_yw = self.hypercube.rotate_4d(self.angle_yw, 'yw')
        rot_zw = self.hypercube.rotate_4d(self.angle_zw, 'zw')
        rot_xy = self.hypercube.rotate_4d(self.angle_xy, 'xy')
        
        # 回転を連続適用
        vertices = vertices @ rot_xw.T
        vertices = vertices @ rot_yw.T
        vertices = vertices @ rot_zw.T
        vertices = vertices @ rot_xy.T
        
        # 4次元から3次元に投影
        vertices_3d = self.hypercube.project_4d_to_3d(vertices)
        
        # エッジを描画
        for edge in self.hypercube.edges:
            i, j = edge
            x = [vertices_3d[i, 0], vertices_3d[j, 0]]
            y = [vertices_3d[i, 1], vertices_3d[j, 1]]
            z = [vertices_3d[i, 2], vertices_3d[j, 2]]
            
            # エッジの深さに応じて色を変更
            depth = (vertices[i, 3] + vertices[j, 3]) / 2
            color_intensity = (depth + 2) / 4  # 正規化
            self.ax.plot(x, y, z, 'b-', alpha=0.3 + 0.5 * color_intensity, 
                        linewidth=1 + color_intensity)
        
        # 頂点を描画
        self.ax.scatter(vertices_3d[:, 0], vertices_3d[:, 1], vertices_3d[:, 2],
                       c=vertices[:, 3], cmap='coolwarm', s=50, alpha=0.8)
        
        # 情報テキストを追加
        info_text = f'Frame: {frame}\n'
        info_text += f'XW rotation: {self.angle_xw:.2f}\n'
        info_text += f'YW rotation: {self.angle_yw:.2f}\n'
        info_text += f'ZW rotation: {self.angle_zw:.2f}'
        self.ax.text2D(0.02, 0.98, info_text, transform=self.ax.transAxes,
                      fontsize=10, verticalalignment='top',
                      bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
        
        return self.ax.collections + self.ax.lines
    
    def animate(self, interval=50, save_gif=False):
        """アニメーションを開始"""
        anim = FuncAnimation(self.fig, self.update, frames=1000, 
                           interval=interval, blit=False)
        
        if save_gif:
            print("Saving animation as GIF...")
            anim.save('hypercube_4d.gif', writer='pillow', fps=20)
            print("Animation saved as hypercube_4d.gif")
        
        plt.show()
        return anim

def main():
    """メイン実行関数"""
    print("4D Hypercube Visualization")
    print("-" * 40)
    print("Initializing 4D hypercube (tesseract)...")
    print(f"Vertices: 16 (2^4)")
    print(f"Edges: 32")
    print(f"Faces: 24")
    print(f"Cells: 8")
    print("-" * 40)
    
    visualizer = HypercubeVisualizer()
    
    print("Starting animation...")
    print("Controls:")
    print("  - Use mouse to rotate the 3D view")
    print("  - Close window to exit")
    print("-" * 40)
    
    # アニメーションを開始
    anim = visualizer.animate(interval=50, save_gif=True)
    
    return anim

if __name__ == "__main__":
    anim = main()
    plt.show()

コードを見ると、HypercubeVisualizerというクラスに描画関連の機能が実装されており、HypercubeVisualizer.animateを呼び出すと描画されるみたいです。ちなみにGIFに書き出す機能があるのですが、書き出したファイルが大きくZennの上限3MBに思いっきり引っかかる内容でしたので、動画で結果をみてみたい人はご自身の環境でお試しください。

このコードを実行すると、以下のような結果が表示されます。私が過去にtesseractについてみていた動画とおんなじような動画になっていたので、おそらく会っているのだと思います(結果をみてこういうコードを作ることもできるのかと感心しました)。

まとめ

今回はclaude codeにtesseractの描画をさせてみました。3次元のフラクタルとかは作れると思っていましたが、4次元tesseractまでちゃんと描画できるとは思っていなかったので、claude codeに感心しました。これができても実務に影響することは少なくとも自分の場合はないですが、複雑な数学的な描画もできることが確認できたので、もっと色々試してみようと思います。

Discussion