表面上は現在、

 

(1)プログラミングネタ(殆どC#でC++がなくなってきましたが...)-現在GhostLegが進行中(次回終了予定)

(2)Python日記(これも元ネタの終了まで行っちゃったので、直に終わりますね。)

 

をやっていますが、「一つ安定的なものが欲しいな」と考えているうちに、昔のブログのps.でC#用のOpenGLライブラリー、OpenTKというものに初めて触れていることに気が付きました。

2023年4月3日

 

OpenGLはC++で扱おうとして、返り討ちにあった奴です。

2024年2月12日

2024年2月15日

2024年2月22日

 

痛い目にあっているのに、またやるの?

OpenGL?

 

という感じなのですが、一応はチェックしようと調べてみました。すると、

 

大本山はここ

 

で、読んでみると現在はVersion 4.xですが、これは.Net用のようで、MSCompAssが使うC# 5(NetFrame)では、(もう更新しないらしい)OpenTK Version 3.x(そのリンクはVersion 3.3.1のダウンロードページに遷移する)とOpenTK.GLControl Version 3.3.3()を使え、ということのようです。

:これはOpenTK(C#用のOpenGL)をウィンドウコントロールとして使う為のものらしく、(後に出てきますが、OpenTKのGameWindow共々)OpenTKに特有みたいです。

 

このOpenTK Version 3.3.1OpenTK.GLControl Version 3.3.3"*.nupkg"ファイルになっており、

 

どうやってつかうの?

 

ということで最初の躓きとなりました。(このVersionも後に躓きとなりますので、よくご覧になってください。)

 

実はこの後も何度も大きな躓きが続きます。そして、やっと現在何とか前方が見張らせるようになった気がします。

 

そうだ、このOpenTKの躓き経験をブログネタにしよう!

 

というのが今回のテーマです。題して、

 

「OpenTK格闘記」

 

現在やっているGhostLegが終了したらこれを連載もので載っけます。乞ご期待!

 

前回まででアミダクジのコア部分をクラス化して機能を確かめたので、今後はこれをウィンドウプログラムに実装するのですが、直ちにコードを弄るのは早計で、その前にどのようなユーザーインターフェース(UI)にするのか、ウインドウのデザインを考える必要があります。

 

C#のプログラムは通常Visual Studioで、WinFormsであれWPFであれ、WYSWYG(注1)的にXamlエディターを使って色々とやるのでしょうが、MSCompAssの場合は「完全コーディングベース」なので一からコーディングしなければなりません。(注2

注1:"What you see is what you get"の略で、1980年代のApple McIntoshのFinder等、ウィンドウベースのの操作環境を指した言葉。なお、アップルのMacの語源は本当に「リンゴ」で洒落であったことが分かります。

注2:Win32のリソースエディターであるBCCFormの出力するリソースファイルをベースにC#のウィンドウ部分のコードにするコンバーターを作ろうか、と考えたこともありますが、只のVisual Studioがあるのに誰が使うか?と考え「没アイデア」にしました。

 

そんな訳で、巧妙性より効率性の方が重要ということから、つい直前までやっていた

 

Othelloプログラム

 

のドンガラを再利用することに決定しました。

 

これを使って、アミダクジの操作シーケンス

 

(1)アミダクジを作る(縦棒数と横棒を引く段数の設定が必要。)

(2)隣接する縦棒間に横棒を引いてゆく。

(3)(時には先に設定することや、複数設定することもあるようですが)「当たり」を無作為に設定する。

(4)各参加者(縦棒)のゴールを確認する。

 

をイメージしながら、まずはベースとなるこんなの↓を作ってみました。

 

しかし、

 

これをユーザー(操作者)が見たら、何をどの順で、どう操作してよいのか分からないのじゃないでしょうか?それはUIとしては失格です。又、Aボタンを押してもらうべきタイミングでBボタンが押されてしまう等の操作者の誤操作の可能性も考えなければなりません。そういった

 

あーでもない、こーでもない

 

を考えた挙句、

 

【初期状態】

下のユーザー指示に基づいて「サイズ設定」ボタンを押すしかないでしょう?これを押すと、

 

【縦棒数、段数設定ダイアログ】

ダイアログが出て縦軸と横棒を描く段数を設定します。これも誤入力を避けるためにコンボボックスにし、更にメインウィンドウのサイズもあるので選択する縦棒数、段数の範囲も「合理的」に設定する必要があります。(

:実は当初「選択幅は広い方が良い」と考え、多数の選択肢を用意しましたが、却って操作者に混乱を与えるだけと考え、

(1)「2~3人ならじゃんけんの方が早いよね?」「大勢人がいるなら、寧ろビンゴ形式になるよね?」ということから、縦棒数は「4~8」に、

(2)また横棒数はその倍の「8~16」に

しました。これは今考えると大正解ですね。また、選択肢はスクロールバーを使わないで一挙に全部見せするようにしました。

 

【開始】

アミダクジのサイズを決定すると、そのサイズに合わせてウィンドウサイズが決定されるようにして、煩わしいスクロールバーでの部分表示を避けました。又ユーザー指示に次の操作は「横棒を引くこと」であり、操作方法も表示されるので、誤操作の危険は避けられるでしょう。なお、「サイズ設定」ボタンは不要なので消し、「開始」ボタンを表示させます。

 

【横棒引き】

「開始ボタン」を押すとこの「横棒を引く操作」の画面になります。また、各縦棒とゴールのラジオボタン(〇)は、誤操作を避けるために機能を殺してあるのでいくらクリックしても反応しないようにし、「開始」ボタンは不要なので消し、「ゴール設定」ボタンを表示させます。横棒を引き終えるまでは「ゴール設定」を押さない、ということが分かるでしょうか?(仮に押しても問題ありませんが...ただ縦棒=ゴールになるだけです。)

 

アミダクジの上でマウスをクリックするとその部分がハイライト表示(↑)となり、隣接する縦棒をクリックして横棒を描画します。段がぶれて斜めとなったり、隣接縦棒以外を押したり、更に既に横棒を描いたところを選択するとエラーメッセージが出ます。(今考えれば、「既に横棒が引かれています」というエラー処理ではなく、「既に横棒が引かれていますが、削除しますか?」にして単純縦棒()に戻す、編集機能を入れてもよかったですね。まぁ、暇なら今度やりましょう。)

 

【ゴールの設定と各縦棒のゴールチェック】

横棒を引き終えて「ゴール設定」ボタンを押すと、アミダクジの下にあるゴール(ラジオボタン)に「当たり」が乱数により設定され、選択不能だった各縦棒ボタンが有効になります。又、最初に表示された「サイズ設定」ボタンが再度現れ、「ゴール設定」ボタンが消えます。

最後に(ここは正直迷ったのですが)当たりの判定をPCによって自動的に表示させるのではなく、

 

ユーザーが各縦棒のボタンを押して、いちいち確認する

 

方法を採りました。

 

何故そうしたのか?

 

それは、「PCが勝手にやって、私はそれを眺めているだけ」のソフトは直ぐに飽きられることが経験的にわかっているからであり、

 

ユーザーが自分で確かめる行為を通じた、アミダクジ参画感

 

を醸成させるのが目的でした。(成功していると思いますが、どうかな?)赤棒によるアミダクジ経路も分かり易いので納得感もあるでしょう?

 

もう一回!

 

となれば、再度「サイズ設定」ボタンを押して初期化を行い、同様の操作を繰り返すことになります。

 

まぁ、実際のアミダクジを紙と鉛筆でやるのと同様の操作感は確保できたのではないでしょうか?

 

そう祈ります。なお、次回はこのウィンドウプログラムのコードとコンパイルの注意を解説します。

 

TBSの日曜劇場で「アンチヒーロー」というドラマが始まりました。

 

私は元々が保険屋で、1990年代に5年間NYCを拠点に、社内弁護士と全米の訴訟管理を行っていたこともあり、65歳で定年を迎えるまで、日本、米国の弁護士さん達とよく交誼を交わしておりましたので、小説やドラマも所謂「弁護士もの」は大好物でした。(

:昔子供の時にみた「12人の怒れる男("12 angry men"(注 of 注))から興味を持ちましたが、特に米国訴訟を仕事としてやるようになり、"A time to kill(「評決のとき」)からジョン グリシャムJohn R. Grisham)に嵌り、今では殆どの作品のペーパーバック本を捨てないで持っています。

注 of 注:この題名、「不適切にもほどがある」代表みたいなものですが、なんでこうなったのかと"12 angry men why no women or female jurors"で調べてみたら、

"The film came out in 1957 which was the same year that women were given the right to be on federal juries in the The Civil Rights Act of 1957. The script was written in 1954 and the setting of New York did not allow women on federal juries until 1968 so that is why all of the jurors are male."

なんだそうです。偉そうなこと言っても、米国は1957年公民権法以降でも差別は後を絶たなかったということです。

 

で、

 

大好物の弁護士もので、結構な役者さんたちも出てきて(「VIVANT」以降の手法のようですが)TBSの秘匿による盛り上げにも拘らず、

 

違和感

 

を感じるんですよねー。

 

(20年来の朝風呂派なんで)今朝風呂に入っていて、それを考えてみると、

 

(1)弁護士さんが喰ってゆくには、弁護士報酬をもらう必要があり、一般に民事事件の方が刑事事件よりも割が良い。

(2)このドラマは刑事事件で、それも恐らく国選弁護人("Pro-bono attorneys - 'Pro bono publico' usually shortened to pro bono, is a Latin phrase for professional work undertaken voluntarily and without payment.")なので、報酬はminimumでしょう。

(3)確かに刑事弁護で無罪を勝ち取ることで知名度が上がり、本人及び事務所が有名になって収入が増えることは事実でしょうが、それにはtaking much, much timeだし、依頼人は政治家や反社に流れるようになると考えられます。

(4)また(米国では陪審や証人の買収なんてよくありますが)日本で刑事訴訟法や弁護士コード違反を犯してまで、刑事弁護でリスクを冒すなど、リターン(+のみならず、刑事罰を受ける可能性等の-も)を考えると「ありえねー」感が半端ないです。

 

そんなことを考えていると、

 

長谷川博己は結局、何がしたいの?

 

という疑問が違和感の原因となっていることが分かりました。金か(無理)、名誉か(工員の発作的殺人を無罪にしてどのようにして社会的名声を得るのか?)、それともなんだ?

 

実は長谷川博己が大金持ちで、趣味で刑事事件連覇を目指していた

 

というのは殆どジョークにしかならないし。(御子柴弁護士もいるし。)

 

分からねー。

 

更に、このドラマの題名。

 

「アンチヒーロー」

 

って、何さ。

米語なら「アンタイヒーロー」じゃないの?と軽く考えて、確認したら、

 

あれれっ?

しょっぱなから「アンチヒーロー」ときました。

 

マジかっ!!!

 

と調べ続けると、

やっぱりこれだよねー。しっかし、どっちが優勢なんだろう?と最後はオックスフォードで調べました。

まぁ、こんなものかもね。

 

現在ブログではアミダクジのクラス化と、それを使ったコンソールテストプログラムをやっていますが、リアルではウィンドウプログラムへの実装を終了し、満足のゆく動作を示しています。

 

この為、先回りして次のネタを探っているのですが、

 

なかなか...

 

そんな時にふと思いついて「物理シミュレーション」でググると、出てくるは、出てくるは、色々とあります。

 

シミュレーション(PhET)

 

 

こういうのを見せつけられると、

「これ以上って、無理っ!」

という反応しか返せない。

 

しかし、

 

物理シミュレーションで楽しい世界

 

ってあるんですよねー。

 

そう、あれはまだ大学1年だったか、ボーリング場にあった、アーケードゲームの草分け的月面着陸ゲームに嵌りましたよ。(大分小銭を使ったなー。)

今でもあれは物理シミュレーションゲームの名作だと信じています。

 

ps. やってみなはれ。結構ムズイよ。

 

前回予告したように、今回はアミダクジのコア部分を(ウィンドウプログラム化を視野に入れながら)、コンソールプログラムでテストしてみます。(実際に開発の時に使ったプログラムです。)

 

アミダクジは、wikiで見ると数学が云々等記述がありますが、アルゴリズム的には極めてシンプルなので直ぐに出来上がってしまいました。要すれば、

(1)アミダクジを作る(縦棒数と横棒を引く段数の設定が必要。)

(2)隣接する縦棒間に横棒を引いてゆく。

(3)(時には先に設定することや、複数設定することもあるようですが)「当たり」を無作為に設定する。

(4)各参加者(縦棒)のゴールを確認する。

という機能があればよいわけです。

 

以下はアミダクジのクラス部分でいつもの通り、コメントと「解説:」を加えてゆきます。

 

【Amidakujiクラス】

    public class Amidakuji                    //アミダクジクラス
    {
        //Amidakujiクラスフィールド(解説:実際はプロパティになっていますね!汗;)
        public int Bars {get; set;}            //縦棒数-アミダクジ配列の列数(横棒数)
        public int Steps {get; set;}        //アミダクジの段数-アミダクジ配列の行数
        public int Goal {get; set;}            //当たりの列
        private int[,] Data = null;            //アミダクジデータ配列
        //コンストラクター
        public Amidakuji()                    //引数無し
        {
            Init();    //解説:初期化するメソッドです。
        }
        public Amidakuji(int col, int row)    //縦棒数と段数を指定
        {
            Init();
            Generate(col, row);    //解説:縦棒数(col)と段数(row)で配列を生成、初期化します。
        }
        //初期化メソッド
        public void Init()    //解説:初期値はいい加減です。(別に0でもよかったんですが...)
        {
            Bars = 1;                        //アミダクジの縦棒数初期値
            Steps = 16;                        //アミダクジの段数(横棒数)初期値
            Data = null;                    //アミダクジデータ配列
        }
        //アミダクジ配列生成メソッド
        public void Generate(int col, int row)
        {
            Bars = col;
            Steps = row;
            if(Data != null)
                Data = null;                //アミダクジデータ配列の再初期化
            Data = new int[Bars, Steps];    //アミダクジデータ配列の設定
            for(int i = 0; i < Bars; i++)
                for(int j = 0; j < Steps; j++)
                    Data[i, j] = 0;            //アミダクジデータ配列データの初期化(解説:0は単なる縦棒の添字です。)
        }
        //アミダクジデータ配列データの取得(解説:特定の(縦棒・段)のデータを取り、そのイメージを表示する為
        public int GetData(int col, int row)
        {
            return Data[col, row];
        }
        //アミダクジに横棒を左から右に引く
        public bool StepL2R(int s, int row)    //s列と(s + 1)列の間に横棒を引く
        {
            if(row < 0 || row >= Steps)        //縦の範囲外
                return false;
            if(s < 0 ||                        //横の範囲外
                s >= Bars - 1)                //一番右の列の右に横棒は引けない
                return false;
            if(Data[s, row] != 0)            //既に横棒が引かれている
                return false;
            Data[s, row] = 1;                //横棒の左半分
            Data[s + 1, row] = 2;            //横棒の右半分
            return true;
        }
        //アミダクジに横棒を右から左に引く
        public bool StepR2L(int s, int row)    //s列と(s - 1)列の間に横棒を引く
        {
            if(row < 0 || row >= Steps)        //縦の範囲外
                return false;
            if(s <= 0 ||                    //一番左の列の左に横棒は引けない
                s >= Bars)                    //横の範囲外
                return false;
            if(Data[s, row] != 0)            //既に横棒が引かれている
                return false;
            Data[s, row] = 2;                //横棒の左半分
            Data[s - 1, row] = 1;            //横棒の右半分
            return true;
        }
        //縦棒のアミダクジの結果を返す

        //解説:前回のGhostLeg0~8.bmpのイメージを思い出してください。ウィンドウプログラムでは、各棒のゴールまでの経路をこのビットマップを配列に入れて示すからです。)
        public int CheckResult(int c)
        {
            int result = c;
            //アミダクジ全体で赤棒(解説:ビットマップ4~8)を元(解説:ビットマップ0~2)に戻す
            for(int i = 0; i < Bars; i++)
            {
                for(int j = 0; j < Steps; j++)
                {
                    switch(Data[i, j])
                    {
                        case 4:
                            Data[i, j] = 0;
                            break;
                        case 5:
                        case 8:
                            Data[i, j] = 1;
                            break;
                        case 6:
                        case 7:
                            Data[i, j] = 2;
                            break;
                        default:
                            break;
                    }
                }
            }
            //経路を赤棒で示す
            for(int i = 0; i < Steps; i++)
            {
                switch(Data[result, i])
                {
                    case 0:
                        Data[result, i] = 4;
                        break;
                    case 1:
                        Data[result, i] = 5;
                        result++;
                        Data[result, i] = 6;
                        break;
                    case 2:
                        Data[result, i] = 7;
                        result--;
                        Data[result, i] = 8;
                        break;
                    default:
                        break;
                }
            }
            return result;
        }
    }
}

 

えっ、たったこれだけ?

 

そうなんです。アミダクジ自体は簡単な内容です。とはいえ、これが正しく動いているか、テストプログラムで検証します。

 

【TestGhostLeg.cs】

////////////////////////////////
// Amidakuji Class Test Program
////////////////////////////////

using System;

namespace TestGhostLeg
{
    //アプリケーションクラス
    public class App
    {
        //アミダクジ配列の列数、行数
        static int col = 8, row = 16;
        //Amidakujiクラスインスタンスの生成
        static Amidakuji adk = new Amidakuji(col, row);
        //解説:Mainメソッド(エントリーポイント)がstaticなので、そこで使うオブジェクトもstaticにする必要があります。


        [STAThread]
        public static void Main()
        {
            //adk.Generate(col, row);    //↑の行を引数無しで宣言した後、このように再設定できる。
            Console.WriteLine("今回の縦棒数は{0}、段数は{1}です。", adk.Bars, adk.Steps);

            //横棒を引く
            bool cont = true;
            Console.Write("これから横棒を追加します。\r\n");
            while(cont)
            {
                //アミダクジの表示
                DispGL();
                DrawHorBar();
                Console.Write("横棒の追加を終了しますか?(yまたはYを入力してください。):");
                string yn = Console.ReadLine();
                if(yn == "y" || yn == "Y")
                    break;
            }

            Console.Write("\r\n");
            for(int i = 0; i < col; i++)
            {
                Console.WriteLine("縦棒{0}の結果は{1}でした。 ", i, adk.CheckResult(i));
                //アミダクジの表示
                DispGL();
                Console.Read();
            }

            //表示したままにする為
            Console.Read();
        }

        //アミダクジの表示
        public static void DispGL()
        {
            for(int j = 0; j < row; j++)
            {
                for(int i = 0; i < col; i++)
                    Console.Write("{0} ", adk.GetData(i, j));
                Console.Write("\r\n");
            }
        }

        //横棒を引く
        public static bool DrawHorBar()
        {
            string num;
            int s, e, r;
            Console.Write("開始列(0-{0})は?:", adk.Bars - 1);
            num = Console.ReadLine();
            if(!Int32.TryParse(num, out s))
            {
                Console.WriteLine("整数ではありません。");
                return false;
            }
            Console.Write("終了列(左右いずれかの隣接列)は?:");
            num = Console.ReadLine();
            if(!Int32.TryParse(num, out e))
            {
                Console.WriteLine("整数ではありません。");
                return false;
            }
            Console.Write("行(0-{0})は?:", adk.Steps - 1);
            num = Console.ReadLine();
            if(!Int32.TryParse(num, out r))
            {
                Console.WriteLine("整数ではありません。");
                return false;
            }
            if((s < 0 || s >= col) || (e < 0 || e >= col) || (r < 0 || r >= row))
            {
                Console.WriteLine("領域外です。");
                return false;
            }
            if((s == e) || ((s - e) > 1) || ((e - s) > 1))
            {
                Console.WriteLine("開始列と終了列が同じ、または離れすぎています。");
                return false;
            }
            if(e > s)
            {
                if(!adk.StepL2R(s, r))
                {
                    Console.WriteLine("位置が不正で横棒を引けません。");
                    return false;
                }
            }
            else
            {
                if(!adk.StepR2L(s, r))
                {
                    Console.WriteLine("位置が不正で横棒を引けません。");
                    return false;
                }
            }
            return true;
        }
    }
 

とこんな感じです。それでは実行時の画面を見てみましょう。

 

<起動時画面>-縦棒は"0"で表されます。

<横棒画面>-黒の縦棒は"1"と"2"で表されます。

<ゴール確認画面>-赤棒の縦棒は"4"、"5"、"6"と"7"、"8"で表されます。

 

次はこれをウィンドウプログラムに移植することになります。

 

(アミダクジを始めたので、少しご無沙汰させて頂きましたが)前回までの「Python初体験」の続きです。

またまた変なのが出てきました。「シーケンス」という概念です。

 

既にデータ集合(「リストやタプルなどのオブジェクトは、コレクションの一種で、他のオブジェクトを登録し、集約できるオブジェクトです。」-Python初体験から)である「コレクション」は学びましたが、コレクションの内、
シーケンスとは、コレクションのうちで、集約する要素が一定の順序で並んでいて、その順序(インデックス)を使ってその要素を指定できる種類のオブジェクトのことを指します。
コレクションに属するオブジェクトでも、リストやタプルとは違って、辞書 は、順序を指定して要素を指定することはできません。このため、辞書はコレクションですが、シーケンスではありません。
」-Python初体験から

前回リストとタプルで比較演算をやりましたが、一応「要素の数、または要素」の比較が出来ました。しかし辞書(注)はエラーになります。

#サンプルコード
dict1 = {"dog": "犬", "cat": "猫"}
dict2 = {"dog": "犬", "cat": "猫"}
print(dict1 <= dict2)


<出力>
TypeError                                 Traceback (most recent call last)
<ipython-input-95-f273e382d9ed> in <module>
      2 dict2 = {"dog": "犬", "cat": "猫"}
      3 
----> 4 print(dict1 <= dict2)
TypeError: '<=' not supported between instances of 'dict' and 'dict'
注:辞書の場合、要素は"値 = 辞書[key]"またはgetメソッドで取得します。
# サンプルコード
dict = {"dog": "犬", "cat": "猫"}
# 辞書から値を取得
val = dict['dog'] # 添字がキー
print(val)  #「犬」(値) 
# 存在しないキーを指定した場合
val = dict['猿']  # KeyError
# 例外を発生させずに値を取得
val = dict.get('犬', 'not found')
print(val)  #「犬」(値) 
val = dict.get('猿', 'not found')  # エラー(例外)が発生しない
print(val)  # "not found"


少し話が脱線しましたが、いずれにしてもこのようにコレクションの内、要素を「順番(要素を整数の添字)」にアクセスできるものをシーケンスと言ってよいのではないかと思われます。

 

今回から久々のプログラミング中継です。何を、どう作るかは前回の仕様メモをご覧ください。

 

現在は(昔のコンサルティング業時代であれば「フェーズ1」等というでしょうが)仕様メモの「『先ずはTestGhostLeg.csというコンソールベースのテストプログラムでAmidakujiクラスを作成、テスト』し、それをアプリクラスのGhostLegクラスに組み込むことで完成させる。」の青字部分を終了した位ですね。

 

では、現在のコードをご披露しましょう ... と期待したアナタ、

 

残念でしたー。

 

今日はGhostLeg(基本デザイン像をどんな風に考えたかをご紹介することにします。

:アミダクジは西欧にはなかったものらしく、(英語として"Amidakuji"があるくらいで)対応原語がありません。唯一訳語らしいものはこの語のみで、英文Wikiには以下の説明があります。

"Ghost leg is a method of lottery designed to create random pairings between two sets of any number of things, as long as the number of elements in each set is the same. This is often used to distribute things among people, where the number of things distributed is the same as the number of people. For instance, chores or prizes could be assigned fairly and randomly this way.
It is known in Japan as Amidakuji (阿弥陀籤, "Amida lottery"), in Korea as Sadaritagi (사다리타기, literally "ladder climbing") and in China as Guijiaotu (Chinese: 鬼腳圖, literally "ghost leg diagram")."

 

アミダクジのイメージと仕様から最初に考えたのは「アミダクジは数十人、否、十数人の規模でやることは稀で、せいぜい8名程度ではないか」で、アミダクジをマトリックス(2次元配列)

 

 1 2 3 4 5 6 7 8

A

B

C (ここにアミダクジを表現する)

 

としてデータ化しようということです。

 

しかし、これを最終的にウィンドウ上に視覚的に表現することも必要になってきます。

 

ならば、

 

とうことで、最初にアミダクジを作ってしまって、それを表現するマトリクスを後で考えることにしました。(BCCFormなどでやった、「リソースからコードビハインドを考える」手法ですね。)

取り敢えず、普通の状態(No. 0 - 2)、選択状態(No. 3)、ゴールまでの地の利を表す赤線もの(No.4 - 8→上からきて右、左に分かれるので4つになります)を作成しました。これをリソースで読み込んでBitmapのインスタンスを配列で持つことを考えると、アミダクジマトリックスに入れるデータは自ずと決定(配列点字である0 - 8)されます。

 

後は、

 

Amidakujiクラスを作って、メンバーフィールドにアミダクジマトリクス等を作り、

(1)初期化メソッド

(2)アミダクジマトリクス生成メソッド

(3)横棒を引くメソッド(これも左→右と右→左の二つを用意しましょう。)

(4)アミダクジマトリクスの特定座標のデータを取得するメソッド

(5)指定列の結果を調べ、(普通の状態を赤字状態に変えて)結果を返すメソッド

を組み込めば、アミダクジの基本機能は確保できます。(これが冒頭の青字部分です。)

 

次回は此処迄のAmidakujiクラス開発の内容とコードを「コンソールベースのテストプログラム」()で解説します。

:最終的にウィンドウプログラムを作る場合でも、アルゴリズムのチェックやコードのチェック等部品化の段階でコンソールプログラムで機能チェックを行うことが手戻りが少なく効率的な開発方法だと思っています。

 

今回でプログラミングネタ探しの【無駄話】は終わり(注)にし、シリーズ物のプログラミングネタにします。

注:このネタが終了すれば、いずれ、元の通り同じ【無駄話】が始まると思いますが、ご容赦願います。

 

今回のプログラミングネタは、

 

あみだくじ

 

です。

 

なーんだ、期待して損した!

 

と思ったあなた、あみだくじを馬鹿にしてはなりません。

 

プログラミングの面白さは、

 

プログラミングの対象となる主題の調査研究

 

から始まります。今回もあみだくじ(注)の「そもそも」を現在勉強中であり、それを踏まえてシリーズ第1回を始めようかと考えております。

注:呼称をどうするかも現在検討中。「あみだくじ」、「アミダクジ」、「阿弥陀籤」、"GhostLeg"、"Amidakuji"等様々です。以下参照サイトです。

(1)Wiki (網羅的に全体像が書かれていますね。)

(2)禅の視点(室町時代のアミダクジの画像が出ています。)

 

ご参考までに、「大体こんなものを作りたい」と思った場合、私は(特に物忘れがひどくなってきたこともあり)備忘として仕様メモを作成しますが、今回のメモ書きは以下のようになっています。さて、どんなものになるのやら?

 

【GhostLeg仕様】

1.C#(WinForms)を使ったウィンドウベースの「あみだくじ」ゲーム
2.画面レイアウトはダイアログベースで左にあみだくじのグラフィック表示、右に操作系ボタン
3.表示はアプリ側でビットマップを使ったクラス(GhostLegクラス)とし、あみだくじ自体はそのクラス(Amidakujiクラス)を設ける。
4.操作シーケンス配管の通り。
(1)ウィンドウ表示(初期状態-あみだくじは表示されない。)
(2)開始ボタンを押すと「プレーヤー数(列数)入力ダイアログ」が現れ、選択入力する。(最大は8名程度?)
(3)列数(プレーヤー数)に基づき、あみだくじクラスインスタンスを作成し、初期状態のあみだくじ表示を行う。
(4)その状態であみだくじ画面をマウスクリックして横棒を引く。
  ①横棒はあみだくじの列の行をクリックし(選択フラグOn)、
  ②左右いずれかの列の同じ行をクリックして(選択フラグOff)
  ③横棒を表示する。(横棒付きビットマップと入替える。)
  ④上記②の段階で不適切な場所がクリックされた場合、エラー表示を行い、選択フラグをOffにする。
  ⑤一旦横棒が引かれた列の当該行は以降②の選択できない。(エラー表示)
  ⑥但し、同じ行でもまだ横棒が引かれていない列は選択や、横棒を引くことが可能。
(5)最後に「当たり(Goal)」(排他的にラジオボタン?-上記(2)で作成、配置する)を選択する。(これは恣意的にできないように乱数を用いるか?)
(6)最後は当たりの列を表示するか、各列のボタンを押すとどの列に行くか表示するか、のいずれかとする。

先ずはTestGhostLeg.csというコンソールベースのテストプログラムでAmidakujiクラスを作成、テストし、それをアプリクラスのGhostLegクラスに組み込むことで完成させる。

 

【現在の姿】

 

【おまけ】

「あみだくじ」なんて、まだそんなにやっていないだろうと思っていましたが、結構先人が手を付けていますね。

C

C

Python

汎用

ご住職さんか?

 

いつも、

 

こればっかし書いている気がする?

 

という標記ですが、再度背景を要すれば、

 

(1)ROM BASICしかない昔は言語、開発環境も選択肢がなく、レベルも低く、全く整備されていなかった。

(2)気の利いた開発環境はお金(注)があれば何とか手に入れることが出来たが、その値段は滅茶苦茶高かった。

(3)従って素人の趣味プログラマーは、インタープリターとコンパイラーであるとを問わず、フリーの言語を探し、

(4)自分で開発環境を整える必要があった。(私のBCCForm and BCCSkeltonもその一例です。)

注:Visual C++やVisual BasicがVersion 6 辺りの頃は、冗談でなく、Visual Studioのフルセットがン十万円しました。

 

そういうことで、プログラミング対象はプログラミング用専用エディターとか、コンパイリングツール(注)、作ったライブラリーのサンプルプログラム等プログラミングネタには事欠かなかったのです。

注:私は最初にBCC Developerを使っていましたが、それを使ってBCCFormから始まり、BCCSkeltonライブラリーとSkeltonWizardや関連ツールを大量に作ることになりました。

 

所が、時は移り、MS帝国はインターネット軍の攻勢で開城し、開発環境が無料で提供(注1)されるようになり、ライブラリーもインターネット技術を加えて多様化、高度化して、

 

ソート・サーチ等大抵のアルゴリズム(注2)、各種データ、ウィンドウコントロールや入出力等プログラミングサービスがコンポーネント化されて、ライブラリーで提供されるようになった

 

ので、素人プログラマーはそういう「プログラミングネタ」を喪失することになりました。

注1:昔Borlan C++ Compilerをフリーにして注目を集めたBorlandとその承継会社は現在もC++ Builderのフリー版(但し年限が1年)を提供していますが、帝王Micro SoftがVisual Studioを多様な言語込みでフリー(年限無し)にしたので大分苦戦しているみたいです。

注2:その他暗号化や3次元描画等は言うに及ばず、Pythonでは機械学習も提供されています。

 

と、いうわけで、

 

素人プログラマーのネタは「一般ユーザーが使うであろうツールやアプリ」に限定されることになるのですが、

 

そんなもんはもう既に事業者やセミプロによって開発しつくされている

 

というのが実情ではないでしょうか?

 

この実証としてキーワード「プログラミングネタ」で検索すれば、「プログラミングを始めたけれど、何を作っていいのか分からない」という方が如何に大勢いるかわかります。また、そういう人の為のプログラミング教育ビジネスも多数存在しています。

 

しかし、

 

口では「今後はプログラミングが重要、(特に子供には)勉強しておくべき」とか「収入の高いプログラミング言語は?」とかの文句がウェブに散らばめられていますが、

 

・そんなもんは1980~2000年代までの話で、

・今は素人が一発当てるような環境にはなく、

・「コード屋」は競争が激しくて使い捨ての現状で、

・更に追い打ちをかけてAIがプログラミング領域に侵食してきている

 

環境であり、もう人間が必要とされる領域ではなくなってきているのではないかなー?と懸念されます。(注)

注:それよりは、グラフィックデザインやリソース関連デザインの方が「人間にしかできない仕事」として貴重ではないかな、と考えられていましたが、ご存じの通り、映像分野でのAIの飛躍的発展により、そこも可也やばくなってきているように思えます。

 

矢張り、

 

いつもこんな愚痴ばっか書いている?

 

と考えざるを得ないのですが、(余り気が進まないのですが)今一つネタを温存しています。まぁ、役にはほとんど立たないでしょうが、上記を考えれば「一般人が使うことがある、まだ未取り組みの希少な分野」のツールではないかと考えています。

 

では質問です。

 

それはなんでしょう?

 

答えは、いずれ開発した時に。

 

前回までの「Python初体験」の続きです。

List、Dictionary、Tuple等の配列を、Pythonでは総称してコレクション(Collection-データ集合とでも訳しますか?)と呼ぶそうです。(文字列も一種の配列だそうです...)

演算子も'=='、'!='、'<(=)'、'>='の他、in(検索キーが要素の中に存在しているか否か)演算子も使え、特にfor文と組み合わせると有効ですね。


【演算子の使用例】
list_obj = [1, 2, 3, 4]
dict_obj = {"dog": "犬", "cat": "猫", "bird": "鳥", "snake": "蛇"}
tuple_obj = (1, 2, 3)
str_obj = "12345"
print("list_obj[2] in str_obj ? : ", str_obj[2] in str_obj)
print("dict_obj['dog'] == dict_obj['snake'] ? : ", dict_obj['dog'] == dict_obj['snake'])
print("tuple_obj[1] in list_obj ? : ", tuple_obj[1] in list_obj)
<出力>
list_obj[2] in str_obj ? :  True
dict_obj['dog'] == dict_obj['snake'] ? :  False
tuple_obj[1] in list_obj ? :  True

そしてコレクション全般に対応できるメソッドがあるそうで、例としてlen()関数を挙げています。
「辞書・タプル・リスト・文字列と、どの型のオブジェクトでも、コレクション であれば、同じように len() 関数で要素の数を求められます。」

【len()の使用例】
ict_obj = {"dog": "犬", "cat": "猫"}
print("辞書の要素数は:", len(dict_obj))
<出力>
辞書の要素数は: 2

tuple_obj = (1, 2, 3)
print("タプルの要素数は:", len(tuple_obj))
<出力>
タプルの要素数は: 3

list_obj = [1, 2, 3, 4]
print("リストの要素数は:", len(list_obj))
<出力>
リストの要素数は: 4

str_obj = "12345"
print("文字列の長さは:", len(str_obj))
<出力>
文字列の長さは: 5

これはほかのメソッドもできるだろうと、↑で使ったsorted()を逆順(reverse = True)で使ってみました。

print("リスト:", sorted(list_obj, reverse = True))
print("辞書:", sorted(dict_obj, reverse = True))
print("タプル:", sorted(tuple_obj, reverse = True))
print("文字列:", sorted(str_obj, reverse = True))
<出力>
リスト: [4, 3, 2, 1]
辞書: ['snake', 'dog', 'cat', 'bird']
タプル: [3, 2, 1]
文字列: ['5', '4', '3', '2', '1']

後どんなものがあるかな?いずれ出てくるでしょう。