【スポンサーリンク】

Pythonで動くハッシュ可視化プログラムを作った

Pythonで動くハッシュ可視化プログラムを作った
\記事が役に立ったらシェアしてね/
【スポンサーリンク】

1. Processingのハッシュ可視化プログラム

Procesing(Pythonモード)で動くハッシュ可視化プログラムを作りました。

コードはPythonで記述しています。

# ハッシュ可視化プログラム

# グローバル変数
input_string = 'apple'
current_char_index = 0
current_hash = 0
animation_state = 0
animation_progress = 0
box_size = 50
char_y = 50
calc_y = 300
text_x = 100
animation_speed = 2
char_pos_x = 0
char_pos_y = 0
pause_timer = 0
current_ascii = 0
current_result = 0

def setup():
    size(800, 600)
    textAlign(CENTER, CENTER)
    textSize(20)
    frameRate(30)

def draw():
    global current_char_index, current_hash, animation_state, animation_progress, animation_speed, char_pos_x, char_pos_y, pause_timer, current_ascii, current_result
    
    background(240)
    
    # 入力文字列の表示
    textAlign(CENTER, CENTER)
    for i, char in enumerate(input_string):
        fill(0)
        rect(50 + i * (box_size + 10), char_y, box_size, box_size)
        fill(255)
        text(char, 50 + i * (box_size + 10) + box_size/2, char_y + box_size/2)
    textAlign(LEFT, BASELINE)
    # 計算式の箱を常に表示
    draw_calculation_boxes()
    
    if current_char_index < len(input_string):
        char = input_string[current_char_index]
        ascii_value = ord(char)
        
        if animation_state == 0:  # 文字をkeyの上に移動
            char_pos_x = lerp(50 + current_char_index * (box_size + 10) + box_size/2, text_x + 240 + box_size/2, animation_progress)
            char_pos_y = lerp(char_y + box_size/2, calc_y - box_size * 2, animation_progress)
            draw_moving_number(char, char_pos_x, char_pos_y)
            
            if animation_progress >= 1:
                animation_state = 1
                animation_progress = 0
        
        elif animation_state == 1:  # 文字をkeyの位置に移動
            char_pos_y = lerp(calc_y - box_size * 2, calc_y, animation_progress)
            draw_moving_number(char, text_x + 240 + box_size/2, char_pos_y)
            if animation_progress >= 1:
                animation_state = 2
                animation_progress = 0
                current_ascii = ascii_value
                if current_char_index <= 3:
                    pause_timer = 15  # (30フレーム/秒の場合)
                else:
                    pause_timer = 0
        elif animation_state == 2:  # ハッシュ計算
            if pause_timer > 0:
                pause_timer -= 1
            else:
                new_hash = ((current_hash * 31) + current_ascii) % 100
            
                if animation_progress < 0.33:
                    current_result = current_hash * 31
                elif animation_progress < 0.66:
                    current_result = current_hash * 31 + current_ascii
                else:
                    current_result = new_hash
                
                if animation_progress >= 1:
                    animation_state = 3
                    animation_progress = 0
                    if current_char_index > len(input_string) - 2:
                        animation_state = 4   
                        current_hash = current_result 
                    elif current_char_index <= 3:
                        pause_timer = 40  # (30フレーム/秒の場合)
                    else:
                        pause_timer = 5 
        elif animation_state == 3:  # 新しいハッシュ値を元の位置に移動
            if pause_timer > 0:
                pause_timer -= 1
            else:
                t = animation_progress
                start_x = text_x + 480 + box_size/2
                end_x = text_x + box_size/2
                control_x = (start_x + end_x) / 2
                
                # 20px下に移動させる
                offset_y = 50
                start_y = calc_y + offset_y
                end_y = calc_y + offset_y
                control_y = calc_y + box_size * 2 + offset_y
                
                x = bezierPoint(start_x, control_x, control_x, end_x, t)
                y = bezierPoint(start_y, control_y, control_y, end_y, t)
                
                draw_moving_number(str(current_result), x, y)
                
                if animation_progress >= 1:

                    current_hash = current_result  # ここで元ハッシュ値を更新
                    current_char_index += 1
                                            
                    animation_state = 0
                    animation_progress = 0
                    
                    if current_char_index >= 3:
                        animation_speed = 6
    
    # テキスト表示
    fill(0)
    textAlign(LEFT, CENTER)
    text("Hash = (Hash * 31 + ASCII) % 100", text_x, 150)
    text("Step: {}".format(animation_state + 1), text_x, 500)
    text("Final Hash: {}".format(current_hash), text_x, 550)
    
    if pause_timer == 0:
        animation_progress += 0.02 * animation_speed

def draw_calculation_boxes():
    fill(0)
    rect(text_x, calc_y, box_size, box_size)  # current hash
    rect(text_x + 120, calc_y, box_size, box_size)  # 31
    rect(text_x + 240, calc_y, box_size, box_size)  # ASCII value
    rect(text_x + 360, calc_y, box_size, box_size)  # 100
    rect(text_x + 480, calc_y, box_size, box_size)  # result
    
    # 演算子と値の表示
    textAlign(CENTER, CENTER)
    textSize(30)
    fill(0)
    text("*", text_x + 80, calc_y + box_size/2)
    text("+", text_x + 200, calc_y + box_size/2)
    text("%", text_x + 320, calc_y + box_size/2)
    text("=", text_x + 440, calc_y + box_size/2)
    
    fill(255)
    textSize(24)  # 定数の文字を小さく
    text(str(current_hash), text_x + box_size/2, calc_y + box_size/2)
    textSize(24)  # 定数の文字を小さく
    text("31", text_x + 120 + box_size/2, calc_y + box_size/2)
    text("100", text_x + 360 + box_size/2, calc_y + box_size/2)
    textSize(24)
    
    # keyの値とASCIIの値を表示
    if animation_state == 1:
        text(input_string[current_char_index], text_x + 240 + box_size/2, calc_y + box_size/2)
    elif animation_state >= 2:
        text(str(current_ascii), text_x + 240 + box_size/2, calc_y + box_size/2)
    else:
        text("?", text_x + 240 + box_size/2, calc_y + box_size/2)
    
    # ASCIIの値を表示
    if animation_state >= 2:
        text(str(current_ascii), text_x + 240 + box_size/2, calc_y + box_size/2)
    
    # 結果の箱に現在の結果を表示
    if animation_state >= 2:
        text(str(current_result), text_x + 480 + box_size/2, calc_y + box_size/2)
    else:
        text("?", text_x + 480 + box_size/2, calc_y + box_size/2)

def draw_moving_number(value, x, y):
    circle_size = 40
    fill(0)
    ellipse(x, y, circle_size, circle_size)
    fill(255)
    text(value, x, y)

def lerp(start, end, t):
    if t<1:
        return start + (end - start) * t
    else:
        return end

2. Claude 3.5に与えた元のプロンプト

Claude 3.5に以下のプロンプトを与えて、プロトタイプを作りました。

ProcessingのPythonモードを使用して、文字列のハッシュ化プロセスを視覚化するアニメーションプログラムを作成してください。

以下はC言語でのhash関数です。

#define TABLE_SIZE 100

unsigned int hash(const char* key) {
    unsigned int hash = 0;
    while (*key) {
        hash = ((hash * 31) + *key) % TABLE_SIZE;
        key++;
    }
    return hash;
}

以下の要件を満たすようにしてください:

  1. 入力文字列 ‘password123’ の各文字を順番に処理します。
  2. ハッシュ関数は (hash * 31 + *key) % 100 を使用します。
  3. 各文字の処理を以下のステップでアニメーション化します:
    画面上部に入力文字が箱に入れて並んでいます。
    また、ハッシュ計算式が下の方にあり、各変数も箱に入れて配置されています(y軸はそろえて配置)。
    その右に計算結果を入れる箱もあります(y軸はそろえて配置)。
    a. 箱から文字が出てきます。 文字を下に移動
    b. ASCII値に変換、変換されたASCIIコードは、数式の*keyの箱の中に移動して置き換えます。
    c. ハッシュ計算の各ステップを表示(初期値、乗算、加算、剰余)このとき各数値を一つずつポップして表示していってください。
    d. 新しいハッシュ値を元の位置に移動、計算結果を計算式のハッシュ値の下まで移動して置き換えます。
  4. テキスト表示(計算式、ステップ説明、最終ハッシュ値)は画面左から220pxの位置に固定します。
  5. 4文字目からは処理速度を3倍に上げます。

ただし、f-string(フォーマット済み文字列)はf”{}”の表記ではなく {}”.format()を使ってください
アニメーションは滑らかで、各ステップが視覚的に理解しやすいものにしてください。

プロンプト

2-1. はじめは対話から

はじめから複雑なプロンプトを考えたわけではなく、まずは無計画に対話して作りたいものを作っていきました。

以下の関数に「apple」を与えたときの計算過程をPythonモードのProcessingで動画化したいです。


unsigned int hash(const char* key) {
    unsigned int hash = 0;
    while (*key) {
        hash = (hash * 31) + *key;
        hash%=100;
        key++;
    }
    return hash % 100;
}

生成されたものに対して、あれこれ希望を伝えていきます。

たとえば、

4文字目からは計算処理のスピードを3倍にしてください。

2-2. プロンプトを整理させて仕切り直し

しかし、たいてい途中で修正の指示が通りにくくなります。
そのタイミングでプロンプトを整理させます。

ここまで作ったプログラムを生成させるための簡潔なプロンプトを考えてください。

ハッシュ関数のビジュアライゼーションを作成するための簡潔なプロンプトを考えました。以下のようになります:

“ProcessingのPythonモードを使用して、文字列のハッシュ化プロセスを視覚化するアニメーションプログラムを作成してください。以下の要件を満たすようにしてください:

  1. 入力文字列 ‘password123’ の各文字を順番に処理します。
  2. ハッシュ関数は (hash * 31 + char) % 100 を使用します。
  3. 各文字の処理を以下のステップでアニメーション化します:
    a. 文字を下に移動
    b. ASCII値に変換
    c. ハッシュ計算の各ステップを表示(初期値、乗算、加算、剰余)
    d. 新しいハッシュ値を元の位置に移動
  4. テキスト表示(計算式、ステップ説明、最終ハッシュ値)は画面左から220pxの位置に固定します。
  5. 4文字目からは処理速度を3倍に上げます。

アニメーションは滑らかで、各ステップが視覚的に理解しやすいものにしてください。”

このプロンプトは、プログラムの主要な機能と要件を簡潔に説明しています。AI開発者や経験豊富なプログラマーであれば、このプロンプトから必要な機能を理解し、適切なコードを生成できるはずです。ただし、細かい実装の詳細や特定の設計上の選択については、追加の質問や指示が必要になる可能性があります。

これを微調整したのがはじめのプロンプトです。
このプロンプトを元に仕切り直してました。

# ハッシュ可視化プログラム

# グローバル変数
input_string = 'password123'
current_char_index = 0
current_hash = 0
animation_state = 0
animation_progress = 0
box_size = 40
char_y = 50
hash_y = 200
ascii_y = 300
result_y = 400
text_x = 220
animation_speed = 1

def setup():
    size(800, 600)
    textAlign(CENTER, CENTER)
    textSize(20)
    frameRate(30)

def draw():
    global current_char_index, current_hash, animation_state, animation_progress, animation_speed
    
    background(240)
    
    # 入力文字列の表示
    for i, char in enumerate(input_string):
        fill(0)
        rect(50 + i * (box_size + 10), char_y, box_size, box_size)
        fill(255)
        text(char, 50 + i * (box_size + 10) + box_size/2, char_y + box_size/2)
    
    if current_char_index < len(input_string):
        char = input_string[current_char_index]
        ascii_value = ord(char)
        
        if animation_state == 0:  # 文字を下に移動
            char_pos = lerp(char_y + box_size/2, ascii_y, animation_progress)
            fill(0)
            text(char, 50 + current_char_index * (box_size + 10) + box_size/2, char_pos)
            
            if animation_progress >= 1:
                animation_state = 1
                animation_progress = 0
        
        elif animation_state == 1:  # ASCII値に変換
            fill(0)
            rect(text_x + 140, ascii_y, box_size, box_size)
            fill(255)
            text(str(ascii_value), text_x + 140 + box_size/2, ascii_y + box_size/2)
            
            if animation_progress >= 1:
                animation_state = 2
                animation_progress = 0
        
        elif animation_state == 2:  # ハッシュ計算
            new_hash = ((current_hash * 31) + ascii_value) % 100
            
            fill(0)
            rect(text_x - 60, hash_y, box_size, box_size)
            rect(text_x + 140, ascii_y, box_size, box_size)
            rect(text_x + 320, result_y, box_size, box_size)
            
            fill(255)
            text(str(current_hash), text_x - 60 + box_size/2, hash_y + box_size/2)
            text(str(ascii_value), text_x + 140 + box_size/2, ascii_y + box_size/2)
            
            if animation_progress < 0.25:
                text("{}".format(current_hash * 31), text_x + 320 + box_size/2, result_y + box_size/2)
            elif animation_progress < 0.5:
                text("{}".format(current_hash * 31 + ascii_value), text_x + 320 + box_size/2, result_y + box_size/2)
            elif animation_progress < 0.75:
                text("{}".format((current_hash * 31 + ascii_value) % 100), text_x + 320 + box_size/2, result_y + box_size/2)
            else:
                text(str(new_hash), text_x + 320 + box_size/2, result_y + box_size/2)
            
            if animation_progress >= 1:
                animation_state = 3
                animation_progress = 0
                current_hash = new_hash
        
        elif animation_state == 3:  # 新しいハッシュ値を元の位置に移動
            hash_pos = lerp(result_y, hash_y, animation_progress)
            fill(0)
            text(str(current_hash), text_x - 60 + box_size/2, hash_pos)
            
            if animation_progress >= 1:
                current_char_index += 1
                animation_state = 0
                animation_progress = 0
                
                if current_char_index >= 4:
                    animation_speed = 3
    
    # テキスト表示
    fill(0)
    textAlign(LEFT, CENTER)
    text("Hash = (Hash * 31 + ASCII) % 100", text_x, 150)
    text("Step: {}".format(animation_state + 1), text_x, 500)
    text("Final Hash: {}".format(current_hash), text_x, 550)
    
    animation_progress += 0.05 * animation_speed

def lerp(start, end, t):
    return start + (end - start) * t

2-3. 再度、修正の作業

ただし、これだけではうまくいきません。
最初の回答は、また細部が荒いです。

これを土台にして、さらに対話しながら完成に向けて調整していきました。

文字だけでなく画像での指示にも対応してくれます。

再度、修正の作業

スクリーンショットに文字を書き込んで画像にして送りました。

徐々に修正して、だいぶイメージ通りになりました。

再度、修正の作業

こちらもどうぞ。
ハッシュ化とは?(かんたんな実装から)
ハッシュ化とは?(かんたんな実装から)
「ハッシュ化」とは、単語や文章などを数値に変換する方法です。 ハッシュ値を索引にデータを保存すると、長い情報も短い数字で表せるのでたくさんの情報を小さなスペースで管理できます。 また、元の文字列には戻せない一方通行の変換ですが、同じ文字列からは同じハッシュ値になるので「照合」に使えます。 ハッシュ関数とハッシュ化、ハッシュ値 「ハッシュ化」とは、'apple'や'password123'といった文字列を、「10」や「63」のような数値に変換する方法です。長い文字列を短い数字で...

子どもにとってのViscuitの魅力(プログラミング学習)
子どもにとってのViscuitの魅力(プログラミング学習)
小学3年生の子どもがプログラミングに興味を示したので、3つの候補(Scratch、Processing、Viscuit)を見せてみました。 子どもが最も興味を示したのは Viscuit。 ルールの小さな変更が大きな変化をもたらすダイナミックさが子どもにとって面白いようで、夢中で遊んでいます。 「自分で作ったルールによって動く世界」。思い通りにならないことも学びにつながるのかも。 YouTube動画でも話しています。 プログラミング言語を選ぶ 最近、小学3年生の子どもが「パソコ...

Claudeの新機能Artifactsを表示できるようにした(Claude 3.5 Sonnet, Feature Preview)
Claudeの新機能Artifactsを表示できるようにした(Claude 3.5 Sonnet, Feature Preview)
Anthropicが新しい人工知能モデル「Claude 3.5 Sonnet」を発表し、その主要機能を紹介しました。 新機能「Artifacts」を使うと、AIが生成したコンテンツをリアルタイムで確認・編集できるようになりました。 Artifactsを表示するには、claude.aiのメニューにある「Feature Preview」から有効にします。 「Claude 3.5 Sonnet is here」というメール Anthropicから「Claude 3.5 Sonnet...
QRコードを読み込むと、関連記事を確認できます。

Pythonで動くハッシュ可視化プログラムを作った
【スポンサーリンク】
タイトルとURLをコピーしました