2015,江端さんの忘備録

(昨日の続きです)

(Continuation from yesterday)

視覚に訴える媒体(ここでは「デザイン」という)のパワーは恐るべきものがあります。

I believe the media based on visualization, calling it "design" in this diary, is awful.

■まず、第一に、デザインが圧倒的に購買意欲を支えているという事実があります。

Firstly, "design" appeals to "eagerness to buy" strongly.

私がどんなに機能が優れていることを説明しても、嫁さんや娘達は、自分の気に入ったデザインの自動車や携帯電話から、ブレることはありませんでした。

My wife and daughters had never accepted my persuasion that they should select productions, like automobiles and cell phones, to view the functions.

私はこの時、私たちエンジニアが命懸けで開発している「機能」という価値が、「デザイン」という価値には、遠く及ばないことを、魂のレベルで理解したのです。

At that time, I could understand profoundly that the value of "functions" is inferior to the value of "design," even if our engineers struggle to develop new good functions.

私は、MACやiPod/iPADのデザインやインターフェースが好きではありませんが、私が少数派であることは、明らかなことです。

I wouldn't say I like the designs and the interface of MAC or iPod/iPad, though it is obvious that I am in a minority group.

■第二に、デザインは、世界共通言語であるという事実があります。

Secondly, "design" is an international communication language.

「英語に愛されないエンジニア」であるこの私でさえ、海外赴任や出張をしてこれたのは、世界中にホワイトボードがあり、そして、メモ用紙があったからです。

I have gone on business trips worldwide, though I am a typical "loveless engineer from English" because I can use paper and whiteboard.

"□"と"→"さえ書ければ、「この世界の全ての事象は表現できる」と思っています。

I can explain "the world" by drawing rectangles and arrows.

■第三に、(これはエンジニア特有の話になりますが)デザインが、工学的アプローチに必須のアイテムであるという事実があります。

Thirdly (this might be for engineers only), "design" is indispensable for the engineering approach.

絵が含まれていないプレゼンテーション資料なんぞ、誰にも読んで貰えません。

Nobody wants to read a presentation material with pictures.

また、図面を含まない特許明細書は、多くの場合、特許庁の審査官から拒絶査定を喰らいます。

In many cases, patent applications without a picture are rejected by the Patent Office Board of Appeals.

それは、「発明が劣っている」からではなく「審査官が発明を理解するのが難しくなる」からです。

It is not for "poor invention" but for "hard to be understood by examiners."

それと、自分のアイデアを、デザインレベルで具現化できる、ということは、そのアイデアが「完成している」ということの証明になります。

Moreover, the "possibility to realize my idea as a design" proves my idea's completion.

-----

ところが、この「デザインを舐めている」エンジニアや研究者が、結構な数いるんですよ。

However, I am afraid that many engineers and researchers make little of this design power.

(続く)

(To be continued)

2024,江端さんの忘備録

今回の地震の第1報で、私の中に最初に出てきた記憶が「スキップとローファー」でした。

The first memory that came to my mind at the first report of this earthquake was "Skips and Loafers."

今回の被災地には、私の親戚も思い当たる友人もいないのですが、それと同等、あるいはそれ以上に、コミックの登場人物を現在被災している方々に重ねて、思いを馳せる ――

I have no relatives or friends in the disaster area; however, I come to overlap the characters in the comic and the people who are currently suffering from the disaster.

これは、不謹慎なことではないと、私は思う(そう信じる)。

This is not inappropriate, I think (and believe).

『自分が何をしなければならないか、ようやく気がついた時、それは、非常に小さくて基本的なものであった』

2024,江端さんの忘備録

世界的に有名なアルゴリズムの改良版を考えていました。

Last night, I contemplated an improved version of the world-famous algorithm, which I believe is the most popular and effective.

しかし、先行研究を調べても、私の考えと同じん内容の論文が出てこなくて、不思議に思っていました。

However, I wondered why I could not find any papers describing the same ideas as mine when I checked the previous studies.

―― もしかして、私が世界初?

"Perhaps I am the first in the world?"

もしそうなら、『これで、1本(の論文)稼げた!』てなことを考えていました。

If so, "Now I've earned one (thesis)!" I thought to myself.

-----

まいったなぁ。

Oh, man.

これから、『江端法』なんて名前が付くアルゴリズムが世界で使われるようになるのかなぁ。

I wonder if algorithms with names like the "Ebata Method" will be used.

自己紹介の時に、「あの『江端法』の江端です」なんて、言わなくちゃならないのかなぁ。

I wonder if I have to say, "I am Ebata of that 'Ebata Method'" when I introduce myself.

偉そうに聞こえないように、言い方をちょっと工夫しなければ。

I have to be a little creative in how I say it so that I don't sound like a pompous ass.

などと考えながら、コーディングをしていたのですが、

I was coding, thinking about things such as the above.

『あれ? コスト値が状態に対して変動的であったとしても、従来法がそのまま適用できるんじゃないか?』

'Huh? Even if cost values were variable for the state, wouldn't the conventional method still apply?'

と気がついたのは、朝の5時でした。

I realized that it was 5:00 in the morning.

-----

1時間を稼ぐのに、ゼーゼー言っている最中に、この「頭脳をフル回転させながら、失なった無意味な数時間」は ――

While heaving to earn an hour, these "meaningless hours lost while racking your brains at full speed"--

死ぬほど痛い。

Hurts to death for me.

 

時間のない中での、こういう一日は ―― 本当に痛い。

 

2024,江端さんの技術メモ

運行情報(ダイヤグラム)を反映した最短時間で到着する計算方法は、通常のダイクストラ法を拡張して実行することができます。以下は、ダイヤ情報を考慮する最短到着時間を計算する一般的なアプローチです:

  1. グラフの作成:
    • ダイヤグラムに基づいて、駅間の接続を表すグラフを作成します。各エッジ(駅間の接続)には、所要時間が含まれます。
    • グラフのノードは駅を表し、エッジの重みは駅間の移動にかかる時間です。
    • 通常のダイクストラ法と同様に、出発駅を始点としてグラフを探索します。
  2. ノードの拡張と更新:
    • 通常のダイクストラ法と同様に、出発駅から各駅への最短到着時間を記録するデータ構造を使用します。初期状態では、出発駅の最短到着時間を0に設定し、他の駅は無限大(無効値)とします。
    • プライオリティキューを使用して、最短到着時間が最小の駅を選択します。
  3. ダイヤ情報の適用:
    • 選択した駅から出発するエッジを調べ、ダイヤ情報を考慮して最短到着時間を計算します。
    • ダイヤ情報には、駅への到着時間や運行間隔などが含まれます。現在の到着時間とダイヤ情報を使用して、次の駅への最短到着時間を計算します。
    • 新しい到着時間が現在の最短到着時間よりも短い場合、その駅の最短到着時間を更新します。
  4. プライオリティキューから次の最短到着時間の駅を選択し、ステップ3を繰り返します。目的の駅に到達した場合、計算を終了します。
  5. 最短到着時間を使用して、目的の駅への最短経路を復元します。

このアプローチを使用すると、ダイヤ情報を反映した最短到着時間を計算できます。ダイヤ情報は、駅への到着時間や運行間隔を正確に取得し、計算に組み込む必要があります。また、プライオリティキューの実装や適切なデータ構造の設計も重要です。

2024,江端さんの技術メモ

/* 
   簡易バスダイヤ作成プログラム    c:\users\ebata\dummy1.go

   (1)バス路線があり、5つの停留所("A0", "A1", "A2", "A3", "A4", "A5")があります。
   (2)このバスは始点から運行を開始し、路線の終点でで一定時間停車した後、再び逆方向に運行を開始します。
   (3)バスは朝6時に出発して、5分単位で次の停留所で停止し、終端で10分間停止します。
   (4)これを3往復するものとします。

*/



package main

import (
	"fmt"
	"strings" // strings パッケージをインポート
	"time"
)

// バスのダイヤグラム
type BusSchedule struct {
	Route             []string             // 停留所のリスト
	DepartureTime     time.Time            // 出発時刻
	ArrivalTimeStops  map[string][]string // 各停留所の到着時刻
	ArrivalTimeRounds int                  // 往復回数
}

// バスのダイヤグラムを生成する関数
func GenerateBusSchedule(route []string, departureTime time.Time, numRoundTrips int) *BusSchedule {
	schedule := &BusSchedule{
		Route:             route,
		DepartureTime:     departureTime,
		ArrivalTimeStops:  make(map[string][]string),
		ArrivalTimeRounds: numRoundTrips,
	}

	currentTime := departureTime
	reverse := false // 逆向き運行を切り替えるフラグ

	for round := 0; round < numRoundTrips; round++ {
		routeOrder := make([]string, 0, len(route)*2-1)

		if reverse {
			// 逆向き運行の場合、終点から始点に戻る
			for i := len(route) - 1; i >= 0; i-- {
				stop := route[i]
				arrivalTime := currentTime.Format("15:04")
				schedule.ArrivalTimeStops[stop] = append(schedule.ArrivalTimeStops[stop], arrivalTime)
				routeOrder = append(routeOrder, fmt.Sprintf("%s(%d): %s", stop, len(schedule.ArrivalTimeStops[stop]), arrivalTime))
				if i > 0 {
					currentTime = currentTime.Add(5 * time.Minute)
				}
			}
			reverse = false
		} else {
			// 正向き運行の場合、始点から終点に向かう
			for i := 0; i < len(route); i++ {
				stop := route[i]
				arrivalTime := currentTime.Format("15:04")
				schedule.ArrivalTimeStops[stop] = append(schedule.ArrivalTimeStops[stop], arrivalTime)
				routeOrder = append(routeOrder, fmt.Sprintf("%s(%d): %s", stop, len(schedule.ArrivalTimeStops[stop]), arrivalTime))
				if i < len(route)-1 {
					currentTime = currentTime.Add(5 * time.Minute)
				}
			}
			reverse = true
		}

		fmt.Println(strings.Join(routeOrder, "->"))
		currentTime = currentTime.Add(10 * time.Minute) // 終点での停止時間
	}

	return schedule
}

func main() {
	route := []string{"A0", "A1", "A2", "A3", "A4", "A5"}
	departureTime := time.Date(2024, 1, 6, 6, 0, 0, 0, time.UTC)
	numRoundTrips := 3

	schedule := GenerateBusSchedule(route, departureTime, numRoundTrips)

	// routeOrder を表示
	fmt.Println("routeOrder:")
	for _, stop := range schedule.Route {
		fmt.Printf("%s:\n", stop)
		for i, arrivalTime := range schedule.ArrivalTimeStops[stop] {
			fmt.Printf("  通過%d: %s\n", i+1, arrivalTime)
		}
	}
}

出力結果

C:\Users\ebata>go run dummy1.go
A0(1): 06:00->A1(1): 06:05->A2(1): 06:10->A3(1): 06:15->A4(1): 06:20->A5(1): 06:25
A5(2): 06:35->A4(2): 06:40->A3(2): 06:45->A2(2): 06:50->A1(2): 06:55->A0(2): 07:00
A0(3): 07:10->A1(3): 07:15->A2(3): 07:20->A3(3): 07:25->A4(3): 07:30->A5(3): 07:35
routeOrder:
A0:
通過1: 06:00
通過2: 07:00
通過3: 07:10
A1:
通過1: 06:05
通過2: 06:55
通過3: 07:15
A2:
通過1: 06:10
通過2: 06:50
通過3: 07:20
A3:
通過1: 06:15
通過2: 06:45
通過3: 07:25
A4:
通過1: 06:20
通過2: 06:40
通過3: 07:30
A5:
通過1: 06:25
通過2: 06:35
通過3: 07:35

2024,江端さんの忘備録

NHKの『平安時代サミット2024 本当に「平安」だったのか』を見ました。

I watched NHK's "Heian Period Summit 2024: Was it really "Heian"?

いわゆる、今年の大河ドラマの番宣番組ですが、面白かったです。

It's a so-called "promotion program" for this year's history drama, but it was interesting.

今回は3つほど頂きました。

This time, I received three of them.

-----

(1)『平安時代の呪詛と、現代のSNSは同じである』

(1) "Curses in the Heian period and social networking sites today are the same."

至言だよなぁ、と思いました。

I thought, "That's a supreme word.

SNSの誹謗中傷は物理的な攻撃ではないのに、人を殺す力があります。

Social networking slander is not a physical attack, yet it has the power to kill.

これを「呪詛」と言わずに、何と言いましょうか。

What shall we call this without calling it a curse?

やはり、SNSなんぞには手を出さないのが良いのです。

After all, it is better to stay away from social networking sites.

(2)『光源氏が"クズ"なのは、もう共通認識ですよね』

(2) "It is already common knowledge that Hikaru Genji is a scumbag.

うん、もう、これはもう、議論の余地なく、奴はクズです。

Yeah, now, this is no longer debatable, the guy is a scumbag.

源氏物語

(3)『"光源氏"を"推し"と置き換えると、その存在を認めることができます』

(3) "If you replace "Hikaru Genji" with "fave", we can recognize its existence.

私、この"推し"は知っているのですが、上記のフレーズの意味が分からなくて、嫁さんに尋ねました。

I know this "fave," but I don't know what the above phrase means, so I asked my wife.

私:「これは、自分の応援している"推し"のアイドルであるなら、クズでも構わんということ?」

Me: "Does this mean you don't care if he's a bum as long as he's your "fave" that you support?"

嫁さん:「そういうこと。"推し"とは、何をしても許される存在のことだから」

Wife: "Right." A "fave" is someone who is allowed to do whatever he wants."

やっぱり私には良く分かりませんでしたが、『"推し"って怖いものなんだなぁ』ということだけは分かりました。

I still didn't understand it well, but I did understand that "fave" is scary.

-----

私が、今でも疑問に思っていることは、

I am still wondering about the question,

『なんで源氏物語は、検閲、発行禁止を免れたのだろう?』

Why did The Tale of Genji escape censorship and a publication ban?"

ということです。

だって、あの話、皇室への不敬のオンパレードですよ。

Because that story is a parade of disrespect to the imperial family.

当時、不敬罪があったかどうかは知りませんが、基本的に皇族に対する不敬が許される時代だったとは思えません。

I don't know if there was a crime of disrespect at the time, but I don't think it was when disrespect for the royal family was tolerated.

帝(桐壺帝)の妻(藤壺)を妊娠させておいて、この子の後見人になるなんて ―― どんな"托卵"だよ!と突っ込みたくなります。

How could he get the wife (Fujitsubo) of the emperor (Kiritsubo) pregnant and then become the child's guardian? I am tempted to say, "What kind of "mendicancy" is this?

-----

さらに、私が、本当に訳が分からんのが、一条天皇が「源氏物語の愛読者」だった、という点です。

Furthermore, I don't understand that Emperor Ichijo was a "lover of the Tale of Genji."

(一条天皇と藤原氏の関係は、説明が面倒なので割愛(ググって下さい))。

(The explanation of the relationship between Emperor Ichijo and the Fujiwara clan will be cut (please Google)).

フィクションとはいえ、自分の家系が、最大級の侮辱を受けている、とは思わなったのでしょうか。

Even though it was fiction, did Emperor Ichijo ever think that his family lineage was being insulted in the greatest possible way?

私、このあたりがどうしても良く分からないので、「源氏物語文学」に詳しい方に解説頂ければ、嬉しいです。

I am unsure I understand this part very well, so I would be glad if someone familiar with "Tale of Genji Literature" could explain it.

-----

ちなみに、上記の私の疑問に応える一つの解釈はあります。

By the way, there is one interpretation that answers my question above. That means,

―― 源氏物語は、あの時代における、異世界ファンタジーであった

"The Tale of Genji was an otherworldly fantasy of its time."

ということです。

または、実世界(α世界線)に類似した、別の世界(β世界線)だった、という、平行世界線解釈です。

Or, it is a parallel worldline interpretation that the real world (alpha worldline) was similar to another world (beta worldline).

ここに、私は、

Here, I would like to propose a new interpretation of

『源氏物語 ≒ シュタインズゲート』

"The Tale of Genji ≒ Steins;Gate."

という、新解釈を提唱したいと思います。

2012,江端さんの忘備録

清水義範の「読み違え源氏物語」を読んでいます。

○夕顔の死因は、六条御息所の怨念ではなく、

○空蝉、惟光を共犯とする、頭の中将の陰謀であり、

○夕顔は空蝉と同一人物で、しかも死んでいない

という、ぶっ飛んだ、「源氏物語殺人事件」に仕上がっています。

こういう本は楽しい。

-----

ところで、私が「夕顔」「六条御息所」「頭の中将」とかの名前をスラスラ出せるのは、

「文部科学省の指導要項による古文の教育の成果」などでは、

『断じて無く』

全て、

大和和紀による漫画コミック、

「源氏物語 あさきゆめみし」

の内容を完全暗記していることと、

そして最近では、

魔夜峰央による漫画コミック

「パタリロ源氏物語!」

で、内容の理解が再強化されている為です。

源氏物語に関しては、文部科学省の指導要項(要するに古文の教科書)は不要でした。

# というか、むしろ邪魔。

-----

文部科学省は、(教育を統制する機関としてのメンツと立場もあるのだろうけど)、

「古典をつまらなくする為に存在しているのだろうか」

とまで邪推することがあります。

なんで、源氏物語を、わざわざ読みにくい原文で記載するのかな。

漫画とまでは言わないけど、現代訳で「内容」を楽しませるのが先だろうが。

そして、現在の価値観に照らして、

『「光源氏」に殺意を覚える』

というくらいまでの親近感を持たせることが大切だと思うんですが。

どうでしょうか。

-----

付録

源氏物語の「『光源氏』批判」としては、あまりに著名な「笑う大天使」(川原泉)より、長文抜粋。

---- ここから -----

(1)校則違反(?)の罰として、源氏物語の全文読破とレポート提出を課せられた3人の女子高校生の、レポート作成中の会話

「女癖は悪いし、くっだらねえ事で悩むし泣くし」

「マザコンでロリコンで不倫大好きの変態だよな」

「この平安人は恋愛沙汰以外にな~んも考えとらんぞ」

(2)提出されたレポートの結言

『――結論

…だから光源氏とゆー人は、女の人の迷惑も考えずやみくもに本能のまま行動し、知的ブレーキのあまり利かない性格か或はブレーキ自体が存在しない質であり、いわゆる「歩く煩悩様」の典型的な例だと思われます。(更科柚子)』

『――結論

…ゆえに光源氏とゆー人は、性的衝動の赴くまま、他を顧みる事無く自らの欲望を満足させなければ気がすまないミーイズムの人であり、このよーなタイプはさしずめ「性衝動人」と申せましょう。(司城史緒)』

『――結論

…つまり光源氏とゆー人は、独りよがりの悩みで周囲の人々を不幸に巻き込むだけでなく、さらにその執着心と多情さで不幸を拡大させるとゆー得意技がパターン化された「増殖ワラジムシ」であるといえる。(斎木和音)』

---- ここまで -----

未分類

ノード間のコストが与えられているダイクストラ計算を行うノードのそれぞれに数値が設定されていて、ノードが持っている数値より小さい数値のノードとは繋がることができない、というアルゴリズムをGo言語で作成する

main2.goで、ノードのコストが分からない場合でも対応できるように改良したもの。

package main

import (
	"fmt"
	"math"
)

type Node struct {
	Name  string
	Value float64 // 各ノードに設定された数値 (負数の場合、この数値を無視する)
}

type Edge struct {
	From   *Node
	To     *Node
	Weight float64
}

func main() {
	/*
		// ノードとエッジを初期化
		nodeA := &Node{Name: "A", Value: 5}
		nodeB := &Node{Name: "B", Value: 8}
		nodeC := &Node{Name: "C", Value: 6}
		nodeD := &Node{Name: "D", Value: 2}
		nodeE := &Node{Name: "E", Value: 4}
	*/

	// ノードとエッジを初期化
	nodeA := &Node{Name: "A", Value: 3}
	nodeB := &Node{Name: "B", Value: -1} // 負数の場合無視
	nodeC := &Node{Name: "C", Value: -1} // 負数の場合無視
	nodeD := &Node{Name: "D", Value: 2}
	nodeE := &Node{Name: "E", Value: -1} // 負数の場合無視
	nodeF := &Node{Name: "F", Value: -1} // 負数の場合無視
	nodeG := &Node{Name: "G", Value: 1}

	/*
		edges := []Edge{
			{nodeA, nodeB, 2},
			{nodeA, nodeC, 4},
			{nodeB, nodeC, 1},
			{nodeB, nodeD, 7},
			{nodeC, nodeD, 3},
			{nodeC, nodeE, 5},
			{nodeE, nodeD, 2},
		}
	*/

	edges := []Edge{ // A,B,C,D,E,Fの順で双方向をしてい
		{nodeA, nodeB, 1},
		{nodeB, nodeA, 1},

		{nodeB, nodeC, 1},
		{nodeC, nodeB, 1},

		{nodeC, nodeD, 1},
		{nodeD, nodeC, 1},

		{nodeD, nodeE, 1},
		{nodeE, nodeD, 1},

		{nodeE, nodeF, 1},
		{nodeF, nodeE, 1},

		{nodeF, nodeG, 1},
		{nodeG, nodeF, 1},
	}

	startNode := nodeG
	targetNode := nodeA

	// ダイクストラアルゴリズムを実行
	shortestPath, totalWeight := dijkstra(startNode, targetNode, edges)

	if shortestPath == nil {
		fmt.Println("最短経路が見つかりませんでした。")
	} else {
		fmt.Printf("最短経路: %v\n", getNodeNames(shortestPath))
		fmt.Printf("最短経路の総重み: %.2f\n", totalWeight)
	}

	fmt.Println(nodeA.Value)
	fmt.Println(nodeB.Value)
	fmt.Println(nodeC.Value)
	fmt.Println(nodeD.Value)
	fmt.Println(nodeE.Value)
	fmt.Println(nodeF.Value)
	fmt.Println(nodeG.Value)

}

func dijkstra(startNode, targetNode *Node, edges []Edge) ([]*Node, float64) {
	// ノード間の最短距離を格納するマップを初期化
	shortestDistances := make(map[*Node]float64)
	// 各ノードの前のノードを格納するマップを初期化
	predecessors := make(map[*Node]*Node)

	// 最短距離を無限大で初期化し、開始ノードの最短距離を0に設定
	for _, edge := range edges {
		shortestDistances[edge.From] = math.Inf(1)
		shortestDistances[edge.To] = math.Inf(1)
	}
	shortestDistances[startNode] = 0

	// 訪問済みのノードを格納するセットを初期化
	visitedNodes := make(map[*Node]bool)

	// まだ訪問していないノードが残っている間ループ
	for len(visitedNodes) < len(shortestDistances) {
		// 未訪問のノードの中から最短距離のノードを選択
		currentNode := getClosestUnvisitedNode(shortestDistances, visitedNodes)

		// ノードがない場合やターゲットノードに到達した場合は終了
		if currentNode == nil || currentNode == targetNode {
			break
		}

		for _, edge := range edges {
			if edge.From == currentNode {
				if edge.To.Value < 0 { // -1などの負数が入っていたら、更新してしまう
					edge.To.Value = currentNode.Value // 下のif文を通す為の手続(書き換えても大丈夫かな(今のところ大丈夫そうだけど))
				}
				if edge.To.Value >= currentNode.Value { //
					distance := shortestDistances[currentNode] + edge.Weight
					if distance < shortestDistances[edge.To] {
						shortestDistances[edge.To] = distance
						predecessors[edge.To] = currentNode
					}
				}
			}
		}

		// このノードを訪問済みとしてマーク
		visitedNodes[currentNode] = true
	}

	// 最短経路を復元
	shortestPath := make([]*Node, 0)
	currentNode := targetNode
	for currentNode != nil {
		shortestPath = append([]*Node{currentNode}, shortestPath...)
		currentNode = predecessors[currentNode]
	}

	// 最短経路の総重みを計算
	totalWeight := shortestDistances[targetNode]

	return shortestPath, totalWeight
}

func getClosestUnvisitedNode(distances map[*Node]float64, visitedNodes map[*Node]bool) *Node {
	minDistance := math.Inf(1)
	var closestNode *Node

	for node, distance := range distances {
		if !visitedNodes[node] && distance < minDistance {
			minDistance = distance
			closestNode = node
		}
	}

	return closestNode
}

func getNodeNames(nodes []*Node) []string {
	names := make([]string, len(nodes))
	for i, node := range nodes {
		names[i] = node.Name
	}
	return names
}

2024,江端さんの技術メモ

このプログラムの目的は、時刻表の乗り換え案内のアルゴリズムを実現する為のテストプログラムです。
「到着時刻より早い時間の電車やバスには乗れない」をダイクストラに組み込むことができるかを調べたものです。

ノードのValueが到着・出発時間を表わすと考えて下さい。

package main

import (
	"fmt"
	"math"
)

type Node struct {
	Name  string
	Value float64 // 各ノードに設定された数値
}

type Edge struct {
	From   *Node
	To     *Node
	Weight float64
}

func main() {
	/*
		// ノードとエッジを初期化
		nodeA := &Node{Name: "A", Value: 5}
		nodeB := &Node{Name: "B", Value: 8}
		nodeC := &Node{Name: "C", Value: 6}
		nodeD := &Node{Name: "D", Value: 2}
		nodeE := &Node{Name: "E", Value: 4}
	*/

	// ノードとエッジを初期化
	nodeA := &Node{Name: "A", Value: 1}
	nodeB := &Node{Name: "B", Value: 1}
	nodeC := &Node{Name: "C", Value: 0}
	nodeD := &Node{Name: "D", Value: 1}
	nodeE := &Node{Name: "E", Value: 1}

	/*
		edges := []Edge{
			{nodeA, nodeB, 2},
			{nodeA, nodeC, 4},
			{nodeB, nodeC, 1},
			{nodeB, nodeD, 7},
			{nodeC, nodeD, 3},
			{nodeC, nodeE, 5},
			{nodeE, nodeD, 2},
		}
	*/

	edges := []Edge{ // "方向性あり"に注意
		{nodeA, nodeB, 1},
		{nodeA, nodeC, 1},
		{nodeB, nodeC, 1},
		{nodeB, nodeD, 1},
		{nodeC, nodeD, 1},
		{nodeC, nodeE, 1},
		{nodeE, nodeD, 1},
		{nodeD, nodeE, 1},
	}

	startNode := nodeA
	targetNode := nodeE

	// ダイクストラアルゴリズムを実行
	shortestPath, totalWeight := dijkstra(startNode, targetNode, edges)

	if shortestPath == nil {
		fmt.Println("最短経路が見つかりませんでした。")
	} else {
		fmt.Printf("最短経路: %v\n", getNodeNames(shortestPath))
		fmt.Printf("最短経路の総重み: %.2f\n", totalWeight)
	}
}

func dijkstra(startNode, targetNode *Node, edges []Edge) ([]*Node, float64) {
	// ノード間の最短距離を格納するマップを初期化
	shortestDistances := make(map[*Node]float64)
	// 各ノードの前のノードを格納するマップを初期化
	predecessors := make(map[*Node]*Node)

	// 最短距離を無限大で初期化し、開始ノードの最短距離を0に設定
	for _, edge := range edges {
		shortestDistances[edge.From] = math.Inf(1)
		shortestDistances[edge.To] = math.Inf(1)
	}
	shortestDistances[startNode] = 0

	// 訪問済みのノードを格納するセットを初期化
	visitedNodes := make(map[*Node]bool)

	// まだ訪問していないノードが残っている間ループ
	for len(visitedNodes) < len(shortestDistances) {
		// 未訪問のノードの中から最短距離のノードを選択
		currentNode := getClosestUnvisitedNode(shortestDistances, visitedNodes)

		// ノードがない場合やターゲットノードに到達した場合は終了
		if currentNode == nil || currentNode == targetNode {
			break
		}

		// 隣接ノードの最短距離を更新
		for _, edge := range edges {
			//
			if edge.From == currentNode && edge.To.Value >= currentNode.Value { // ここがポイント
				distance := shortestDistances[currentNode] + edge.Weight
				if distance < shortestDistances[edge.To] {
					shortestDistances[edge.To] = distance
					predecessors[edge.To] = currentNode
				}
			}
		}

		// このノードを訪問済みとしてマーク
		visitedNodes[currentNode] = true
	}

	// 最短経路を復元
	shortestPath := make([]*Node, 0)
	currentNode := targetNode
	for currentNode != nil {
		shortestPath = append([]*Node{currentNode}, shortestPath...)
		currentNode = predecessors[currentNode]
	}

	// 最短経路の総重みを計算
	totalWeight := shortestDistances[targetNode]

	return shortestPath, totalWeight
}

func getClosestUnvisitedNode(distances map[*Node]float64, visitedNodes map[*Node]bool) *Node {
	minDistance := math.Inf(1)
	var closestNode *Node

	for node, distance := range distances {
		if !visitedNodes[node] && distance < minDistance {
			minDistance = distance
			closestNode = node
		}
	}

	return closestNode
}

func getNodeNames(nodes []*Node) []string {
	names := make([]string, len(nodes))
	for i, node := range nodes {
		names[i] = node.Name
	}
	return names
}

2024,江端さんの忘備録

社会人になって、まだ数年も経たないくらいの時に、阪神・淡路大震災が発生し、3日間だけでしたが、ボランティア活動に従事したことがあります。

When I worked for less than a few years, the Great Hanshin-Awaji Earthquake struck, and although I was only there for three days, I volunteered.

あれから、約30年を経過しました今にあっても、「被災人数が劇的に減った」とか、「避難所の効率が劇的に改善した」、という感じを受けません。

Even now, some 30 years later, I do not feel that the number of victims has dramatically decreased or that the efficiency of evacuation centers has significantly improved.

今も、ニュースで、30年前と同様に、寒さを凌ぐためのダンボールや新聞紙の使い方とかが説明されている状況です。

Even now, just as it was 30 years ago, the news is explaining how to use cardboard boxes and newspapers to beat the cold, and so on.

「建物が倒壊しなくなる新しい外装塗」とか、「孤立した避難所にで大量の物資を送り込むロケット」とか、そういう技術は、まだ登場していません。

Technology such as "a new exterior coating that stops buildings from collapsing" or "a rocket that sends large quantities of supplies to isolated evacuation centers" has yet to appear.

-----

人類史上、自然災害に対して、私たちは例外なく「受け身」です。

We have been exceptionally "passive" regarding natural disasters throughout history.

自然災害に日常生活を蹂躙されつくして、そこから復興するしかありません。

We can only recover from a natural disaster that has completely overrun our daily lives.

なんとも、もどかしいです。

It is very frustrating.

現時点で、私は、自然災害の直撃に遭遇することなく生きてきましたが、このような幸運が死ぬまで続く保証はありません。

At this point, I have lived without encountering a direct hit from a natural disaster, but there is no guarantee that such good fortune will last until my death.

-----

これから、私は、体を頭も気力も衰えていき、日常生活も、ままならない状態になる未来が確定しています。

I am sure that my body, head, and energy will deteriorate, and I will be unable to live my daily life.

そんな状態で、自然災害の直撃を喰らったら、生き残れるかどうか。仮に生き残ったとしても、その後に生きていく気力が維持できふのかどうか、まったく自信がありません。

In such a situation, I am unsure if I would survive if I were hit directly by a natural disaster. Even if I stayed, I am skeptical I could maintain the energy to live afterward.

『戦争にも災害にも遭遇することなく、人生を逃げきりたい』と、何かぬ向かって祈ることしかできない我が身が、本当にもどかしいです。

It is frustrating that all I can do is pray to God, saying, "I want to escape my life without encountering war or disaster.