- BACKNUMBERS -
2024年 5月分
2024年 6月分
2024年 7月分
2024年 8月分
2024年 9月分
2024年 10月分
2024年 11月分
2024年 12月分
最新月

web6047 - 2024年 11月

私がプログラミングを好きなのは、探求心創造性を満たしてくれるからです。

会話 AI の Gemini との会話にて

- Special Documents -

特別な記事へのリンク

▼3DCG プログラミングの方法
▼書籍「はじめて読む486」の
サンプル動作環境の作成方法
▼3Dお姉さんによるプログラミング解説
▼RPG のルーツ(PDF)

ゲームコーナー 

▼クレイジーバルーン
(↑, ↓, ←, →)
▼テトリス
(←, →, ↓, x, y)

その他 単発のアプリ

▼矩形波は複数の波形の合成です

- 以降は日記です -

2024年11月4日

このサイト どうしよう(12月に解決しました) 

このページ、記事を書くとどんどん たまっていくんです。

うまく分割する方法を考えないといけないんだけど、いい方法が見つからないので保留中です。

今年の5月から書くままに書きためている…

2024年11月16日

やり方 ChatGPT アプリを使った英会話の方法 

~ ChatGPT で英会話を学ぶ ~

「デスクトップ版 ChatGPT」と「Google 翻訳」を使って、誰でも英会話を学べるのでやってみましょう。

私も今までこんなにいっぱい英語をしゃべったことはなく、まったく初めての体験となりました。

ChatGPTってすごいですね。


英会話をやってみるためには以下の手順を行ってください。

※ ChatGPT のアカウント(サインアップ)は必要なので、事前に行う必要があります。

  1. まず、この URL にアクセスします。
    ChatGPT の正規の「デスクトップ版 ChatGPT ダウンロードページ」です。
    https://openai.com/chatgpt/desktop/


    「Download for macOS」か「Download for Windows」のボタンを押します。
    ここでは Windows の場合で手順を進めます。

  2. ボタンを押すと、
    「次の場所の Microsoft Store にアクセスしています: English、、日本語にしますか?」
    と聞かれるので、「日本語(日本)に移動」ボタンを押します。

  3. すると、Microsoft Store のページが表示されます。
    「ダウンロード」ボタンを押します。

  4. すると、ブラウザでこのようにダウンロードされます。
    この項目「ChatGPT Installer.exe」をクリックします。

  5. すると、Microsoft Store アプリ専用のインストーラーが起動します。
    右下の「インストール」ボタンを押しましょう。


    アプリのダウンロードとインストールが開始されます。

  6. インストールが終わると、アプリが起動されます。
    ログインボタンを押してください。

  7. すると、ブラウザのほうで、ログイン画面が表示されるので、ログインします。

  8. すると、アプリのほうで、チャットが開始できるようになります。
    最下部のメッセージを入力する部分の右端の黒いアイコンをクリックします。

  9. すると、マイクを使って良いかと聞かれるので「はい」ボタンを押します。
    マイクを使わないと「しゃべって会話をする」というのができません。

  10. さらに、カメラを使って良いかと聞かれるので、"写真撮影したものについて話す" という使い方をしたい場合は「はい」ボタンを押します。

  11. すると、マイクからの入力を待つ状態になります。
    最初のうちは ChatGPT のバージョンが高い設定(会話の質が高く、本来有料だけどちょっとのあいだ無料で使える)になっていて、画面の中央は「きれいな青っぽいグラデーションアニメ」が表示されるようです。

    時間が過ぎるとノーマルバージョン(無料)になり、下図のように大きな黒い丸●になるようです。


    下部のアイコンのは、「マイク入力を現在受け付けている」ことを示しています。
    このアイコンだと「現在マイク入力できない状態」です。

  12. とりあえず、「もしもし?」と聞いてください。
    ChatGPT のウィンドウは前面に出ていなくても、話すことができます。
    たとえば、何か別のアプリで作業中に、独り言のようにしゃべると、裏で聞いていて、声で応答をしてくれます。
  13. もし、話しかけて英語で返事があったら、「えーっと、日本語でお願いします」と言ってください。
  14. ブラウザで Google 翻訳のページにアクセスします。
    https://translate.google.co.jp/

    中央上部のボタンを押して、「左側で日本語を入力したら、右側に英語が表示される」ようにしておきます。
  15. ChatGPT のアプリで、次の内容をゆっくりでいいので読み上げます。

    えーっと、こちら、僕(私)の方で Google 翻訳のページを開いて、 日本語を英語に翻訳して、その英語をしゃべるので、 君は英語で答えてもらっていいですか?

    下図のような画面構成で会話を進めるということです。
  16. 次に、たとえば以下のような日本語を翻訳に入力して、英訳を得ます。

    「ChatGPT の言うことはいつでも正しいですか?」
    Is ChatGPT always right?

    Google 翻訳にはスピーカーアイコンがあるので、クリックすれば正確な発音を聞くことができるので、参考になります。



    イズ、チャット・ジー・ピー・ティー、オルウェズ、ライト

    疑問文ではこの最後の単語の right の発音は上にあげますよね。やってみてください。
    ChatGPT に向かって英語を読み上げます。
  17. すると、ChatGPT は英語で答えてくれます。

    しかし、日本語しか分からない私たちは英語を聞いても意味が分からず、その後の会話が続きませんので、ChatGPT に以下のように英語で伝えます。
    カッコ内の日本語を翻訳に入力して英文を得て、スピーカーアイコンで発音を確認すると良いでしょう。

    After you say something in English, could youクッジュー please translate it ↓息into Japanese?

    I want to learn English conversationコンバーセーション, so please do thatドゥーザッ.

    (英語で話した後、続けて日本語の訳を言っていただけますか? 英会話を学びたいのでお願いします。)

    長文だと慣れない英語を かんでしまうので、あらかじめ頭の中で読み上げて
    • 単語の発音方法や、
    • 文のどこで息をつくのか
    など確認してから声に出すと良いです。

    伝わらないと、なかなか英語+日本語で話してくれないので、根気よく何度も伝えてください。
    うまく通じないときは、下記の★★部分の赤文字部分の方法で効率的に練習できます。
  18. すると、英語で回答したのち、日本語を続けてくれるようになります。
    これで英会話を学ぶことができるようになりました。

    会話が続かない場合は、以下の文を参考にして下さい。
あなたはどこから来ましたか? Where are you from?
もっとゆっくり話してください。 Please speak more slowly.
何か話題を考えてくださいよ。 Please think of a topic.
それより、私の話を聞いてほしいのですが? Instead, I want you to listen to what I haveハフ゛ to say.
(最近感動したことや、やろうとしていることを思い出して話す) (翻訳に入力します)


Google 翻訳のスピーカーを参考にして発音したいときは、ChatGPT 画面のマイクボタンを押してマイクをオフにします。そうすれば、練習中の発音を ChatGPT に聞き取られないようにできます。

翻訳のスピーカーは2回目の再生は少しゆっくりとしゃべってくれるようです。

慣れてきたら、翻訳のスピーカーによる発音と「ハモる」ように同時にしゃべってみてください。


★★欲を言えば、ChatGPT が話す英語は、音声を出しつつ英文も画面に表示してくれたらより勉強になると思います。

Windows 11 にて、

  1. 画面左下のウィンドウズマークを右クリックします。
  2. 「設定」を選びます。
  3. 左側のリストから(下の方の)「アクセシビリティ」をクリックします。
  4. 「聴覚」のセクションの「字幕」をクリックします。
  5. 「ライブ キャプション」をオンにします。
    すると画面上部に字幕を表示するエリアが表示されます。
    以後、ライブ キャプションが必要なときは、CTRL + Win + L で表示できます。
  6. そのエリアの右端の歯車アイコンをクリックします。
  7. 「言語を変更」を選びます。
  8. 最初は「日本語(日本)」になっていると思いますが、これを「英語(米国)」にして、続行ボタンを押します。

字幕エリアはドラッグして位置を変更できます。また4隅のどれか一つのカドをドラッグすればサイズを変更できます。

英語+日本語で回答をもらっているので、「英語(米国)」にしていると日本語の部分がローマ字みたいになるし、英語も必ずしもきちんと表示されるわけではないので、ほんとにおまけみたいなものですが参考にはなるかもしれません。

歯車アイコン>設定>マイクオーディオを含める を利用すれば自分の発音も英語として表示してくれます。これは自分がまともな発音をしているかどうかを確認することになるので、とても有効です。

ChatGPT のマイクをオフにして、正しく認識されるまで何度も同じ発音を繰り返すと良いでしょう。

ただ機械的に棒読みで読み上げ発音するのではなく、気持ちを込めながらしゃべると、より良くなると思います。


上記の手順をすぐに使えるように下記にまとめました。いつでも英会話してみましょう。

  1. ChatGPT アプリを起動する。("メインウィンドウ" にする)
  2. 右下のを押す。
  3. もしもし、日本語を話せますか?
  4. こちら、僕(私)の方で Google 翻訳のページを開いて、 日本語を英語に翻訳して、その英語をしゃべるので、 君は英語で答えてもらっていいですか?
  5. Google 翻訳を開く。
  6. After you say something in English, could you please translate it into Japanese?
    I want to learn English conversation, so please do that.
    (英語で話した後、続けて日本語の訳を言っていただけますか? 英会話を学びたいのでお願いします)
  7. 以後、日本語をGoogle 翻訳に入力し、表示された英語を(スピーカーボタンで確認後、)読み上げます。

2024年11月24日

生活 最近どうしてる? 

最近やっていること

駅のニューデイズのかたわらで展開されている農協の野菜売り場で「銀杏」が売られていて良さそうだったので買いました。50 粒くらい入っていて 350 円。

母に食べ方を聞いて、その通りにして食べたら普通にうまかったです。

カラに切り込みを入れて、フライパンで弱火、フタをして10分ころがす。塩を付けて食べる。食べ過ぎると良くないので 1 日 10 粒くらいまで。

観ているアニメは、

「推しの子」再放送、「進撃の巨人」再放送、「呪術廻戦」再放送、、といった感じ。

新作では、「ダンダダン」を観ています。人気アニメばかり観ているので普通と言えますかね。

最近見た映画は、

「65」。6500万年前の地球に不時着した男と少女。宣伝トレーラーは SF で面白そうだったのに、男と少女のやり取りが甘ったるくて苦しかった。舞台設定もいろいろ甘かった。レンタル 300円。

「インターセクション(吹替)」。リュック・ベッソン製作。複数の男女のそれぞれの交差を普通に描いた映画。出来が良くて見せる . . . 映画だった。YouTube 期間限定無料公開。8カ月前から無料公開が続いているみたいで、いつまでなのかが不明です。


RPG開発 試作品3 スクリーンショット 

RPG の試作品3です。スクリーンショットなので動作はしません。

前回の試作品2をボツにして、手順書(「RPGプログラミング手順書」)を使って再び1から作り直しています。

何度も何度も RPG を作り直していると、RPG の根源的なしくみが少しずつ見えてきます。

たとえば、「RPG は "行動" と "結果" を中心にプログラムできる」なんて、ちょっと早合点気味に思ったりしました。

それが本当に早合点なのか、それとも本当に根源的なしくみなのかは、もうちょっと進めないと分かりません。


2024年11月26日追記:

やはり早合点でした。

  • 記述がシンプル過ぎて意味不明となる(何をやっているのかわからない。見通しが悪い)
  • 細かい関数に分散させると、それらの関数から見た1つ上の変数スコープにアクセスする手段は「引数」しかなく、やりづらい。(たとえば戦闘画面で各コマンドが関数になると、戦闘画面で管理しているモンスターの配列にアクセスするには引数で渡すしかない)

2024年12月7日追記:

そう考えて戦闘画面のプログラムや、フィールド上のコマンドのプログラムに、直に各コマンド実行を書こうとしましたが、たとえば普通の道具を使うコマンドと、相手を攻撃する道具を使うコマンドを、どのように分けて書くのかが見当がつかず、結局、actionz、resultz を使う方法に戻しました。

その際の各変数にアクセスするスコープの問題については、アクセスしたい変数は全部 env というオブジェクトに収納して、env を各関数に引数で渡すことにしました。


下記はその考えをサンプルで示そうと思って作った JavaScript プログラムです。(行動のことをてふだと呼んでいます)

<script>
//「テスト」スクリプト
function onloadx() {

    actionz = {
        "てふだ1" : {
            exec : function() {
                console.log( this.name );
                resultz[ "けっか1" ].exec();
            },
        },
    }
   
    resultz = {
        "けっか1" : {
            exec : function() {
                console.log( this.name );
                resultz[ "けっか2" ].exec();
            },
        },
        "けっか2" : {
            exec : function() {
                console.log( this.name );
            },
        },
    }
// それぞれに name プロパティを自動的に追加
    for( let key in resultz ) resultz[ key ].name = key;
    for( let key in actionz ) actionz[ key ].name = key;
   
    actionz[ "てふだ1" ].exec();
}
</script>

※ このプログラム中の actionz や resultz というような「末尾に z を使った表記」は、「連想配列は ~z、普通の配列は ~s」という独自の命名規則によるものです。


▼上記プログラムの実行結果


RPG ではいろいろなコマンドを実行し、それに対していろいろな結果があります。

  1. 薬草を使ったら、仲間の体力が回復します。
  2. 敵を攻撃したら、敵はダメージを受けます。
  3. また、ある道具を敵に使っても、敵はダメージを受けます。

上記 2. 3. のように、異なる行動で、同じ結果が得られる場合があります。


また、薬草などの道具は、フィールドを歩いているときのコマンドメニューで使うことができ、そしてまた、戦闘画面でも使うことができます。

つまり、使った結果が同じならば、異なる行動で結果を共通化させることができ、また、フィールドでも戦闘画面でも同じ「行動と結果」がありえるので異なる画面で共通化させることができます。

さらには、プレイヤーがフィールド上を動き回ることも、一種の行動であり、そこに結果を設定することもありえます。たとえば、

  1. 町のマークに乗ったら、町に入るし、
  2. 毒の沼地の上に乗ったら、ダメージを受けます。


それから、上記のサンプルプログラムでも示していますが、

行動 → 結果1 → 結果2

というように結果が連鎖する場合もあります。たとえば、

「敵を攻撃して、敵はダメージを受ける。さらにその結果 敵が体力0になり倒れる」

という場合です。


RPG は行動だらけのゲームであり、行動だらけゆえに結果も大量にあります。

だからこの行動と結果を基本的なしくみとして とらえることができれば、プログラムはより簡潔になるのではと、期待しています。


下記は実際に「RPG の試作品3」で記述し始めた「行動と結果」のプログラムの一部です。

//--- actionz

actionz = {
    "道具を使う" : async function( $command ) {
        let darega = $command.darega;
        let dougu = $command.dougu;
        await narrate( `${darega.name}は${dougu.name}を使った!@k\n` );
        await resultz[ "結果ひとり回復" ]( dareni );
        
        let index = darega.dougus.indexOf( dougu );
        darega.dougus.splice( index, 1 );
    },
    "誰かに道具を使う" : async function( $command ) {
        let darega = $command.darega;
        let dareni = $command.dareni;
        let dougu = $command.dougu;
        await narrate( `${darega.name}は${dareni.name}に${dougu.name}を使った!@k\n` );
        await resultz[ "結果ひとり回復" ]( dareni );
        
        let index = darega.dougus.indexOf( dougu );
        darega.dougus.splice( index, 1 );
    },
    "こうげきする" : async function( $command ) {
        let darega = $command.darega;
        let dareni = $command.dareni;
        await narrate( `${darega.name}は${dareni.name}をこうげきした!@k\n` );
        await resultz[ "結果ひとりダメージ" ]( dareni );
    },
} // actionz

//--- resultz

resultz = {
    "結果ひとり回復" : async function( $dare ) {
        let heal = 3 + Math.floor( Math.random() * 10 );
        let healStr = han2zen( heal );
        await narrate( `${$dare.name}のHPが${healStr}回復した!\n@k` );
        $dare.HP += heal;
    },
    "結果ひとりダメージ" : async function( $dare ) {
        let damage = Math.floor( Math.random() * 10 );
        let damageStr = han2zen( damage );
        await narrate( `${$dare.name}は${damageStr}のダメージを受けた!\n@k` );
        $dare.HP -= damage;
            //check.
            if( $dare.HP <= 0 ) {
                $dare.HP = 0;
                await narrate( `${$dare.name}は倒れた!@k` );
            }
    },
} // resultz

このおかげで、戦闘画面のロジックの微妙に長く冗長だった部分が、ばっさりと消えて1行だけになってしまいました。


▼戦闘画面のロジックの微妙に長く冗長だった部分


▼ばっさりと消えて1行だけに


でもまだ使い始めたばかりなのでどうなるかは分かりません。

『簡潔だけど意味が不明』なコードよりは、『冗長だけど意味がよく分かる』コードのほうが良いです。

でも一番良いのは『簡潔で意味も良く分かる』という両立できているコードです。

「行動と結果」の仕組みが本当に良いものかどうかはまだこれからです。


※ 以下は上記「2024年12月7日追記:」で書いたご案内の、「再び actionz、resultz を使うようにした現状のプログラム」です。actionz は actionFunctionz、resultz は resultFunctionz という名前にしています。

色分け Red:文字列、Green:コメント、Cyan:順次・分岐・繰り返し・小プログラム、Orange:キーワードYellow:引数
//=== actionFunctionz let actionFunctionz = {     // #1     "たたかう" : async function( $env, $argz ) {         let actor = $argz.actor;         let target = $argz.target;                 await narrate( `${actor.name}は${target.name}をこうげきした!@k\n` );                 let argz = {             target : target,             power : Math.floor( Math.random() * 10 ),         }         await resultFunctionz[ "結果一人ダメージ" ] ( $env, argz );     },         // #2     "どうぐ" : async function( $env, $argz ) {         let comName;             if( $env.name == "キャンプ" ) {                 // キャンプでは「つかう、わたす、すてる」のどれか。                 comName = $argz.dousuru;             }             else if( $env.name == "戦闘画面" ) {                 // 戦闘画面ではすぐに「つかう」                 comName = "つかう";             }             else {                 err( "actionFunctionz['どうぐ']()", "$env.name が不正です.", $env.name, "$env.name や if文の条件を確認." );             }                     await $argz.dougu[ comName ] ( $env, $argz );     }, } // actionFunctionz //=== resultFunctionz let resultFunctionz = {     // #1     "結果ひとり回復" : async function( $env, $argz ) {         let target = $argz.target;             //check.             if( target.HP <= 0 ) {                 await narrate( `${target.name}は死んでいるので回復できない!\n@k` );                 return;             }         let heal = $argz.power;                 await narrate( `${target.name}のHPが${heal}ポイント回復した!\n@k` );                 target.HP += heal;     },         // #2     "結果一人ダメージ" : async function( $env, $argz ) {         let target = $argz.target;             //check.    相手はすでに死んでいる             if( target.HP <= 0 ) {                 await narrate( `しかし${target.name}はすでに死んでいる!\n@k` );                 return;             }         let damage = $argz.power + ( Math.floor( Math.random() * 6 ) - 3 );             //check.    修正             if( damage < 0 ) damage = 0;                 await narrate( `${target.name}は${damage}ポイントのダメージを受けた!\n@k` );                 target.HP -= damage;             //check.    倒した             if( target.HP <= 0 ) {                 target.HP = 0;                                 await narrate( `${target.name}は倒れた!@k\n` );                     //check.    モンスターの場合は                     if( $env.monsters.includes( target ) ) {                         target.visibility = false;                     }                 await resultFunctionz[ "全滅チェック" ] ( $env );             }     },         // #3     "結果全員ダメージ" : async function( $env, $argz ) {                 for( let target of $argz.targets ) {             let argz = {                 target : target,                 power : $argz.power,             }             await resultFunctionz[ "結果一人ダメージ" ] ( $env, argz );         }     },         // #4     "全滅チェック" : async function( $env, $argz ) {         if( $env.name == "キャンプ" ) {                     if( getAlives( $env.players ).length == 0 ) {                 await narrate( `\n@s200${$env.players[ 0 ].name}たちは全滅した...@k` );             }         }         else if( $env.name == "戦闘画面" ) {                     if( getAlives( $env.players ).length == 0 ) {                 await narrate( `\n@s200${$env.players[ 0 ].name}たちは全滅した...@k` );                 $env.endOfBattle = true;             }             else if( getAlives( $env.monsters ).length == 0 ) {                 await narrate( `@s10モンスターたちをやっつけた!@k` );                 $env.endOfBattle = true;             }         }         else {             err( "resultFunctionz['全滅チェック']()", "$env.name が不正です.", $env.name, "$env.name や if文の条件を確認." );         }     }, } // resultFunctionz