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; }
以下の要件を満たすようにしてください:
- 入力文字列 ‘password123’ の各文字を順番に処理します。
- ハッシュ関数は (hash * 31 + *key) % 100 を使用します。
- 各文字の処理を以下のステップでアニメーション化します:
画面上部に入力文字が箱に入れて並んでいます。
また、ハッシュ計算式が下の方にあり、各変数も箱に入れて配置されています(y軸はそろえて配置)。
その右に計算結果を入れる箱もあります(y軸はそろえて配置)。
a. 箱から文字が出てきます。 文字を下に移動
b. ASCII値に変換、変換されたASCIIコードは、数式の*keyの箱の中に移動して置き換えます。
c. ハッシュ計算の各ステップを表示(初期値、乗算、加算、剰余)このとき各数値を一つずつポップして表示していってください。
d. 新しいハッシュ値を元の位置に移動、計算結果を計算式のハッシュ値の下まで移動して置き換えます。- テキスト表示(計算式、ステップ説明、最終ハッシュ値)は画面左から220pxの位置に固定します。
- 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モードを使用して、文字列のハッシュ化プロセスを視覚化するアニメーションプログラムを作成してください。以下の要件を満たすようにしてください:
- 入力文字列 ‘password123’ の各文字を順番に処理します。
- ハッシュ関数は (hash * 31 + char) % 100 を使用します。
- 各文字の処理を以下のステップでアニメーション化します:
a. 文字を下に移動
b. ASCII値に変換
c. ハッシュ計算の各ステップを表示(初期値、乗算、加算、剰余)
d. 新しいハッシュ値を元の位置に移動- テキスト表示(計算式、ステップ説明、最終ハッシュ値)は画面左から220pxの位置に固定します。
- 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. 再度、修正の作業
ただし、これだけではうまくいきません。
最初の回答は、また細部が荒いです。
これを土台にして、さらに対話しながら完成に向けて調整していきました。
文字だけでなく画像での指示にも対応してくれます。
スクリーンショットに文字を書き込んで画像にして送りました。
徐々に修正して、だいぶイメージ通りになりました。