【Rust】木構造(tree)の深さ優先探索(depth-first search)

### 行きがけ順(上から左下へ)
下のような木構造の場合、左から順に 0 -> 1 -> 3 -> 4 -> 2 -> 5 -> 6 と探索していく。
0
1 2
3 4 5 6
これは、再帰処理を行う。

struct Tree {
    node: Vec<[i32; 2]>,
}

fn search(pos: usize) {
    let tree = Tree { node: vec![[1, 2], [3, 4], [5, 6], [7, 8],[9, 10], [11, 12], [13, 14], [0, 0], [0, 0], [0, 0], [0, 0],[0, 0],[0, 0],[0, 0],[0, 0]]};
    println!("{}", pos);
    for i in tree.node[pos] {
        if i != 0 {
            search(i.try_into().unwrap());
        }
    }
}

fn main() {
    search(0);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/rust`
0
1
3
7
8
4
9
10
2
5
11
12
6
13
14

### 帰りがけ順(子ノード優先して上へ)
下のような木構造の場合、左から順に 3 -> 4 -> 1 -> 5 -> 6 -> 2 -> 0 と子ノードから順番に探索していく。一番上が一番最後になる。
0
1 2
3 4 5 6

fn search(pos: usize) {
    let tree = Tree { node: vec![[1, 2], [3, 4], [5, 6], [7, 8],[9, 10], [11, 12], [13, 14], [0, 0], [0, 0], [0, 0], [0, 0],[0, 0],[0, 0],[0, 0],[0, 0]]};
    for i in tree.node[pos] {
        if i != 0 {
            search(i.try_into().unwrap());
        }
    }
    println!("{}", pos);
}

fn main() {
    search(0);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.68s
Running `target/debug/rust`
7
8
3
9
10
4
1
11
12
5
13
14
6
2
0

### 通りがけ順(子ノードから上下上下)
下のような木構造の場合、左から順に 3 -> 1 -> 4 -> 0 -> 5 -> 2 -> 6 と子ノードから順番に探索していく。一番右の子ノードが一番最後になる。
0
1 2
3 4 5 6

fn search(pos: usize) {
    let tree = Tree { node: vec![[1, 2], [3, 4], [5, 6], [7, 8],[9, 10], [11, 12], [13, 14], [0, 0], [0, 0], [0, 0], [0, 0],[0, 0],[0, 0],[0, 0],[0, 0]]};
    if tree.node[pos][0] != 0 && tree.node[pos][1] != 0 {
        search(tree.node[pos][0].try_into().unwrap());
        println!("{}", pos);
        search(tree.node[pos][1].try_into().unwrap());
    } else if tree.node[pos][0] != 0 || tree.node[pos][1] != 0 {
        search(tree.node[pos][0].try_into().unwrap());
        println!("{}", pos);
    } else {
        println!("{}", pos);
    }
}

fn main() {
    search(0);
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.26s
Running `target/debug/rust`
7
3
8
1
9
4
10
0
11
5
12
2
13
6
14

最初のif文では子ノードがあれば左を再帰処理、自信をprintして右を再帰処理
2つ目のif文ではどちらかに子ノードがあれば左を再帰処理
2つ目のif文では子ノードがないので自身をprint

帰りがけは完全に子ノードからボトムアップだが、通りがけは左からツリーを作っていくような順番だ。

Treeの中から一つだけ探したい場合は、幅優先探索が最も早い。
全ての答えを見つける時、決められた深さまで探索する時は、深さ優先探索がよく使われる。

基本ロジックはわかったので、応用編を試してみたいですな。

【Rust】木構造(tree)の幅優先探索(breadth-first search)

幅優先探索は、木構造で横に順番に探索していく。
木構造をプログラムで表現するには、各ノードの下のノードの番号を配列で持つようにする。
例えば 下のような木構造があった場合、
0
1 2
3 4 5 6

0は1, 2を子ノードとして持つので、[1, 2]
1は3, 4を子ノードとして持つので、[3, 4]
2は5, 6を子ノードとして持つので、[5, 6] となる。

use std::collections::VecDeque;

struct Tree {
    node: Vec<[i32; 2]>,
}

fn main() {
    let tree = Tree { node: vec![[1, 2], [3, 4], [5, 6], [7, 8],[9, 10], [11, 12], [13, 14], [0, 0], [0, 0], [0, 0], [0, 0],[0, 0],[0, 0],[0, 0],[0, 0]]};
    
    let mut data: VecDeque<i32> = [0].into();

    while data.len() > 0 {
        let pos = data.pop_front();
        println!("{:?} ", pos.unwrap());
        for i in tree.node[pos.unwrap() as usize] {
            if i != 0 {
                data.push_back(i);
            }
        }
    }
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.24s
Running `target/debug/rust`
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14

ノードのデータの表現の仕方が勉強になりますね。

【Rust】AxumでCSS, JSなどstaticファイルを使いたい時

tower-http = { version = “0.6.2”, features = [“fs”] }

staticフォルダにcssファイルを置きます。
static/styles.css

h1 {
    color:red;
}

template/test.html

<head>
    <title>title</title>
    <link rel="stylesheet" href="styles.css">
</head>
<h1>Hello world</h1>

main.rs

use tower_http::services::{ServeDir, ServeFile};
use axum::{
    routing::get,
    Router,
};

#[tokio::main]
async fn main() {

    let serve_dir = ServeDir::new("static").not_found_service(ServeFile::new("static"));

    let app = Router::new()
        .route("/", get(handle_index))
        .nest_service("/static", serve_dir.clone())
        .fallback_service(serve_dir);

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

async fn handle_index()-> axum::response::Html<String> {
    let tera = tera::Tera::new("templates/*").unwrap();

    let mut context = tera::Context::new();
    context.insert("title", "Index page");

    let output = tera.render("test.html", &context);
    axum::response::Html(output.unwrap())
}

なるほど、これでCSSもjsも自由にコーディングできますね。

【Rust】QRコードの生成

qrcode = “0.14.1”
image = “0.25.5”

use qrcode::QrCode;
use image::Luma;

fn main() {
    let code = QrCode::new(b"https://google.com").unwrap();
    let image = code.render::<Luma<u8>>().build();

    image.save("./data/qrcode.png").unwrap();

    let string = code.render()
        .light_color(' ')
        .dark_color('#')
        .build();
    println!("{}", string);
}

うーん、なるほど…

【Rust】OpenAIの画像生成AIを使ってみる

open ai reference
https://platform.openai.com/docs/api-reference/images/create

なんじゃこりゃ…

use std::io::{stdout, Write};
use curl::easy::{Easy, List};
use dotenv::dotenv;
use std::env;


fn main() {
    let _ = dotenv();
    let auth = format!("Authorization: Bearer {}", &env::var("OPENAI_API_KEY").unwrap());
    let mut list = List::new();
    list.append("Content-Type: application/json").unwrap();
    list.append(&auth).unwrap();
    
    let mut handle = Easy::new();
    handle.url("https://api.openai.com/v1/images/generations").unwrap();
    handle.post(true).unwrap();
    handle.http_headers(list).unwrap();

    let post_field_bytes = "{ \"model\": \"dall-e-3\", \"prompt\": \"A cute baby sea otter\", \"n\": 1, \"size\": \"1024x1024\"}".as_bytes();
    handle.post_fields_copy(post_field_bytes).unwrap();

    handle.write_function(|data| {
    stdout().write_all(data).unwrap();
    Ok(data.len())
    }).unwrap();

    handle.perform().unwrap();

}

Compiling sample v0.1.0 (/home/vagrant/dev/rust/sample)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.58s
Running `target/debug/sample`
{
“created”: 1738034805,
“data”: [
{
“revised_prompt”: “Imagine a charming depiction of a baby sea otter. This adorable little creature is floating on its back in the gentle waves of a clear blue ocean. Its fur, a shade of rich brown, is slick and slightly wet from its playful activities in the water. The otter’s bright, curious eyes are looking directly towards us, as if inviting us to join the fun. It is holding a small, smooth pebble with its tiny paws, perhaps preparing to break open a shell for a feast. The entire image exudes a sense of playfulness, innocence and natural beauty.”,
“url”: “https://oaidalleapiprodscus.blob.core.windows.net/private/org-wo6kkwujqXYOYKEKz5X1nc60/user-JNvegCxXc2nlYJGCjwPgwcv7/img-Z6WR4EMZFstjPwV7BQriTyyf.png?st=2025-01-28T02%3A26%3A45Z&se=2025-01-28T04%3A26%3A45Z&sp=r&sv=2024-08-04&sr=b&rscd=inline&rsct=image/png&skoid=d505667d-d6c1-4a0a-bac7-5c84a87759f8&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2025-01-28T00%3A53%3A13Z&ske=2025-01-29T00%3A53%3A13Z&sks=b&skv=2024-08-04&sig=V2MXStLlOGdaaB7OOT65JzvSFLRA9zOMHOLN8UPOg1o%3D”
}
]
}

面白いんだけど、サービスとして提供するのは抵抗あるな…

【Rust】OpenAIのAPIを使ってみる

APIキーをenvファイルに設定しなければならないので、OSSとして使うのは無理があるな…

use dotenv::dotenv;
use std::env;
use openai_api_rust::*;
use openai_api_rust::chat::*;
use openai_api_rust::completions::*;

fn main() {
    let _ = dotenv();
    let auth = Auth::new(&env::var("OPENAI_API_KEY").unwrap());
    let openai = OpenAI::new(auth, "https://api.openai.com/v1/");
    let body = ChatBody {
        model: "gpt-3.5-turbo".to_string(),
        max_tokens: Some(100),
        temperature: Some(0_f32),
        top_p: Some(0_f32),
        n: Some(2),
        stream: Some(false),
        stop: None,
        presence_penalty: None,
        frequency_penalty: None,
        logit_bias: None,
        user: None,
        messages: vec![Message { role: Role::User, content: "有名なキャラクターは?".to_string() }],
    };
    let rs = openai.chat_completion_create(&body);
    let choice = rs.unwrap().choices;
    let message = &choice[0].message.as_ref().unwrap();
    println!{"{}", message.content};
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.14s
Running `target/debug/sample`
有名なキャラクターには、以下のようなものがあります。

– ミッキーマウス(ディズニーキャラクター)
– マリオ(任天堂のゲーム「スーパーマリオブラザーズ」の主人公)
– ピカチュウ(ポケモンの一匹)

【Rust】envファイルの設定方法

cargo.tomlと同じディレクトリに.envを作成します。

.env

APP_VERSION=1.0.0
APP_PROD=false
dotenv="0.15.0"
use dotenv::dotenv;
use std::env;

fn main() {
    dotenv();
    println!("{}", env::var("APP_VERSION").unwrap());
}

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.28s
Running `target/debug/sample`
1.0.0

なるほどねー

【Rust】二分探索(binary search)

fn main() {
    let data = vec![10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
    let target = 50;
    binary_search(data, target);
    
}

fn binary_search(data: Vec<u32>, target: u32) {
    let mut left = 0;
    let mut right = data.len() - 1;
    
    while left <= right {
        let mid = (left + right) / 2;
        if data[mid] == target {
            println!("ターゲットは要素の[{}]です。", mid);
            break;
        } else if data[mid] < target {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
}

Compiling rust v0.1.0 (/home/vagrant/dev/algorithm/rust)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.13s
Running `target/debug/rust`
ターゲットは要素の[4]です。

これは凄い面白いなあ

【Rust】線形探索

fn main() {
    let target = 40;
    let mut flg = format!("{}{}", target, "はデータの中にありません");
    let data = [50, 30, 90, 10, 20, 70, 60, 40, 80];
    for d in data {
        if d == 40 {
            flg = format!("{}{}", target, "はデータの中にあります!");
        }
    }
    println!("{}", flg);
}

Compiling rust v0.1.0 (/home/vagrant/dev/algorithm/rust)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.56s
Running `target/debug/rust`
40はデータの中にあります!

### 関数を定義
配列だと、data: [u32; 10] というように要素数を指定しなければならないので、Vectorの方が使い勝手が良い。

fn main() {
    let data = vec![50, 30, 90, 10, 20, 70, 60, 40, 80, 55];
    let target = 40;
    linear_search(data, target);
    
}

fn linear_search(data: Vec<u32>, target: u32) {
    let mut flg = format!("{}{}", target, "はデータの中にありません");
    for d in data {
        if d == 40 {
            flg = format!("{}{}", target, "はデータの中にあります!");
        }
    }
    println!("{}", flg);
}

【Blockchain】Walletの比較

人気のWallet比較

### coincheck(pc/mobile)
取引: 総資産、入金出金、購入、売却、送金、受取、積立、大口、NFT, チャート、トレードビュー
アカウント:アカウント変更、本人確認、電話番号、取引履歴、ログイン履歴
ログアウト

### bitcoin wallet(mobile)
btc amount, transaction, send, request, exchange rate, network monitor, block, peer情報

### Trust Crypto Wallet(mobile)
send, receive, buy, earn, crypt, NFT

### bitbank(pc/mobile)
総資産、現物、信用、保有銘柄、お気に入り、ピックアップ、入金、販売所、資産、お知らせ、メニュー、データ(履歴)、登録情報、設定、API

### SafePal wallet(app/hardware)
coin, Delfi, swap, bridge, exchange, market, favorite, deposit, Network

### coinbase wallet
Crypt, NFTs, DeFi,
Buy, swap, bridge, send, receive
Asset, Transaction, Browser, Explore, Setting

### blockchain.com
buy swap sell receive
Asset, price

### 楽天ウォレット
ホーム、運用状況、ニュース、お知らせ、メニュー

大体、どのような機能が必要かはわかりました。QRコードは必要ですね。