Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
SVX日記
[go: Go Back, main page]

SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|12|
2025|01|02|03|04|05|06|07|08|09|10|

2025-10-25(Sat) 着ブクれ保険にNo!

  最近、久々にバイクに乗ったこともあり、アレコレと車種名で検索したりして、事故動画やブログ記事を眺めているのだが、興味深い記事を見つけた。「バイクが故障したのでレッカーが必要になった。保険はファミリーバイク特約なのでロードサービスがない。JAFに頼むと3万前後かかる見込みなのが痛すぎる」という内容。

  どうやら自宅での故障であり、JAFには入っていないようだ。でも、それって「故障に対する備えがなかった」などと後悔するような状況なのだろうか。でもって対策に年に何万もするような保険を検討している。いや、気づけよ。滅多に起きない事故を想定して少額を投げ捨てるのが保険だ。今回はたかが3万だろ。毎年2万以上も払わなければならない保険に入ってどうする。

  自分は30年以上、ほぼ継続して車を運転しているがレッカーのお世話になったことは一度もない。レッカーの保険が年に1万だとしても、既に30万円を浮かした計算だ。仮に明日レッカーが必要になり、それに20万かかったとしても、まだ10万も得しちまってるんだ!

  そんな自分なので、先日の2回のバイクレンタルのどちらも、追加の保険契約は断っている。ホンダでは「立ちゴケしてブレーキレバーが折れたりしたら修理費に加えて営業保証が1万とかかかりますよ」などと脅されたが、それを補償する保険の料金は8千円を超える。そんなの契約したら総額がレンタル料の倍近くになってしまうではないか。アホらしい。

  そもそも自分の所有するバイクでコケたって、自損保険を契約していない限り修理費は必要になる。やらかしたら少なからず支出が発生するのは当たり前のことではないか。

  そして、改めてヤマハとホンダの追加の保険の詳細を見ると、だいぶ異なることに気づく。

  ヤマハバイクレンタルの保険には修理費用に上限キャップがあり、それを免除するための追加保険が第一段階。少額の営業保証を免除するための追加保険が第二段階。

  ホンダバイクレンタルの保険には修理費用に上限キャップはなく「大修理が発生した場合のみ」それを「軽減する」ための追加保険が第一段階。営業保証も含めすべて免除するための追加保険が第二段階。第一段階は発生確率の高い小修理の場合には効果がないので、たとえ少額でもこれ単独を契約する意味はないように思える。

  こういっちゃなんだが、ヤマハの追加保険は素直で安価だが、ホンダの追加保険はちょっとトラップな印象すら受ける。もうホンダで借りることはないかもなぁ。店員の愛想も最低限だったし。

  結局、保険というものはイザという時に自らの貯蓄から払うことを許容できるなら、契約しない(削る)ことを検討するべきだろう。実際、自分は自動車保険に自損を付けていない。金持ちはケチだといわれるが、金持ちは金を減らさないための選択の幅が広い、というのが正確だろう。寝てても投資で資産は増え続けるしね。自分ですらロードスターの1台分くらいは軽く増やせている。

  と、そういうことに気付かされたのも、若い頃にバイクの保険を契約する時だったりする。物損の上限額によっても掛金が違うのを見て「バイクの物損に無制限て必要ですかね?」と訊いたのだ。答えは「交差点で転倒し、バイクが滑ってってコンビニに突っ込んで全焼した場合とかですね」だった。本気だったのか冗談だったのかわからんが、そんなこと起きまっかいな! そもそも自分にはそんな高速度で交差点を曲がるテクニックなんてないし。

  最初の話に戻るが「自宅での故障であり、JAFには入っていない」なら、極端な話「JAFに入った翌日にレッカーを呼べばいい」んじゃねぇの? 翌日が気マズいなら、翌々日でも、翌月でもいい。

  とはいえ、自分の場合、なぜかカミさんがJAFに入っているのだよね。JAFはロードサービス以外にも、あちこちの観光施設で割引きが効いたり、それなりに興味深い冊子を送ってきたりするので、4000円/年の大半は回収できる。家族会員なら2000円/年の追加で済んじまうんだ! 恐るべき費用対効果だといえよう。まぁ、クルマの保険にロードサービスは付いているので、自分にはそれさえいらないのだけれどね。


2025-10-19(Sun) 復帰ライダーレンタルアンコール

  いい季節はここ数週間だけだろうからさぁ、などと理由をつけつつ、先週に続いて、またバイクを借りてみた。今回は以前に同僚が乗っていたというRebel250。ちょっと店まで距離があるがホンダで借りてみるというテストも兼ねてだ。

  先週から妙にバイク熱がブリ返してしまって、アレコレとネットで検索していたらokomotoというサイトが見つかった。これがまたオモシロい。理想的なブレーキ操作による停まり方、お作法のチャンク化、危険性の啓蒙など、持論を述べつつも、その結論に至る理由もしっかり書いてあって納得性が高い。これはスゴい。有益。というわけで、やっぱり多少の防御も必要か、と思い直し、インナプロテクタの手袋のインナを手配してみた。

  当日の朝。ホンダまでは自転車でヒト山を超える必要があるのだが、早速、汗ダクになってしまった。秋なのにコレかよ。夏に借りるの無理じゃん。服装も、漕がなければならない自転車と乗っているだけのバイクでは違うべきだ。とはいえ、バイクに乗って走り出せば汗は引くだろう。

  画像の説明

  Rebel250とご対面。要するにアメリカンだ。このタイプには初めて乗る。アメリカンというと、後傾の姿勢でブラ下がるように上に手を伸ばすイメージだが、これはそこまでではなかった。座席が低いので足付きには問題ないが、ニーグリップができないことには不安を感じる。走り出すとそれほどの違和感はない。んが、どんなもんじゃろう。250ccにしてはそれほどのパワーを感じない。つうか、エンジン音はやや派手なのに、タコメータがないので、どの辺りを常用すべきなのかわからん。なんでないんだ。つまらんやんか。

  しばらくは街中なので、頻繁な操作を強要されるが、早速okomotoで読んだ理想的な停まり方を意識してみる。ギアが落としきれなかったり、フラついて両足を付いたりするが、テーマを持って走るのは楽しい。

  田舎の方に抜け、コンビニで休憩。駐車場の枠ではなく、駐輪場っぽい場所に停める。昼飯を食べたら、三河湖へ。そこから、奥はちょっとした険道。そこで発見。当たり前かもしれないが、アメリカンは小回りが効きにくい。低速走行にも向かない。後傾までいかなくても姿勢が直立なので、全体重が尻に乗り、尻が痛くなる。これは自分には向かないなぁ。筋トレで尻の脂肪が減ると尻の耐久性が減るのだ。

  何度も通ったことのある道ではあるが、ナビがないので右往左往しながら、そろそろ帰路につかなければならない時間になってきた。帰る方向に向かいつつ、ロードスターではもう通りたくないけれど、バイクなら通ってみたい狭い道を見つけたので通ってみることにした。んが、林の中を通る道なので、ほぼウェットで落ち葉も多い。バイクには厳しい道が延々と続く。というか、特にアメリカンに厳しすぎるのだ。ものすごく慎重に操縦する。2速の穏やかな加速挙動が望ましいが、遅すぎてエンストしたら逆にコケそうでヤバい。狭さは記憶どおりだが、長さは記憶の倍以上あって、抜けたときは心底ホッとしてしまった。

  さて、このまま帰ってもいいが、23号に出てブッ飛ばして帰るのもいいな、などと考えたのが失敗だった。渋滞に巻き込まれて時間が迫ってきてしまう。途中、スリ抜けすりゃいいことに気づくが、結局23号までは出られず、1号で戻ることに。んが、微妙に間に合わない時間になってしまった。仕方なくホンダに電話して、延長し明朝に返却する旨を伝える。その後、計画通りのルートでホンダの前に戻ったのは、30分弱オーバした時間だった。そのまま通り過ぎて帰宅。

  小雨の中を帰宅したら、走行距離は237kmだった。明日、ちょっと仕事を抜けて朝から返しに行かなきゃな。


2025-10-13(Mon) MAGIシステムっぽいものを作る

  例によってAIネタなのだが、仮に間違えても自ら気づいたりするなどして、精度を上げていく方法はないか、などというサジェスチョンをもらった。

  それって、いわゆるMAGIシステムなんじゃないのか。合議制により結論を出すことで回答の精度を上げるという。先日作ったXoPilotが出した見解なんかも、加味して結論を出せるのなら意義があるかもしれない。

  ネットを検索すると同様の考えで遊んでいる先駆者がいるが、自分が重要だと思うポイントは「プロキシ動作」である。「AIに問い合わせるAPI」と「合議制AIに問い合わせるAPI」とを揃えることに価値がある。それにより見解を得る側のクライアントは特別なものである必要がなくなり、設定を変更するだけで合議制AIに尋ねられるようになる。そして、合議制AIの側も設定を変更するだけでどんな構成の合議制にも対応できる。そんなものがあるといい。

  つうわけで作ってみた。XAGIシステム。一般的なAPI動作をさせる都合から、ウェブサーバ機能が必要だ。作ってもいいのだが、せっかくなのでイマサラながらRubyのWebrickを使ってみた。サーバはたったこれだけ。

require 'webrick'
server = WEBrick::HTTPServer.new({
    :DocumentRoot => './',
    :BindAddress => '127.0.0.1',
    :Port => 8080,
})
server.mount('/v1/chat/completions', WEBrick::HTTPServlet::FileHandler, 'xagi_v1_chat_completions.cgi')
trap('INT') { server.shutdown }
server.start

  APIの本体はxagi_v1_chat_completions.cgiの側に記述する。これもメインの処理はこれだけ。

post_body = $stdin.read
post_body.force_encoding('UTF-8')
req = JSON.parse(post_body)
 
opinions = {}; @configs[:xagi][:magi].each {|name, config|
    prompt  = (config[:def] || 'あなたは「%s」という名前です。') % name \
            + (config[:ask] || '%sと問いかけられました。') % req['messages'].last['content'].enbracket \
            + (config[:com] || 'それに対しての助言をお願いします')
    opinions[name] = ngs[config[:ngs_config]].ask(prompt, :FULL)
}
 
chairs = (it = @configs[:xagi][:chair]).keys
config = it[chairs[rand(chairs.size)]]
 
prompt = config[:def] || 'あなたは議長です。'
prompt += (config[:sta] || '%sという問いかけに対して') % req['messages'].last['content'].enbracket
opinions.each {|name, opinion|
    prompt += (config[:opi] || '「%s」は%sと、') % [name, opinion.content.enbracket]
}
prompt += (config[:ask] || '助言しました。')
prompt += (config[:com] || '各々の意見を考慮し、結論を出してください。')
conclusion = ngs[config[:ngs_config]].ask(prompt, :FULL)
 
response = {
    'model'     => 'XAGI-NAGOYA-2025-10-10',
    'choices'   => [
        {
            'message'   => {
                'role'      => 'assistant',
                'content'   => conclusion.content,
            }
        }
    ]
}
 
$\ = "\r\n"
print('Content-Type: application/json')
print()
print(JSON.pretty_generate(response).gsub(/\r?\n/, $\))

  合議制の設定は以下。エヴァのMAGIに準じて「科学者」「母」「女」の3人をせめぎあわせているわよ。別にエヴァのMAGIを忠実に再現するのが目的ではないので、議長役は別に設定できるようにしてある。いずれにも個別に異なるLLMを使うようにもできる。

@configs[:xagi] = {}
@configs[:xagi][:magi] = {
    (name = 'MELCHIOR') => {
        :ngs_config => 'gpt-4o-mini',
        :def        => 'あなたは「%s」という名前の%sです。' % [name, job = '科学者'],
        :ask        => '%sと問いかけられました。',
        :com        => 'それに対して%s的な視点からの助言を300文字程度でお願いします' % job,
    },
    (name = 'BALTHASAR') => {
        :ngs_config => 'gpt-4.1-nano',
        :def        => 'あなたは「%s」という名前の%sです。' % [name, job = '母親'],
        :ask        => '%sと問いかけられました。',
        :com        => 'それに対して%s的な視点からの助言を300文字程度でお願いします' % job,
    },
    (name = 'CASPER') => {
        :ngs_config => 'gpt-5-nano',
        :def        => 'あなたは「%s」という名前の%sです。' % [name, job = '女性'],
        :ask        => '%sと問いかけられました。',
        :com        => 'それに対して%s的な視点からの助言を300文字程度でお願いします' % job,
    },
}
@configs[:xagi][:chair] = {
    'CHAIR'     => {
        :ngs_config => 'gpt-5-mini',
        :def        => 'あなたは議長です。',
        :sta        => '%sという問いかけに対して',
        :opi        => '「%s」は%sと、',
        :ask        => '助言しました。',
        :com        => '各々の意見を考慮し、結論を出してください。',
    },
}

  上述のとおり、APIは揃えてあるので、従来の「chat」というツールの照会先をXAGIに変更するだけで問い合わせが可能。結果は以下。

$ ./chat
YOU> 戦争は必要ですか?
NGS[XAGI-NAGOYA-2025-10-10]> 私は議長として、MELCHIOR・BALTHASAR・CASPER の各意見を踏まえた総合的な結論を述べます。
 
各意見の要点
- MELCHIOR:歴史的・科学的観点から戦争は破壊と犠牲をもたらし、正当化は困難。外交・国際協力で紛争を平和的に解決する努力を強化すべき。
- BALTHASAR:人命と日常の安全を最優先にする母親的視点。対話と教育で平和を育てつつ、危険時は現実的な避難・防護を準備することを重視。
- CASPER:戦争がもたらす痛みに共感しつつ、現実には「避けられない」とされる場合もあると認める。だからこそ対話、共感、内面の変化が重要。
 
総合的結論(簡潔)
- 戦争は基本的に必要ではなく、極力回避すべきものです。戦争は多大な人命・環境・社会的コストを生み、長期的な害を残します。したがって外交、対話、国際ルールと紛争予防の強化が最優先です。
- ただし、自己防衛や大規模な人道的危機(迫害や虐殺の差し迫った危険)など、全ての非軍事的手段が尽くされても避けられない場合に限り、最小限かつ短期的な軍事行動が検討され得る、という慎重な立場をとります。そうした判断は厳格な倫理的・法的基準(正当な原因、最後の手段、比例性、正当な権限、成功の見込みなど)に基づくべきです。
 
具体的な提言(実践的)
- 国家・国際レベル:
  - 外交・仲介・経済協力・開発支援・紛争予防の投資を増やす。
  - 国際法、人権、国際機関の機能強化(監視・制裁・平和維持)を推進する。
  - 軍縮、武器管理、地域の安全協定を促進する。
- 社会・コミュニティレベル:
  - 異文化理解・平和教育・市民社会の対話を支援する。
  - 紛争の根本原因(不平等、資源争奪、差別、政治的排除)への長期的対処を行う。
- 個人レベル:
  - 情報リテラシーを高め、扇動的言説に流されない。
  - 被害者支援や人道支援に関わる、ボランティアや寄付を検討する。
  - 緊急時には安全確保と避難計画を優先する。
 
最後に
戦争は避ける努力を最優先にすべきだが、現実的には最悪の事態を免れるために限定的に検討されることがある、というのが現実的で倫理的な結論です。重要なのは、戦争を正当化する前にできる限りの平和的手段を尽くし、被害を最小化し、終わったあとは和解と再建に責任を持つことです。
 
必要であれば、特定の紛争やシナリオについて(防衛か人道介入か等)一緒に検討し、より具体的な判断基準や行動案を提示します。どの側面を深掘りしますか。

  ちゃんと複数の視点からの助言がまとめられている。想像よりいいな、これ。もいっちょ。

YOU> 麻婆豆腐は飲み物ですか?
NGS[XAGI-NAGOYA-2025-10-10]> 私は議長として、MELCHIOR・BALTHASAR・CASPER の意見を踏まえた結論を示します。
 
結論(簡潔)
- 麻婆豆腐は基本的に「料理(食べ物)」であり、飲み物ではありません。固形の豆腐や挽き肉が主成分で、とろみのあるソースと一緒に咀嚼して味わうものです(MELCHIORの指摘)。
- ただし、汁を多めに作ってスープ感覚で楽しんだり、とろみを抑えて「飲める」ように調整することは可能です(CASPERの創意的提案)。その場合でも一般的には「麻婆豆腐スープ」や「麻婆風スープ」と呼ぶ扱いになります。
- 食べ方の実用的助言としては、熱さや辛さに注意して少しずつ味わう、ご飯と一緒に食べる、量を調整する等が有効です(BALTHASARの母親的配慮)。
 
実用的な一言
- 「飲み物か?」という問いには否定的だが、「飲める形にすること」は可能。やり方やレシピが必要なら教えます。どの方向で試したいですか(スープ状にする/辛さを抑える/飲みやすくアレンジする 等)?

  まぁ、そうだなw。ちゃんと、与えられた視点によって、それらしい助言が寄せられ、まとめられているのには価値があるんじゃないか。

  XAGIは自製のngsライブラリの一部である。http://itline.jp/git/ngsに置いておく。


2025-10-12(Sun) 復帰ライダーレンタル

  先月の中頃、職場の若い子と話しているうちにバイクの話になった。そういえば最近はレンタルってテも……って検索したら近所のYSP(ヤマハの販売店)で貸してもらえるらしい。F1の日本GPもバイクで行けば渋滞は少ないのではないか。それにしても、このXSR125ってオレ好みだなぁ……自分から話を振ったのに、気づくと見事なミイラ取り。

  借りるとなったらギアは自分のを揃えたい。ヘルメットグローブバックパックU字ロック……次々と揃って、あとはレンタルするだけ。なのに連休の土曜は雨、日曜は……微妙だが我慢しきれずゴー。朝からチャリでYSPへ。レンタル開始は10:30。

  しかし、自分がバイクに乗っていたのは1993年の夏頃から……たしか1999年の夏頃まで。実に四半世紀のブランクである。イキナリ立ちゴケしたらどうしよう。特に店の歩道から車道に出る段差とかで……って、つくばのYSPで新車のXJR400を受け取る時にも同じ心配したなぁ。まったく大丈夫だったけど。

  画像の説明

  しかし思った以上に大丈夫だった。何ひとつ忘れてない。我ながら四半世紀もブランクがあるとは思えない。まぁ、もともと華麗な運転じゃないけど、とはいえ何の危なげもなく普通に走れた。

  そういえば、やっぱり20年くらいぶりのマニュアルだったロードスターの試乗の時も、初っ端にエンストしただけで、その後は大丈夫だった。小脳に形成された回路って一生ものなんだな。

  行く先は……せっかくなら通ったことのない狭い道w。半兵衛グリーンロードとふるさと沙羅林道をチョイス。後者は何度かロードスターで向かってみたものの毎度のように通行止めで通ったことがなかった……のだが今回は通れた。ちょっとダートもあったが、ロードスターでも特に問題なく通れそうな道だった。霧が出て寒くなったのもウィンドブレーカで凌げた。

  懐かしく池田山の頂上のハングライダーの発射台に行って一休みしてたら、通りがかりの若者からの熱視線。「カッコイイすね」「レンタルだけどな」「何ccすか」「これで125」「マジすか」「でも値段は50超え」「お金貯めます」みたいな他愛もない会話だったが、久々で誰かとバイク談義したかったところなので、ちょうどいい話し相手だった。

  池田温泉の道の駅でトイレをすませて帰路につく。どうしよう。明日も続けて借りようか。定刻の18:30までには帰れそうではあるが。しかし、クラッチを握る左手がすごくツラくなってきた。普段から握力も鍛えているのだけどなぁ。頭の左側もヘルメットの内張りに押されたのか痛くなってきた。安物だしなぁ。いきなり6時間も乗れば無理もないか。雨まで降ってきた。ひさびさのバイクなのに出来事が満漢全席ではないか。

  明日は天気よさそうだが、左手が使えるか怪しい。結局、ちょうどいい時間に自宅にたどり着いてしまったので返すことにした。ガソリンスタンドで給油。初めてのセルフ給油だ。事前に方法を確認しておいたが、奥にノズルの当たる場所があるし、それで全力で入れても止まる構造らしい。でも、入ったのは4リッター弱。200kmも走ったのに。燃費は50を超えている。

  返却時に店の兄ちゃんと少し話す。「どうでした」「やっぱ欲しくなるなぁ、借りるの面倒だし」「面倒なのは返すのですね」「確かに」「また借りにきます」なんて会話して帰宅。

  帰ったメシ食って落ち着いたら、左手はほとんどなんともなくなっていた。なんだよもーッ!

  あ。写真のバイクのナンバは、AIに異世界風の文字に変更してもらった。いいな、これ。


2025-10-05(Sun) TopDrivin'でマリーナベイを走る

 とりあえずの実装が多いので、しばらくはリファクタリングかな」とは書いたが、丸々1ヶ月近くかかるとは思わなかった。概ね動いている「F1中継とほぼコンパチなラップタイム表示」をできるだけ整然とサラッとした感じに書き直すだけのことに。

  どうにか納得できるようなコードになったが、何度も書いては元に戻しを繰り返して、ちょっとイヤになってしまうほどだった。まぁ、その分、様々なノウハウが溜まったけれども。

  そして今週末はF1のシンガポールGPということで、コースデータを作ってみた。気づけば、1年半以上前にメルカトル補正のテストに使ったサーキットではないか。当時とは航空写真が更新されているな。あの時点ではコースデータはJSON化してなくて、スクリプト内に直書きしてたっけ。

  作ったところでテスト走行してみる……が、市街地サーキットは車だらけで実に走りづらい。そもそもコースが設置されていないし……とはいえ、フリー走行の中継映像と突き合わせながら練習走行を繰り返すうち、徐々に上達し、自分の作ったゲームのゲーム性が明らかになってきた。

  自分で作っておいて、そのゲーム性を知るというのもヘンだが、現実の地図データを使う都合から、ゲームバランスよりもシミュレーションを優先して作ってきたので、ゲームの体をなしていない可能性も十分にあるのだ。結果は……

 

  ……ムチャクソシビアだが、それなりに楽しめるような気がする。なんというか視野が狭いので完全に覚えゲー。コーナまでの距離(色)表示や道路の形状を目印に、シフトダウンで減速、ハンドル操作でアウトインアウトを狙う。フレーム単位の操作の遅れで大きくコースアウトしてしまうシビアさは音ゲー以上。当たり判定は「ない」ので、トラックリミットを超えたと思ったら失敗。

  つうても、実際のレースも覚えゲーだよな。ブレーキのタイミングやライン取りなんかね。コースアウトしないで走るだけでも難しい。が、何周もすれば徐々に走るラインが収束してくる。気づけば熱中してしまっていた。結局100周くらいは走ったかもしれない。一番マトモに走れたラップを動画にしてみた。ターン13ではちょっと壁をコスッてるかなぁ。

  100周も走ると、F1中継を観る視点がちょっと変わってくる。それだけでも、作った甲斐があったってもんだなぁ。それはそうとシンガポールの角田。結果だけ見ると残念だったけれど、スタートの失敗からのレースペースにはスゴいものがあった気がする。あとは本人よりも周囲と運の問題に見えるけどなぁ。


2025-09-07(Sun) ラップタイム、コーナー表示、概ね実装

  まだ、完全ではないけど、ラップタイムの表示、計測、記録、コーナー表示(距離、番号、名前)などを実装した。

  今夜のイタリアGP決勝観戦に向け、レコノサンスラップを実施中w。

  画像の説明

{
    "map_proxy": "http://localhost/~user/topdrivin/gmproxy.cgi",
    "name": "モンツァ・サーキット",
    "id": "Autodromo Nazionale di Monza",
    "ver": "0.1g",
    "grid": {
        "lat":  45.618794,  "lng":   9.281122,  "dir": 68
    },
    "sectors": [
        {   "l": [ 45.616205,   9.280705],  "r": [ 45.616194,   9.280862],  "name": "=Sector 3"         },
        {   "l": [ 45.630079,   9.288256],  "r": [ 45.629995,   9.288265],  "name": "-Sector 1"         },
        {   "l": [ 45.623941,   9.287987],  "r": [ 45.624002,   9.287912],  "name": "-Sector 2"         },
        {   "l": [ 45.612689,   9.283791],  "r": [ 45.612699,   9.283660],  "name": " dummy 25"         }
    ],
    "corners": [
        {   "p": [ 45.624469,   9.281841],  "sign": { "type": "RCH" },  "name": "1 - Rettifilo"         },
        {   "p": [ 45.627408,   9.282167],  "sign": { "type": "R45" },  "name": "3 - Grande"            },
        {   "p": [ 45.630130,   9.291306],  "sign": { "type": "LCH" },  "name": "4 - Roggia"            },
        {   "p": [ 45.631396,   9.295403],  "sign": { "type": "R90" },  "name": "6 - Lesmo"             },
        {   "p": [ 45.628643,   9.296924],  "sign": { "type": "R90" },  "name": "7 - Lesmo"             },
        {   "p": [ 45.622789,   9.285930],  "sign": { "type": "LCH" },  "name": "8 - Ascari"            },
        {   "p": [ 45.612487,   9.283763],  "sign": { "type": "R45" },  "name": "11 - Parabolica"       }
    ]
}

  とりあえずの実装が多いので、しばらくはリファクタリングかな。


2025-08-31(Sun) 富士スピードウェイでレースごっこ

  角田がレッドブルに昇格してから、我が家はF1ブームである。先日(8/7)など、富士スピードウェイでハースが旧車テストをするというので、わざわざ観に行ってしまった。ゆるい速度で国際レーシングコースを走る「体験走行」にも、ついでに参加である。

  それに前後して、富士スピードウェイで「体験走行フルスロットル」「スポーツ走行トライアル」などというイベントが連日あり、サーキット脇にキャンプ場があると知って、思わず全部入りイベントを組んで、旧い友人と決行してしまった。

  正直、スポーツ走行は「クルマにカンナをかける」ようなもの、と思っているので、あまり気は進まないが、それでも一度は体験しておいて損はないとも思っての参加である。

  初日は「体験走行フルスロットル」。最終コーナーの先、ホームストレートの端あたりから、スタンディングスタートでフル加速をするというもの。普段、アクセルをベタ踏みすることはないのだが、この時ばかりはそれをする。キッカリ7000回転で素早くギアチェンジ。回転落ちが遅いのでそのタイミングでも加速をする。何も難しいことはなく、よほどのビビりでなければ誰でも同じ結果になるだろう。加速はパナのゲートまで、という指示を守って、最高速は170km/h弱であった。やはり指示通り1コーナーの250m前から減速。簡単だ。3回やったら、先導車に続いて割とハイスピードで2周。ホームストレートでは177km/hチョイ出た。いやなかなかの体験だったな、これは。

  画像の説明

  そしてキャンプで一泊。夜遅くまで旧友とあれこれ話す。F1のオランダGPの予選もチラチラと観ながら。しかし、夜も暑くて寝苦しかったな。夜が更けるにつれて徐々に涼しくなるのは体感できたが。

  翌日は「スポーツ走行トライアル」。こっちはトライアルとはいえ、ヘルメットも手袋も牽引フックも装備するガチ走行だ。先導走行のあとの、フリー走行がものすごく怖い。自車だけでなく、他車も走るので。事故したら帰れないし、保険も効かない。

 

  とはいえ、せっかくの機会なので、ストレートは全開、コーナーは余裕を持って、でも、一度くらいはコースアウトする程度には攻める、荷重移動がどんなものか体感する、という目的で走って、概ね達成できた。最高速度は177.7km/h。ラップタイムは2:40前後。うわっ…私のラップ、遅すぎ…? な、気もするが、1コーナーとか余裕を見すぎてたし、パワーバンドから外れてたし、まぁ、初めてなら上出来だろう。

  荷重移動は体感できた。加速に入ると一気にアンダー。でも、一般道では使いどころのない技術だな。各操作はそんなに忙しいわけじゃないので、イメージトレーニングするだけで改善しそう。最終コーナーは先が見えないので、覚えゲー。ちょっと工夫すれば、ストレートが長いので、それだけで数秒は速くなりそう。

  ブレーキはフェードしかけた。180km/hからのフルブレーキングの繰り返し。NR-Aなので熱容量は大丈夫だが、ノーマルパッドでは持たない。クールラップは適当に入れてね、とは言われてはいたが、ホントにヤバいんだな。ブレーキの強化ってのは、ストッピングパワーの強化じゃないってのが確認できた。そして、タイヤはイイ感じにボロクソになった。次の車検までには交換予定なので問題はないけど、これにはどうにもモッタイナイ感がある。スポーツ走行はもうしないかな。

  画像の説明

  帰りはフル下道。渋滞ゼロでノンストップ。時々、剥がれたゴムがタイヤハウスの内側に当たってペチペチと音を立てていた。でも、タイヤがボロクソになるくらいまで走れたのはよい体験だったと思う。

  もうちょっと練習してもう倍の速度で走れるようになれば、F1といい勝負できるんだろうが、もう満足だなぁ。


2025-08-26(Tue) ちょっとウェブサーバ起動しといてくんない?

  ここんとこ「TopDrivin」の開発に夢中で、ゲームする間も惜しんで(?)、物理挙動やら、エンジン音やら、ラップタイム表示やら、次々に実装を進めている……のだが、その開発記事を書くのが追いつかない。どれも面白いコードばかりなのに。

  そこで気分を変えてプログラミングする(?)ことにする。ちょっと前から構想していた、AIによる自律端末操作。要するに、AIにコマンドを考えさせて、それを実際に端末で実行し、その結果をAIに渡して、必要ならまた次のコマンドを考えてもらう……というもの。

  ネックはAIの応答からコマンドを抜き出す方法……なのだが、実はそれはもう解決済み。AIに「JSON形式で答えてね」と指示すればよいのだ。それだけで割と機械処理しやすい形で返ってくる。

  個人的な考えだが、AIに事細かに指示する「プロンプトエンジニアリング」は極めてくだらない取り組みだと思う。自然文での指示が基本なのだから、ごく自然に必要最小限の文で指示をするべきなのだ。AIの種別によっては意図した結果にならなかったり、どのAIを使っても意図した結果にならなかったりするかもしれないが、それはAIの能力の不足であって、いましばらくの進化を待つべきだ。AIが十分に進化すれば「プロンプトエンジニアリング」などは不要になるはずで、そうなればそんな策を弄したような指示は逆に不自然な指示になるだろう。つまるところ「あなたは◯◯の専門家です」というプロンプト。気持ち悪ィんだよ。

  というわけで、作ってみた。やってることは単純。AIにコマンドをJSONで出させて、ssh経由で実行、その結果を渡し、AIにコマンドを……を繰り返すだけ。で「あー、あのー、あれ。ウェブサーバだっけな。起動してないんなら、ちょっと起動しといてくんない?」と、AIに指示した結果がこちら。

/home/user/devel/ngs $ INT=1 ./xopilot
REQ> あー、あのー、あれ。ウェブサーバだっけな。起動してないんなら、ちょっと起動しといてくんない?
コマンド[ssh root@localhost cat /etc/os-release]を実行しますか?
コマンド[ssh root@localhost id]を実行しますか?
================================================================================
Linuxの端末でコマンド「cat /etc/os-release」の実行結果は以下でした。
```
NAME="Fedora Linux"
VERSION="42 (MATE-Compiz)"
RELEASE_TYPE=stable
ID=fedora
VERSION_ID=42
VERSION_CODENAME=""
PLATFORM_ID="platform:f42"
PRETTY_NAME="Fedora Linux 42 (MATE-Compiz)"
ANSI_COLOR="0;38;2;60;110;180"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:fedoraproject:fedora:42"
DEFAULT_HOSTNAME="fedora"
HOME_URL="https://fedoraproject.org/"
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f42/"
SUPPORT_URL="https://ask.fedoraproject.org/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=42
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=42
SUPPORT_END=2026-05-13
VARIANT="MATE-Compiz"
VARIANT_ID=matecompiz
```
Linuxの端末でコマンド「id」の実行結果は以下でした。
```
uid=0(root) gid=0(root) groups=0(root)
```
あー、あのー、あれ。ウェブサーバだっけな。起動してないんなら、ちょっと起動しといてくんない?
コマンドの実行が必要であれば、そのコマンドをJSON形式で指示してください。実行結果を返します。
指示内容を実行できたら「追加のコマンドは必要ありません」と答えてください。
--------------------------------------------------------------------------------
Fedora Linuxにウェブサーバ(Apache HTTP Serverなど)がインストールされている場合、次のコマンドでサービスを起動できます。以下のコマンドをJSON形式で指示します。
 
```json
{
  "command": "systemctl start httpd",
  "description": "Apache HTTP Serverを起動します。"
}
```
 
もしNginxなど別のウェブサーバを使用している場合は、コマンドを変更する必要がありますので、その場合はお知らせください。
--------------------------------------------------------------------------------
コマンド[ssh root@localhost systemctl start httpd]を実行しますか?
================================================================================
指示してもらったコマンド「systemctl start httpd」の実行結果は以下でした。
```
 
```
あー、あのー、あれ。ウェブサーバだっけな。起動してないんなら、ちょっと起動しといてくんない?
コマンドの実行が必要であれば、そのコマンドをJSON形式で指示してください。実行結果を返します。
指示内容を実行できたら「追加のコマンドは必要ありません」と答えてください。
--------------------------------------------------------------------------------
次に、ウェブサーバの状態を確認してみましょう。以下のコマンドを実行してください。
 
```json
{
  "command": "systemctl status httpd",
  "description": "Apache HTTP Serverの状態を確認します。"
}
```
 
これにより、ウェブサーバが起動しているかどうかが確認できます。結果を教えてください。
--------------------------------------------------------------------------------
コマンド[ssh root@localhost systemctl status httpd]を実行しますか?
================================================================================
指示してもらったコマンド「systemctl status httpd」の実行結果は以下でした。
```
● httpd.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
             /etc/systemd/system/httpd.service.d
             └─override.conf
     Active: active (running) since Tue 2025-08-26 22:48:29 JST; 4s ago
 Invocation: 9638ae5341dd4ad4a36c37ec35333ea1
       Docs: man:httpd.service(8)
   Main PID: 77463 (httpd)
     Status: "Started, listening on: port 80"
      Tasks: 177 (limit: 18293)
     Memory: 13.8M (peak: 15.2M)
        CPU: 127ms
     CGroup: /system.slice/httpd.service
             ├─77463 /usr/sbin/httpd -DFOREGROUND
             ├─77464 /usr/sbin/httpd -DFOREGROUND
             ├─77465 /usr/sbin/httpd -DFOREGROUND
             ├─77466 /usr/sbin/httpd -DFOREGROUND
             └─77467 /usr/sbin/httpd -DFOREGROUND
 
 8月 26 22:48:29 derota.itline.jp systemd[1]: Starting httpd.service - The Apache HTTP Server...
 8月 26 22:48:29 derota.itline.jp (httpd)[77463]: httpd.service: Referenced but unset environment variable evaluates to an empty string: OPTIONS
 8月 26 22:48:29 derota.itline.jp httpd[77463]: Server configured, listening on: port 80
 8月 26 22:48:29 derota.itline.jp systemd[1]: Started httpd.service - The Apache HTTP Server.
```
あー、あのー、あれ。ウェブサーバだっけな。起動してないんなら、ちょっと起動しといてくんない?
コマンドの実行が必要であれば、そのコマンドをJSON形式で指示してください。実行結果を返します。
指示内容を実行できたら「追加のコマンドは必要ありません」と答えてください。
--------------------------------------------------------------------------------
ウェブサーバ(Apache HTTP Server)は既に起動しているようです。実行結果に「Active: active (running)」とあり、ポート80でリッスンしていることが示されています。
 
したがって、追加のコマンドは必要ありません。
--------------------------------------------------------------------------------

  見事に日本語の自然文の指示によりウェブサーバを起動することができている。root権限で実行させる都合から、確認モード(INT=1)を指定しているが、元気があれば自動走行でもできる。

  必要な設定は以下。操作対象のサーバとアカウントはsshのコマンドパラメータとして与える。最初に既定で「cat /etc/os-release」と「id」の実行結果を渡すのは、AIにコマンドの動作環境を知らせるためだ。これは、なかなかのアイデアではないかな。

@configs[:xopilot] = {}
@configs[:xopilot][:ssh_cmd]    = ['ssh', 'localhost']
@configs[:xopilot][:first_cmds] = ['cat /etc/os-release', 'id']
@configs[:xopilot][:result_max] = 64
@configs[:xopilot][:ask_max]    = 20

  あ。ちなみに「XoPilot」というコマンド名は「ゾパイロット」と読む。「Xalebot」の姉妹品であることを暗示しつつ「eXtra Offhand Pilot」を意味しつつ、某マイクソソフトのアレに当てつけた名前でもある。

  なお、全部は紹介しきれないが、指示の達成率はそれなりに高く、以下のような指示を概ねクリアできている。

・時刻同期の状態を教えてください
・ホームディレクトリの下に動画はありますか? あれば、そのリストと、動画の長さを調べてください
・昨日のメールの送受信数を調べてください
・ホームディレクトリの下にhoge.txtというファイルをfuga!という内容で生成してください。
・/etc/hostsにhogeというホストを追加してください。IPアドレスは192.168.0.99です。
・/etc/hostsにhogeというホストがあれば削除してください。
・ホームディレクトリの下に開発物件はありますか? あれば、概要を教えてください。

  XoPilotは自製のngsライブラリのサンプルである。http://itline.jp/git/ngsに置いておく。


2025-08-09(Sat) 理詰めすぎたエンジン音

  前回、エンジンの回転数を元に、理詰めでエンジン音の生成を試みたのだが、概ね、コレジャナイ、という音になった。主な理由は音の成分が単一だからだ。

  走行音には、エンジン音以外にも、いろいろな音が混じっている。プロペラシャフトは、エンジンの回転数に同期して回転するが、ギアボックスはそれを何種類かの回転数に落とし、ドライブシャフトを回転させ、それに同期してホイールやタイヤも回転する。要するに、クルマは回転速度の異なる回転物体の集合体だということだ。それらは、1回転に1音とは限らず、様々な音を発する……結局、走行音は、様々な周波数が混じりまくった音なのだ。

  そこで、実際のレッドブルのオンボード映像の走行音をスペクトル分析してみた。対象はシフトアップする直前の0.1秒分。

  画像の説明

  支配的なのは200Hz弱と300Hz弱。後者がエンジン音だろう。が、それ以外にも高音成分がピョコピョコとある。

  それに引き換え、単純なノコギリ波だとこう。300Hzのn倍に無数にピークがあるが、規則的すぎる。これだと、聴感上はシンプルな印象になってしまう

  画像の説明

  そこで、基本となる300Hzのノコギリ波に、異なる周波数のノコギリ波をいくつも足してやる。

@length = 1
 
car1 = it = {}
it[:device] = 'generate'
it[:length] = @length
it[:type] = 'sawtooth_r'
it[:freq] = [(r = 300) * 10500 / 12000, r]
it[:amp] = [0.3]
 
car2 = it = {}
it[:device] = 'generate'
it[:length] = @length
it[:type] = 'sawtooth_r'
it[:freq] = [(r = 180) * 10500 / 12000, r]
it[:amp] = [0.4]
 
car3 = it = {}
it[:device] = 'generate'
it[:length] = @length
it[:type] = 'sawtooth_r'
it[:freq] = [(r = 800) * 10500 / 12000, r]
it[:amp] = [0.15]
 
car4 = it = {}
it[:device] = 'generate'
it[:length] = @length
it[:type] = 'sawtooth_r'
it[:freq] = [(r = 1500) * 10500 / 12000, r]
it[:amp] = [0.15]
 
add = it = {}
it[:device] = 'add'
 
@connection = [ car1, car2, car3, car4, add, add, add ]

  こんな音になった。まぁ、元のシンプルすぎる音よりは、だいぶ厚みが出て多少はそれらしくはなった。スペクトルはこう。多少なりとも似た感じになってはいる。まだまだ、コレジャナイ、という音ではあるが。

  画像の説明

  と、ここでアプローチを変えてみる。そもそも「支配的な音はエンジンの『燃焼』時の破裂音だから、音色は『鋸歯状波』に近い」という仮定は正しいのか。間違いなく正弦波ではないのだが、単純な鋸歯状波でもないだろう。

  実際のレッドブルのオンボード映像の走行音の波形はこうだ。

  画像の説明

  先の、複数のノコギリ波を重ね合わせたものがこう。

  画像の説明

  似ても似つかない。やはり、もう少し波形の形を似せないと、コレジャナイ、を脱出することはできないのではないか。と、ここで奇しくも、再びレトロゲー技術を投入することになるのであった。つづく。


2025-07-29(Tue) エンジン音を理詰めする

  次はサウンド関係に手を付けるかなぁ、とかいいながら、なぜか加速の物理挙動を組み込み始めたら止まらなくなってしまい、ほぼ完璧に組み込みを完了してしまったのだが、それはまた後日に扱うことにして、サウンド関係について少し進めることにする。

  F1ゲームでサウンドといえば、重要なのは走行音だ。特に実装したいのは「ドゥ、ドゥ、ドゥ、ドゥーン」という連続シフトダウンの操作の効果音だが、まずは通常のエンジン音を実装するのが先だ。

  エンジン音とは何か。雑に言えば「ブゥーン」という尻上がりのノイズ、なのだが、加速の物理挙動の組み込みがあまりに興味深かったので、効果音も適当に付けようという気にならなくなってきた。ここは理詰めで、可能な限りリアルな効果音を付けてみたい。

  エンジンとは「吸気、圧縮、燃焼、排気」の繰り返しを回転運動に変換する機構で、支配的な音は「燃焼」時の破裂音だ。なので、音色は「鋸歯状波」に近くなる。ノコギリのように素早く立ち上がって、スッと消える。そして、アクセルを踏んでエンジンの回転が高まると、破裂音の発生間隔が狭まる。つまり、周波数が高くなり、低音から高音に遷移していく。それが「ブゥーン」と「尻上がり」な音になる理由だ。

  基本となるパラメータはエンジンの回転数だ。rpm。Round Per Minute。1分間の回転数。3000rpmなら、50回転/秒。では、50Hzかというと、それは違う。4サイクルエンジンは2回転に1回しか燃焼しないからだ。では、25Hzかというと、それも違う。4気筒エンジンなら、基本的に各気筒が順次に燃焼するので、その4倍。100Hzが正解である。

  そこまでわかったところで音を出してみる。効果音の生成には、以前に作ったり、改良したりした、自製のツールを使う。記述は以下。

@length = 2
 
car1 = it = {}
it[:device] = 'generate'
it[:length] = @length
it[:type] = 'sawtooth'
it[:freq] = [100]
 
@connection = [ car1 ]

  こんな音になった。まぁ、ロードスターを含む、小型車のエンジン音、といわれれば、まぁ、そんな風に聴こえなくもない。波形はこう。

  画像の説明

  んが、これ「ノコギリのように素早く立ち上がって、スッと消える」の逆になっている。欲しいのは、こうではないか?

  画像の説明

  つうわけで、ツールに「sawtooth_r」を追加で実装してみる。

#---------------------------------------------------------------
#
#   鋸歯状波
#
wgens['sawtooth'] = Proc.new {|dev, p|
    p += 0.5
    (p - p.to_i) * 2 - 1                        # output: -1.0 - 1.0
}
 
#---------------------------------------------------------------
#
#   鋸歯状波(逆、破裂音?)
#
wgens['sawtooth_r'] = Proc.new {|dev, p|        # p: 波形の周期位置、最初の波形の中点なら 0.5、10 周期目の終点なら 9.9
    1 - (p - p.to_i) * 2
}

  こんな音になった……んが、聴感上では違いがわからないな。鼓膜が感知するのは経時的な圧力変化だから、そういうもんなのかもな。と、ここで、加速させてみる。2秒で3000rpmから6000rpmへと。

@length = 2
 
car1 = it = {}
it[:device] = 'generate'
it[:length] = @length
it[:type] = 'sawtooth_r'
it[:freq] = [100, 200]
 
@connection = [ car1 ]

  こんな音になった。チープだが悪くない。つうか実際、黎明期のレースゲームの走行音って、まさにこんな音だよね。

  とりあえず、ロードスターはコレでいいとして、次はF1マシンだ。F1マシンは12000回転くらいまで回して走る。そんなら倍の400Hzかといえば、これまた違う。6気筒エンジンなので、その1.5倍。600Hzになる……はずなのだが、オンボード映像の音声を解析してみると300Hzが支配的なんだよなぁ。どうやら、バンク角90度のV6という特性が影響しているらしい。ついでなので、10500〜12000回転でシフトアップする音を作ってみる。

@length = 1
 
car1 = it = {}
it[:device] = 'generate'
it[:length] = @length
it[:type] = 'sawtooth_r'
it[:freq] = [262, 300]
 
@connection = [ car1 ]
$ sox 6kitou_f1.wav 6kitou_f1.wav 6kitou_f1.wav 6kitou_f1_shift3.wav

  こんな音になった。3回繰り返しているだけだが、シフトアップしているようにも聴こえなくもない。

  これだけでも十分に高音だが、1990年代のフェラーリは17000回転も回して馬力を稼いでいた。しかも12気筒。フェラーリサウンドってやつだ。こっちも、オンボード映像の音声を解析してみると理論値の半分で850Hz。13000〜17000回転でシフトアップする音を作ってみる。

it[:freq] = [650, 850]

  こんな音になった。カン高いフェラーリサウンドの片鱗を感じられなくもないが、コレジャナイ。主な理由は音の成分が単一だからだ。つづく。