1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【個人開発】壁をぶち抜いて混雑を回避しろ!自律進化型ナビアプリ「DrillRoute」を作ってみた

1
Posted at

はじめに

人混みや渋滞を避けるために、遠回りをした経験は誰にでもあると思います。でも、「いっそ目の前の建物をぶち抜いて直線で進めたら一番早いのに…」と考えたことはありませんか?

そんな願望をブラウザ上でシミュレーションできるアプリ「DrillRoute(ドリルルート)」を開発しました!

image.png

👉 実際に動かしてみる(公開URL)

実はこのアプリの「混雑(赤いエリア)を避けるために、あえて障害物(壁)を破壊して新しい道を切り開く」というギミックは、アニメ『天元突破グレンラガン』の「ドリル」から着想を得ています。
「俺のドリルは天を創るドリルだ!」ならぬ、「俺のドリルは道を創るドリルだ!」の精神で、障害物を粉砕しながら進む気持ちのいいナビゲーションを実装しました。

主な機能と特徴

このアプリでは、マップ上にランダムに「建物(障害物)」と「混雑エリア(赤いモヤ)」が生成されます。目的地(G)をタップして設定し、2つのルート検索を比較して遊べます。

1. 通常ルート(最短距離)

一般的なナビゲーションです。建物(障害物)を正しく迂回しますが、その結果として「大渋滞している赤いエリア」に突っ込んでしまい、通過に多大な時間がかかるルートを提示します。

2. 混雑回避ルート(ドリルモード)

ここで「混雑回避ルートを検索」ボタンを押すと、AIがドリルモード(内部ロジック:SPIRAL戦略)で経路を再計算します。
混雑エリアを絶対に避ける代わりに、ルート上にある建物をドリルで粉砕(マップデータを書き換え)しながら、緑色の光の軌跡とともに新しい道を切り開いていきます。

結果として、距離は遠回りになっても、混雑を避けたことで到着時間が早くなる(あるいは快適に移動できる)というシミュレーションを楽しめます。


技術スタック・実装の工夫点

ReactやVueなどのフレームワークは使わず、HTML / Tailwind CSS / Vanilla JavaScript (Canvas API) の1ファイルのみで構築しています。

特にこだわった「ドリル」のアルゴリズムと、混雑シミュレーションの実装について解説します。

① A* (A-star) アルゴリズムの「コスト」をハックする

経路探索には一般的なA*アルゴリズムを使用していますが、戦略(Strategy)によってノードの重み付け(コスト計算)を極端に変えています。

通常(LINEAR)は壁を通行不可(continue)とし、混雑のコストを少し加算します。
しかし、ドリルモード(SPIRAL)では「壁はコストを払えば通れる」とし、逆に「混雑エリアは絶対に通りたくない(超高コスト)」という設定にしています。

let isWall = mapGrid[nHash] === 1;
let entropy = entropyGrid[nHash]; // 混雑度

let cost = (n.dx !== 0 && n.dy !== 0) ? 1.414 : 1.0;

if (strategy === 'LINEAR') {
    if (isWall) continue; // 壁は絶対に通れない
    cost += entropy * 2;  // 混雑は少し嫌がる
} else if (strategy === 'SPIRAL') {
    if (isWall) {
        cost += 15; // ドリルで壁を壊すコスト(通れる!)
    } else {
        cost += entropy * 50; // 混雑は絶対に避けたい(超高コスト)
    }
}

② 描画時に壁データを本当に破壊する

探索でルートを見つけた後、Canvasにパスを描画してアニメーションさせる際、実際にマップデータ(mapGrid)を上書きして壁を消し飛ばしています。

if (isDrilling) {
    let headIdx = Math.floor(drillProgress);
    let head = currentPath[headIdx];
    let headHash = getHash(head.x, head.y);
    
    // もしルート上に壁があったら
    if (mapGrid[headHash] === 1) {
        mapGrid[headHash] = 0; // 壁を破壊!
        // 飛び散るパーティクル(破片)を生成
        createParticles(head.x * CELL_W + CELL_W/2, head.y * CELL_H + CELL_H/2, '#10b981');
    }
    entropyGrid[headHash] = 0; // 混雑も消し飛ぶ
    // ...
}

この処理により、単に線が引かれるだけでなく「本当に道を切り開いている」という視覚的カタルシスを生み出しています。

③ 熱伝導モデルによる混雑(エントロピー)のシミュレーション

マップ上の赤いモヤ(混雑エリア)は、ただの静的なノイズではありません。
ランダムに配置された発生源から、毎フレーム「熱伝導」のアルゴリズムを応用して、周囲のマスへ徐々に混雑度が広がっていくシミュレーションを行っています。これにより、より生々しい渋滞の様子を表現しています。

// 周囲のセルの混雑度の平均を取ることで、モヤが広がっていく
let sum = entropyGrid[hash]; 
let count = 1;

const neighbors = [[0,-1], [1,0], [0,1], [-1,0]];
for(let n of neighbors) {
    let nhash = getHash(x+n[0], y+n[1]);
    if(mapGrid[nhash] === 0) {
        sum += entropyGrid[nhash];
        count++;
    }
}

let avg = sum / count;
entropyBuffer[hash] = Math.max(0, avg - 0.002); // 少しずつ減衰する

おわりに

「既存の道を辿るだけでなく、自ら道を創る」というグレンラガンのテーマを、経路探索アルゴリズムのコスト計算に落とし込むという試みでした。

現実世界で建物をぶち抜くわけにはいきませんが、アルゴリズムの視点を少し変えるだけで、こんなにもユニークで気持ちのいいアプリが作れます。
スマホのブラウザでもサクサク動くので、ぜひリンクから「ドリルルート」を開拓してみてください!

👉 DrillRoute で道を切り開く

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?