100日アプリ開発チャレンジ Day15 - ソートアルゴリズム可視化で「見える化」の力を知った
Day15、学習ツールと向き合った日
100日チャレンジDay15。
今日作ったのは、ソートアルゴリズムの可視化ツール。
そして今日、気づきました。
「見える化が、理解を生む」
ゲームじゃない。教育ツール。でも、これが一番面白かった。


折れそうになった瞬間
今日は、最初から迷ってました。
「何を作ろう」
Day10-14:シンプルなゲーム路線
でも、そろそろ変化が欲しい。
選択肢は3つ
A. また新しいゲーム
安全
でも、飽きてきた
B. 複雑なゲーム
挑戦的
でも、Day9の将棋がトラウマ
C. 全く違うもの
新鮮
でも、何作る?
朝、2時間悩んだ
「何か作りたいけど、何も思いつかない」
これが、一番辛い。
手が動かない。
コード書く気力がない。
「もう休もうかな...」
ここで、折れそうになりました。
でも、思い出しました。
Day9の将棋、何が辛かったか。
「終わりが見えない」
これが辛かった。
じゃあ、今日は:
「終わりが見えるもの」を作ろう。
迷った判断
迷い1:何を可視化するか
可視化ツール、作ることにしました。
でも、何を可視化する?
選択肢A:データ分析ツール
CSVを読み込んで、グラフ化
実用的
でも、地味
選択肢B:ソートアルゴリズム
バブルソート、クイックソートなど
動きがある
学習に使える
選択肢C:物理シミュレーション
重力、衝突など
見た目が面白い
でも、複雑
判断理由
ソートアルゴリズムを選びました。
理由は3つ:
終わりが明確
ソートが終われば、完成
無限ループにならない
4種類実装できる
バブル、選択、挿入、クイック
バリエーションがある
自分も学べる
アルゴリズムを理解できる
作りながら勉強できる
「作りながら学ぶ」
これが、決め手でした。
迷い2:ステップ実行か、一気にソートか
選択肢A:一気にソート
def bubble_sort(array):
for i in range(len(array)):
for j in range(len(array) - i - 1):
if array[j] > array[j + 1]:
array[j], array[j + 1] = array[j + 1], array[j]
シンプル
でも、途中経過が見えない
選択肢B:ステップ実行
def bubble_sort_step():
# 1ステップだけ実行
# 状態を保存
# 次回続きから
複雑
でも、途中経過が見える
判断理由
ステップ実行を選びました。
可視化ツールなのに、途中が見えないのは意味がない。
「見える化」が目的。
ステップ実行なら、アルゴリズムの動きが見える。
どこを比較してるか。
どこがソート済みか。
これが、学習ツールの価値。
続けるために決めたこと
決断1:完璧を目指さない
4つのソートアルゴリズム。
全部完璧に実装しようとしたら、終わらない。
だから、決めました。
「動けばOK。最適化は後で」
バブルソートから始めて、1つずつ。
動いたら、次へ。
完成を優先。
決断2:「作りながら学ぶ」を受け入れる
ソートアルゴリズム、全部理解してたわけじゃない。
特に、クイックソート。
「わからないから、作らない」じゃなくて。
「作りながら、理解する」
これを受け入れました。
わからないことは、調べる。
試す。
動かす。
作ることが、学びになる。
決断3:教育ツールとしての価値を意識
ゲームじゃない。
でも、これは**「学習ツール」**として価値がある。
プログラミングを学ぶ人の役に立つかもしれない。
「誰かの役に立つかも」
この意識が、モチベーションになりました。
実装で苦労したところ
1. ステップ実行の状態管理
一番難しかったのは、これ。
def bubble_sort_step():
global sort_state
if 'current_index' not in sort_state:
sort_state = {'current_index': 0, 'compare_index': 0, 'swapped': False}
ci = sort_state['current_index']
coi = sort_state['compare_index']
# 1ステップだけ実行
if coi < len(array) - ci - 1:
if array[coi] > array[coi + 1]:
array[coi], array[coi + 1] = array[coi + 1], array[coi]
sort_state['swapped'] = True
sort_state['compare_index'] += 1
return [coi, coi + 1], list(range(len(array) - ci, len(array)))
状態を保存しないと、続きができない。
どこまで比較したか。
どこまでソート済みか。
これを sort_state に保存。
次回呼ばれたとき、続きから再開。
これが、ステップ実行の本質。
2. クイックソートのスタック管理
クイックソートは、再帰アルゴリズム。
でも、ステップ実行には再帰が使えない。
だから、スタックで管理。
def quick_sort_step():
if 'stack' not in sort_state:
sort_state = {
'stack': [(0, len(array) - 1)],
'current_partition': None,
'pivot_index': None,
'i': None,
'j': None,
'sorted_indices': set()
}
stack = sort_state['stack']
if not stack:
# 全部ソート完了
sorting = False
return
# スタックから次のパーティションを取り出す
low, high = stack.pop()
再帰をスタックで模倣。
これ、理解するのに1時間かかりました。
でも、理解できたとき、「あ、そういうことか!」って。
作りながら、学びました。
3. 色分けの設計
どこを比較してるか、一目でわかるように。
def draw_array(highlight_indices=None, sorted_indices=None, pivot_index=None):
for i, value in enumerate(array):
# 色を決定
if i == pivot_index:
color = PURPLE # ピボット(クイックソート用)
elif i in sorted_indices:
color = GREEN # ソート済み
elif i in highlight_indices:
color = RED # 比較中
else:
color = BLUE # 未ソート
色で、状態を伝える。
青:未ソート
赤:比較中
緑:ソート済み
紫:ピボット(クイックソート)
視覚的にわかる。
これが、可視化ツールの価値。
4. 4つのアルゴリズムの統一
def sort_step():
"""現在のアルゴリズムに応じてソートステップを実行"""
algo = ALGORITHMS[current_algorithm]
if algo == "Bubble Sort":
return bubble_sort_step()
elif algo == "Selection Sort":
return selection_sort_step()
elif algo == "Insertion Sort":
return insertion_sort_step()
elif algo == "Quick Sort":
return quick_sort_step()
4つのアルゴリズム、同じインターフェース。
どれも sort_step() で呼べる。
統一されたAPI。
これで、メインループがシンプルになりました。
開発者視点の裏話
なぜ4つのアルゴリズムを選んだのか
バブルソート:基本中の基本 選択ソート:シンプルでわかりやすい 挿入ソート:実用的 クイックソート:高速、でも複雑
段階的に難易度が上がる。
初心者は、バブルソートから理解できる。
上級者は、クイックソートの美しさがわかる。
幅広い層に対応。
なぜFPS 60にしたのか
FPS = 60
clock.tick(FPS)
60フレーム/秒。
これより速いと、見えない。
これより遅いと、待てない。
60FPSが、ちょうどいい。
なぜ棒グラフで表現したのか
ソートアルゴリズム、数値の並び替え。
高さで大小を表現。
視覚的に、一瞬でわかる。
数字で「45, 32, 78...」って見るより、
棒グラフの方が、圧倒的にわかりやすい。
「見える化」の力。
なぜ凡例を入れたのか
# カラー凡例
pygame.draw.rect(screen, BLUE, (20, legend_y, 15, 15))
screen.blit(tiny_font.render("Unsorted", True, BLACK), (40, legend_y))
pygame.draw.rect(screen, RED, (130, legend_y, 15, 15))
screen.blit(tiny_font.render("Comparing", True, BLACK), (150, legend_y))
色の意味、わからないと混乱する。
凡例があれば、誰でもわかる。
教育ツールだから、親切設計。
開発時間:約5時間
アルゴリズム設計:1.5時間
ステップ実行実装:2時間
可視化・UI:1時間
デバッグ:0.5時間
クイックソートが一番時間かかりました。
でも、理解できたとき、達成感がすごかった。
今日の学び
技術面
ステップ実行の状態管理
再帰をスタックで模倣
グローバル状態の活用
色分けによる視覚化
統一されたAPI設計
アルゴリズム面
バブルソートの仕組み
選択ソートの効率
挿入ソートの実用性
クイックソートの美しさ
設計面
教育ツールの設計思想
親切なUI(凡例、操作説明)
段階的な難易度設計
視覚的フィードバック
メンタル面
「作りながら学ぶ」を受け入れる
終わりが見えるものを選ぶ
完璧を目指さない
教育ツールとしての価値
Day15を終えて
今日、気づきました。
「見える化が、理解を生む」
ソートアルゴリズム、教科書で読んでもピンと来なかった。
でも、動いてるのを見たら、わかった。
「ああ、こうやって並び替えてるのか」
これが、可視化の力。
そして、気づいたこと。
ゲームじゃなくても、面白い。
今日作ったのは、ゲームじゃない。
教育ツール。
でも、これが一番面白かった。
アルゴリズムが、動いてる。
クイックソートのピボットが、左右に振り分けていく。
バブルソートの大きい値が、右に浮いていく。
美しい。
これまで、「ゲーム」ばかり作ってました。
でも、今日気づきました。
「ツール」も、面白い。
誰かの学びに、役立つかもしれない。
自分も、作りながら学べる。
作ることが、学びになる。
Day15、新しい扉が開きました。
ゲームだけじゃない。
ツール、可視化、教育。
作れるものは、無限にある。
今日のコード行数: 320行
開発時間: 約5時間
実装したアルゴリズム: 4種類
学んだこと: クイックソートの美しさ
達成感: ★★★★★
「作りながら学ぶ」実感: ★★★★★
「見える化の力」実感: ★★★★★
100日チャレンジ、Day16に続く。
(見える化が、理解を生む。作ることが、学びになる。)
完全版コード
引き続き、最初の30日間はコードを直接貼り付けていきます。
import pygame
import random
# 初期化
pygame.init()
# 画面設定
WIDTH = 900
HEIGHT = 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Sorting Algorithm Visualization")
# 色定義
BLUE = (100, 150, 255) # 未ソート
RED = (255, 100, 100) # 比較中
GREEN = (100, 255, 100) # ソート済み
PURPLE = (200, 100, 255) # ピボット
# ソートアルゴリズム
ALGORITHMS = ["Bubble Sort", "Selection Sort", "Insertion Sort", "Quick Sort"]
def bubble_sort_step():
"""バブルソートの1ステップ"""
# 状態を保存して、次回続きから
def selection_sort_step():
"""選択ソートの1ステップ"""
def insertion_sort_step():
"""挿入ソートの1ステップ"""
def quick_sort_step():
"""クイックソートの1ステップ"""
# 再帰をスタックで模倣
# ... 以下省略(全320行)
# 完全版が見たい方はコメントでリクエストください!
#100日チャレンジ #プログラミング #アルゴリズム #Python #Pygame #ソートアルゴリズム #可視化 #教育ツール #初心者エンジニア
