プログラミング素人のArduino

技術屋の末端。プログラミングは専門外。 電気回路も専門外です。 コードに間違いなど見つけられたら、気軽にコメントください。 VC#始めました。

人工無能による3目並べ

3目並べとはこのようなものですが、
f:id:s51517765:20170813170441p:plain
三目並べ - Wikipedia

人工知能ならぬ「人工無能」でC#で作成しました。
無能な所以は、Computerは乱数で指すだけだから。

このゲームは今、AI界隈で流行りの「将棋」や「囲碁」と比べて、すこぶる単純で、勝敗判定も総当たりで実現できます。

f:id:s51517765:20170813171000j:plain

ぐぐると、プログラミングしている例はあると思いますが、今回はこんなですが完全自力です。
素人なので、効率的なアルゴリズムではないかもしれませんし、一つどうしても修正できない部分もあります。
//ここだけ強引
と書いてあるところ。
いずれ考えなおして修正します。

using System;
using System.Windows.Forms;

namespace _3x3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        bool teban = true;
        int shouhai = 0;
        int count = 0;
        int[,] Array = new int[,] { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };

        private void Form1_Load(object sender, EventArgs e)
        {                      
        }
        
        private void hantei()
        {
            if (Array[0, 0] == 1)
            {
                button00.Text = "〇";
            }
            else if(Array[0,0]==-1)
            {
                button00.Text = "●";
            }
            if (Array[0, 1] == 1)
            {
                button01.Text = "〇";
            }
            else if (Array[0, 1] == -1)
            {
                button01.Text = "●";
            }
            if (Array[0, 2] == 1)
            {
                button02.Text = "〇";
            }
            else if (Array[0, 2] == -1)
            {
                button02.Text = "●";
            }
            if (Array[1, 0] == 1)
            {
                button10.Text = "〇";
            }
            else if (Array[1, 0] == -1)
            {
                button10.Text = "●";
            }
            if (Array[1, 1] == 1)
            {
                button11.Text = "〇";
            }
            else if (Array[1, 1] == -1)
            {
                button11.Text = "●";
            }
            if (Array[1, 2] == 1)
            {
                button12.Text = "〇";
            }
            else if (Array[1, 2] == -1)
            {
                button12.Text = "●";
            }
            if (Array[2, 0] == 1)
            {
                button20.Text = "〇";
            }
            else if (Array[2, 0] == -1)
            {
                button20.Text = "●";
            }
            if (Array[2, 1] == 1)
            {
                button21.Text = "〇";
            }
            else if (Array[2, 1] == -1)
            {
                button21.Text = "●";
            }
            if (Array[2, 2] == 1)
            {
                button22.Text = "〇";
            }
            else if (Array[2, 2] == -1)
            {
                button22.Text = "●";
            }

            int sum = 0;
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    sum += Array[i, j];

                }
                if (sum == 3)
                {
                   shouhai = 1;
                }
                else if(sum ==-3)
                {
                       shouhai = -1;
                }
                sum = 0;
            }
            for (int j = 0; j < 3; j++)
            {
                for (int i = 0; i < 3; i++)
                {
                    sum += Array[i, j];

                }
                if (sum == 3)
                {
                    shouhai = 1;
                }
                else if (sum == -3)
                {
                    shouhai = -1;
                }
                sum = 0;
            }
            if (Array[0, 0] + Array[1, 1] + Array[2, 2] == 3) //斜め
            {
                shouhai = 1;
            }
            else if (Array[0, 0] + Array[1, 1] + Array[2, 2] == -3)
            {
                shouhai = -1;
            }
            if (Array[2, 0] + Array[1, 1] + Array[0, 2] == 3)  //斜め
            {
                shouhai = 1;
            }
            else if (Array[2, 0] + Array[1, 1] + Array[0, 2] == -3)
            {
                 shouhai = -1;
            }



            if (teban == true)
            {
                count++;
            }
            else if (shouhai == 0)
            {

                DateTime now = DateTime.Now;
                int set;
                set = now.Second + 2;
                if (set > 59)
                {
                    set = set - 60;
                }
                while (DateTime.Now.Second - set != 0) { }

                Random r = new Random();
                int randX = r.Next(0, 3);
                int randY = r.Next(0, 3);
                while (Array[randX, randY] != 0 && shouhai == 0)
                {
                    randX = r.Next(0, 3);
                    randY = r.Next(0, 3);
                }
                Array[randX, randY] = -1;
                teban = !teban;
                hantei();
                count++;              
            }

            if (shouhai == 1)
            {
                MessageBox.Show("You Win!");
            }
            else if (shouhai == -1)
            {
                MessageBox.Show("You Lose!");
                shouhai = 2;
                count = 10;   //ここだけ強引
            }
            else if (count == 9)
            {
                MessageBox.Show("Draw!");
                shouhai = 2;
            }
        }

        private void button00_Click(object sender, EventArgs e)
        {
            if (teban == true)
            {              
                Array[0, 0] = 1;
            }
            else
            {               
                Array[0, 0] = -1;
            }
            teban = !teban;
            hantei();
         }

        private void button01_Click(object sender, EventArgs e)
        {
            if (teban == true)
            {
                Array[0, 1] = 1;
            }
            else
            {               
                Array[0, 1] = -1;
            }
            teban = !teban;
            hantei();
        }

        private void button02_Click(object sender, EventArgs e)
        {
            if (teban == true)
            {               
                Array[0, 2] = 1;
            }
            else
            {
                Array[0, 2] = -1;
            }
            teban = !teban;
            hantei();
        }

        private void button10_Click(object sender, EventArgs e)
        {
            if (teban == true)
            {
                Array[1, 0] = 1;
            }
            else
            {
                Array[1, 0] = -1;
            }
            teban = !teban;
            hantei();
        }

        private void button11_Click(object sender, EventArgs e)
        {
            if (teban == true)
            {
                Array[1, 1] = 1;
            }
            else
            {
                Array[1, 1] = -1;
            }
            teban = !teban;
            hantei();
        }

        private void button12_Click(object sender, EventArgs e)
        {
            if (teban == true)
            {
                Array[1, 2] = 1;
            }
            else
            {
                Array[1, 2] = -1;
            }
            teban = !teban;
            hantei();
        }

        private void button20_Click(object sender, EventArgs e)
        {
            if (teban == true)
            {
                Array[2, 0] = 1;
            }
            else
            {
                Array[2, 0] = -1;
            }
            teban = !teban;
            hantei();
        }

        private void button21_Click(object sender, EventArgs e)
        {
            if (teban == true)
            {
                Array[2, 1] = 1;
            }
            else
            {
                Array[2, 1] = -1;
            }
            teban = !teban;
            hantei();
        }

        private void button22_Click(object sender, EventArgs e)
        {
            if (teban == true)
            {
                Array[2, 2] = 1;
            }
            else
            {
                Array[2, 2] = -1;
            }
            teban = !teban;
            hantei();
        }

        private void buttonRestart_Click(object sender, EventArgs e)
        {
            shouhai = 0;
            count = 0;
            teban = true;
            button00.Text = "";
            button01.Text = "";
            button02.Text = "";
            button10.Text = "";
            button11.Text = "";
            button12.Text = "";
            button20.Text = "";
            button21.Text = "";
            button22.Text = "";

            for (int j = 0; j < 3; j++)
            {
                for (int i = 0; i < 3; i++)
                {
                    Array[j, i] = 0;
                }
            }
        }
    }

    }

マウス自動化ツール

マウス操作をC# で自動化するツールを作ってみました。

使うだけであれば、ぐぐるといろいろ出てきますのであってアイデア自体は昔からあるものです。
マウス自動化 - Google 検索

↓のサイトを参考にプログラミングしてみました。
whoopsidaisies.hatenablog.com

目標はスクレイピングでは対応しきれない(自分の技術力的に)部分をマウスエミュレーションで解決することです。

◆目指す機能
マウスで座標をもとにブラウザ上のLinkをたどって目的のWeb Pageへ
そのために、クリックすべき座標を記録する。
記録した座標をもとにWeb Pageをたどる

using System.Runtime.InteropServices;
  public partial class Form1 : Form
    {

        int interval = 2000;
        private const int MOUSEEVENTF_LEFTDOWN = 0x2;
        private const int MOUSEEVENTF_LEFTUP = 0x4;
        private const int MOUSEEVENTF_RIGHTTDOWN = 0x8;
        private const int MOUSEEVENTF_RIGHTUP = 0x10;
        [DllImport("USER32.dll", CallingConvention = CallingConvention.StdCall)]
        static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
        int[] cursorLogX = new int[10] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
        int[] cursorLogY = new int[10] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
        int n = 0;

        private void Form1_Load(object sender, EventArgs e)
        {
            this.KeyPreview = true;   
            comboBoxInterval.Items.Add("2000");
            comboBoxInterval.Text = "2000";
        }
}

Using System.Runtime.InteropServices;の宣言を追加し、Classの直下に
[DllImport("USER32.dll", CallingConvention = CallingConvention.StdCall)]
を追加します。
これが、マウス操作のためのRuntimeのようです。(詳細はよくわかってない)
MOUSEEVENTF_LEFTDOWN …などの変数を設定します。
この16進数で示された値を渡すことでマウスを操作します。
x,yの座標を最大10個記憶するため、配列を持たせます。(必要に応じて配列の大きさは変更可能)
座標は0以上の整数として入ってくるので、"-1"で初期化するとことで、呼び出された座標が"-1"であれば座標が記録されていないということになります。

  private void Form1_Load(object sender, EventArgs e)
        {
      this.KeyPreview = true;  
    }

これで、キー操作を受け取るようになります。

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        { 
           if ((e.Modifiers & Keys.Alt) == Keys.Alt)
            {                
                //マウスポインタのX座標を取得する
                int x = System.Windows.Forms.Cursor.Position.X;
                //マウスポインタのY座標を取得する
                int y = System.Windows.Forms.Cursor.Position.Y;

                textBoxLog.AppendText( x.ToString()+" "+y.ToString()+ System.Environment.NewLine);
                cursorLogX[n] = x;
                cursorLogY[n] = y;
                n++;
            }

private void Form1_KeyDown( ~ という関数を作成し、ここでは「Alt」キーを押したときのマウス座標を記録します。

        private void button1_Click(object sender, EventArgs e)
        {
            interval = int.Parse(comboBoxInterval.Text);
            for (int m = 0; m < 10; m++)
            {
                if (cursorLogX[m] != -1)
                {
                    //マウスポインタの位置を画面左上基準の座標(x,y)にする
                    System.Windows.Forms.Cursor.Position = new System.Drawing.Point(cursorLogX[m], cursorLogY[m]);
                    mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);      
                      // マウスの左ボタンダウンイベントを発生させる             
                    mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);        
                      // マウスの左ボタンアップイベントを発生させる
                    System.Threading.Thread.Sleep(interval);
                }
                else
                {
                    break;
                }
            }
  
        }

ボタン1を押すと再現します。
webを扱うときには、読み込みにかかる時間を計算に入れておかないと、ItemがすべてDownloadされないうちに次のステップに進んでしまうと、座標とWeb Linkがずれてしまいます。のでここではIntervalとして、2000msほど入れています。

paizaスキルチェックのランタイムエラー

paizaとは転職サイトであり、プログラミングのスキルチェックができるサイトです。
paiza.jp

ここでは好きな言語を選んでプログラムを書いて、与えられた課題をこなすスキルチェックがあります。
スキルチェックでは正解するごとにランキングが発生したり、転職市場価値を算出したりできます。

問題を解いている中で、一般的なコンパイルエラーはIDEのようにエラーが出ます。
f:id:s51517765:20170802224244j:plain

しかし、いくつか問題を解いているうちに”Unhandled Exception”や ”ランタイムエラー”という、原因がはっきりしないエラーが発生することがありました。

ぐぐってもそのようなことが説明されている例がなかったのですが、その原因のひとつが分かったのでここに記します。
スキルチェックの内容を公開するのは問題があるので、オンライン実行環境でその内容を要点に絞って再現しました。
f:id:s51517765:20170802224622j:plain

この例では、「要素数3つの配列」を宣言して、「4つ目」の配列要素を使用しようとしたものです。
Errorメッセージをよく見ると、「インデックスが配列の中に無いよ。」ということが書かれていますね。

ただしく、「3つ目」の要素を使用するとエラーが消えます。
f:id:s51517765:20170802225248j:plain

C#で文字列の配列を数値の配列に変換する

Pythonだと一発でできるみたいなのだが。

a1 = ['0', '12.2','23']
a1_list = [float(i) for i in a1]

hiroto1979.hatenablog.jp


なんか、簡単な方法がないものか?

public class Hello
{
    public static void Main()
    {
        string[] strAry = new string[] { "1", "2", "3" }; 
    //ここでは右辺の"new string[]"は省略できる。
        int[] array = new int[strAry.Length];
        for (int i = 0; i < strAry.Length; i++)
        {
            array[i] = int.Parse(strAry[i]);
        }
        System.Console.WriteLine(array[0] + array[1]+ array[2]);    
    }
}

ジャンパピン中継基板を作る

通常のArduinoなどでは、ピンがメス型で出ていて、オス-オスのジャンパワイヤを使います。
f:id:s51517765:20170723173801j:plain
しかし、中にはオスのピンが出ているものがあります。
(写真左)

このような時は↓のようなメス-メスケーブルや、メス-オスケーブルを使いますが、

簡単なので、メス-メス変換基板を作ってみました。
f:id:s51517765:20170723174046j:plain

ユニバーサル基板の切れ端に、ピンヘッダをつけて反対側でリード線で接続します。
ユニバーサル基板はデザインナイフで、同じところを何度も切り込み、0.5mmぐらいに掘れれば手で割ることができます。
定規を当てながら、何回も引っかきます。
f:id:s51517765:20170723175048j:plain
f:id:s51517765:20170723174820j:plain

ピンヘッダは、最早お気に入りのHiletgoの商品から↓を使いました。

これを、4つづつに切断しはんだ付けしていきます。
5つめのピンのあるところに、強めにデザインナイフで切込みを入れて反対側へ曲げるように折ると簡単に切断できます。
これは、安物だからこその”割り安さ”のように思います。

はんだ付けや、カッター版として、ひび割れて使えなくなった、ミニまな板を使っています。
どこかの100均だったと思います。
f:id:s51517765:20170723174925j:plain

完成。

「実装しない」機能の決め方 – 週休7日で働きたい

「実装しない」機能の決め方 – 週休7日で働きたい

 

なるほど、耳が痛い。

だが一方で、それが出来るのも趣味だからこそ。

アルゴリズムをはじめよう

アルゴリズムとは「問題を解決するための手順をもれなく表現したもの」。
プログラミングをするにあたっては、まず初めに考えるものです。

例えば、文字列を表示したいなら

Console.WriteLine("*****");

であったり、

MessageBox.Show("*****");

といったものを使う、ということを考えて組み立てていきます。
このように、すでに関数として完成しているものではそのまま使うことができますが、

・土壌湿度が下がったら
・ポンプをオンにして
・一定時間経過したら
・ポンプをオフにする
※自動水やり器のアルゴリズム

このようなものもアルゴリズムの一つです。

プログラムはそのほとんどが、じつは「for」と「if」の組み合わせで表現することができます。
・関数として出来上がっているものをどのような順番で呼び出すか?
・関数がなければその処理をどのように「for」と「if」の組み合わせで実現するか?
が、アルゴリズムの設計です。

そこで、私は最初の一歩としてこの本を選択しました。

アルゴリズムを、はじめよう

アルゴリズムを、はじめよう

基本的な、主にデータの並べ替え(ソート)や抽出について丁寧に説明されています。
また、流れ図(フローチャート)と疑似言語ですべての例が説明されています。

フローチャートは考えをまとめるときや説明するときにも使えますので、プログラマでなくても使えると便利です。

疑似言語は慣れないとむしろ若干わかりにくいですね。
"if(i<5)" なら "i<5"と書かれていたり、
"i=5" を "5→i" と書いていたりします。
C言語と疑似言語の関係

内容的には少なめだと思いますが、ここに出てくるようなものがプログラミングできるようになれば一段階複雑な問題にも取り組めるようになると思います。

この次ぐらいにこちらをみると、さらに多くの例にふれられると思います。

アルゴリズム図鑑 絵で見てわかる26のアルゴリズム

アルゴリズム図鑑 絵で見てわかる26のアルゴリズム

Androidiphoneアプリで一部が無料で見られます。
こちらは、アルゴリズムをアニメーションで説明していて動きはわかりやすいですが、いきなりこちらを見てもプログラミングは難しいかもしれません。

勉強の目標を立てるために一度見てみると、意欲がわくのではないでしょうか?