【ラズパイ】これまでやってきたことを組み合わせる。

ここまでやってきたことを全て組み合わせます。

GLCDに表示するのは、

  • 時刻、天気、温度、湿度
  • カレンダー
  • 倉田ましろの絵

この3つの表示を、スイッチの1番を押すことで切り替えます。

import RPi.GPIO as GPIO
import time
import datetime
import calendar
import GLCD
import AM2320
import Weather
import SW


def __main__():
    GPIO.setmode(GPIO.BCM)
    GLCD.PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCD.GLCDInit()
    GLCD.GLCDDisplayClear()

    SW.PinsInit(21, 22, 23, 24, 25, 26, 27)
    SW.Start()

    roop = 10 * 60 * 60
    mode = 1
    try:
        while True:
            key = SW.GetKey()
            if key == "1":
                GLCD.GLCDDisplayClear()
                mode += 1
                if mode > 3:
                    mode = 1

            if mode == 1:
                if roop >= 10 * 60 * 60:
                    Weather.RequestAPI()
                    weather = Weather.GetWeather()
                    temp = Weather.GetTemp()
                    roop = 0

                GLCD.GLCDPuts(1, 0, "Date :")
                GLCD.GLCDPuts(5, 8, datetime.datetime.now().strftime('%Y:%m:%d %A'))
                GLCD.GLCDPuts(1, 16, "Weather :")
                GLCD.GLCDPuts(10,24, weather)
                GLCD.GLCDPuts(10,32, "Temp : " + format(temp) + 'C')
                GLCD.GLCDPuts(1, 40, "Time : " + datetime.datetime.now().strftime('%H:%M:%S'))
                GLCD.GLCDPuts(1, 48, "Humidity    : " + AM2320.GetHum() + '%')
                GLCD.GLCDPuts(1, 56, "Temperature : " + AM2320.GetTemp() + 'C')

                roop += 1
            elif mode == 2:
                cal = calendar.month(datetime.datetime.now().year, datetime.datetime.now().month)
                cals = cal.split("\n")
                y = 0
                for c in cals:
                    GLCD.GLCDPuts(1, y, c)
                    y += 8
            
            elif mode == 3:
                GLCD.drowMashiro()

            time.sleep(0.1)
    except KeyboardInterrupt:
        SW.Stop()
        GLCD.GLCDDisplayClear()
        GPIO.cleanup()

__main__()

スイッチ押下でmodeの値が変化し、表示処理の内容を変えています。

なかなか上手くいったので、これで完成品を作ってみようか。

ラズパイ遊びの集大成です。

【C#】【ピクロス】【ALTSEED】自動テスト機能を実装する。

前回までの状況はこちら。

最新ソースはこちら。(gitHub)

https://github.com/takishita2nd/Picross

さて、いよいよ、自動テストを作っていきますか。

前回で問題データと解答データを用意したので、

問題データの読み込み→解析→回答データと照合→結果出力

こんな感じの流れでできると思います。

という訳で実装。

    class AutoTest
    {
        private const string QuestionFolder = "q";
        private const string AnswerFolder = "a";
        private const string ResultFolder = "r";
        private const string QuestionFile = "save";
        private const string AnswerFile = "output";
        private const string ResultFile = "result";

        public AutoTest()
        {

        }

        public void Run()
        {
            var files = Directory.EnumerateFiles(QuestionFolder, "*");
            foreach(var file in files)
            {
                string answerFile = file.Replace(QuestionFolder, AnswerFolder).Replace(QuestionFile, AnswerFile);
                string resultFile = file.Replace(QuestionFolder, ResultFolder).Replace(QuestionFile, ResultFile);
                if (File.Exists(resultFile))
                {
                    File.Delete(resultFile);
                }

                if (File.Exists(answerFile))
                {
                    List<List<NumberSquare>> rowNumberSquare = new List<List<NumberSquare>>();
                    List<List<NumberSquare>> colNumberSquare = new List<List<NumberSquare>>();
                    FileAccess.Load(file, ref rowNumberSquare, ref colNumberSquare);
                    PicrossAnalyze picross = new PicrossAnalyze(rowNumberSquare, colNumberSquare);
                    var ret = picross.Run();
                    string answer = string.Empty;
                    for(int r = 0; r < rowNumberSquare.Count; r++)
                    {
                        for(int c = 0; c < colNumberSquare.Count; c++)
                        {
                            if (ret[r, c].IsPainted())
                            {
                                answer += "1";
                            }
                            else
                            {
                                answer += "0";
                            }
                        }
                        answer += "\r\n";
                    }
                    string compare = FileAccess.AnswerLoad(answerFile);
                    string result;
                    if(compare.CompareTo(answer) == 0)
                    {
                        result = "OK";
                    }
                    else
                    {
                        result = answer;
                    }
                    using (var stream = new StreamWriter(resultFile, true))
                    {
                        stream.Write(result);
                    }
                }
            }
        }
    }
    class PicrossUI
    {
        public void Run()
        {

            // テストボタン
            var testButton = new Button(10, 170, "テスト");
            testButton.Show();
            asd.Engine.AddObject2D(testButton.getBackTexture());
            asd.Engine.AddObject2D(testButton.getTextObject());
            buttons.Add(testButton);
            testButton.SetAction(() =>
            {
                var test = new AutoTest();
                test.Run();
            });

Directory.EnumerateFiles()で問題ファイルの一覧を取得し、それをforeachで回します。

問題ファイルからデータを取り出し、ピクロス解析処理にかけます。

その結果を前回のような0と1の文字列に変換し、CompareTo()で回答結果との照合を行います。

結果、問題無ければOK、問題があれば解析結果をresultファイルに出力します。

これでテストも楽になる!

【ラズパイ】【GLCD】カレンダーを表示する

GLCDにカレンダーを表示させたいと思います。

import RPi.GPIO as GPIO
import time
import datetime
import calendar
import GLCD
import AM2320
import Weather
import SW


def __main__():
    GPIO.setmode(GPIO.BCM)
    GLCD.PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCD.GLCDInit()
    GLCD.GLCDDisplayClear()

    try:
        while True:
            cal = calendar.month(datetime.datetime.now().year, datetime.datetime.now().month)
            cals = cal.split("\n")
            y = 0
            for c in cals:
                GLCD.GLCDPuts(1, y, c)
                y += 8

            time.sleep(0.1)
    except KeyboardInterrupt:
        GLCD.GLCDDisplayClear()
        GPIO.cleanup()

__main__()

calendar.month(year, month)で現在月のカレンダーを文字列で出力されます。

これは改行文字を使って整形されているので、改行文字で分割し一行ずつ表示位置を変えながら表示させています。

出来れば今日の日付の部分が分かるようにしたかったんだけど、無理っぽい。

よし、これでやりたいことは一通り出来た。

休止状態のPCが勝手に起動する問題。

パソコンの電源を入れて、昨日までの作業状態にするのがめんどくさい。

でも電気代も気になる(特にこのエアコンの夏場)。

なので、寝る前にはPCを休止状態にして寝るのですが、

なぜか勝手にPCが起動してしまう。

なぜだーと言うことをTwitterで問うたところ、

情報ありがとうございます!

リンク先の情報は少し古いですが、コントロールパネルで「デバイスマネージャー」と入力すれば、すぐにデバイスマネージャーを開くことが出来ます。

ちなみに、オイラはすでに高速スタートアップは無効化していました。

設定を調べたところ、デバイスやネットワークの動きに感知してPCが復帰する設定になっていたようですね。

これらの設定を無効化したところ、勝手に立ち上がることは無くなりました。

解決です!

FitBit Payが日本でも使えるようになったぞ!

ほとんど諦めていたけど。

https://japanese.engadget.com/fitbit-pay-053021750.html

FitBit Payがソニー銀行と提携して、日本でも使用できるようになりました。

ソニー銀行が発行しているデビットカードがあれば、FitBitアプリにカード情報を入力することで、カードと連携して使用できるようになります。

VISAのタッチ決済に対応している店舗で使用可能です。

https://www.visa.co.jp/pay-with-visa/featured-technologies/contactless.html

専用端末にFitBitデバイスをタッチするだけで決済が行われます。

これは、NFC Type-A/Bを使用した決済方法で、日本ではFelica(NFC Type-F)が一般的ですが、国外ではNFC Type-A/Bの方が一般的です。

日本国内でも海外からのインバウンド客を取り込むために、Type-A/Bに対応した決済方法を取り入れ始めていると言うことですね。

では、具体的にどの店舗で使えるのかというと、

このマークがある店舗。

コンビニでは、セブンイレブンやローソンなどが使用できるみたいです。

使うことがあるかどうか分かりませんが、選択肢が増えるのは良いことだと思います。

少し口座に振り込んでおこうかな。

【ラズパイ】スイッチをモジュール化する

前回までの状況はこちら。

前回作成したサンプルソースコードを元に、スイッチ処理をモジュール化します。

やり方としては、スイッチの押下検出をスレッドで動かしてメインスレッドで取り出す、という方式が良いと思います。

GPIOのエッジ検出で割り込み処理する、という方法もありますが、このスイッチモジュールの仕様上、それは難しそうです。

import RPi.GPIO as GPIO
import time
import threading

X_p = 0
Y_p = 0
Z_p = 0
A_p = 0
B_p = 0
C_p = 0
D_p = 0

Non = ""
Key = Non

thread = None
Loop = True

def PinsInit(x, y, z, a, b, c, d):
 省略

def Start():
    thread = threading.Thread(target=threadProcess)
    thread.start()

def Stop():
    global Loop
    Loop = False

def GetKey():
    global Key
    ret = Key
    Key = Non
    return ret

def threadProcess():
    global Key

    col = 1
    swState = [0] * 12
    while Loop:
        if col == 1:
            GPIO.output(X_p, GPIO.LOW)
            GPIO.output(Y_p, GPIO.HIGH)
            GPIO.output(Z_p, GPIO.HIGH)
        elif col == 2:
            GPIO.output(X_p, GPIO.HIGH)
            GPIO.output(Y_p, GPIO.LOW)
            GPIO.output(Z_p, GPIO.HIGH)
        else:
            GPIO.output(X_p, GPIO.HIGH)
            GPIO.output(Y_p, GPIO.HIGH)
            GPIO.output(Z_p, GPIO.LOW)

        # 1押下
        if swState[1] == 0 and col == 1 and GPIO.input(D_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(D_p) == 0:
                Key = "1"
                swState[1] = 1
        # 1押下戻し
        elif swState[1] == 1 and col == 1 and GPIO.input(D_p) == 1:
            Key = Non
            swState[1] = 0
        # 2押下
        if swState[2] == 0 and col == 2 and GPIO.input(D_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(D_p) == 0:
                Key = "2"
                swState[2] = 1
        # 2押下戻し
        elif swState[2] == 1 and col == 2 and GPIO.input(D_p) == 1:
            Key = Non
            swState[2] = 0
        # 3押下
        if swState[3] == 0 and col == 3 and GPIO.input(D_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(D_p) == 0:
                Key = "3"
                swState[3] = 1
        # 3押下戻し
        elif swState[3] == 1 and col == 3 and GPIO.input(D_p) == 1:
            Key = Non
            swState[3] = 0
        # 4押下
        if swState[4] == 0 and col == 1 and GPIO.input(C_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(C_p) == 0:
                Key = "4"
                swState[4] = 1
        # 4押下戻し
        elif swState[4] == 1 and col == 1 and GPIO.input(C_p) == 1:
            Key = Non
            swState[4] = 0
        # 5押下
        if swState[5] == 0 and col == 2 and GPIO.input(C_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(C_p) == 0:
                Key = "5"
                swState[5] = 1
        # 5押下戻し
        elif swState[5] == 1 and col == 2 and GPIO.input(C_p) == 1:
            Key = Non
            swState[5] = 0
        # 6押下
        if swState[6] == 0 and col == 3 and GPIO.input(C_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(C_p) == 0:
                Key = "6"
                swState[6] = 1
        # 6押下戻し
        elif swState[6] == 1 and col == 3 and GPIO.input(C_p) == 1:
            Key = Non
            swState[6] = 0
        # 7押下
        if swState[7] == 0 and col == 1 and GPIO.input(B_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(B_p) == 0:
                Key = "7"
                swState[7] = 1
        # 7押下戻し
        elif swState[7] == 1 and col == 1 and GPIO.input(B_p) == 1:
            Key = Non
            swState[7] = 0
        # 8押下
        if swState[8] == 0 and col == 2 and GPIO.input(B_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(B_p) == 0:
                Key = "8"
                swState[8] = 1
        # 8押下戻し
        elif swState[8] == 1 and col == 2 and GPIO.input(B_p) == 1:
            Key = Non
            swState[8] = 0
        # 9押下
        if swState[9] == 0 and col == 3 and GPIO.input(B_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(B_p) == 0:
                Key = "9"
                swState[9] = 1
        # 9押下戻し
        elif swState[9] == 1 and col == 3 and GPIO.input(B_p) == 1:
            Key = Non
            swState[9] = 0
        # *押下
        if swState[10] == 0 and col == 1 and GPIO.input(A_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(A_p) == 0:
                Key = "*"
                swState[10] = 1
        # *押下戻し
        elif swState[10] == 1 and col == 1 and GPIO.input(A_p) == 1:
            Key = Non
            swState[10] = 0
        # 0押下
        if swState[0] == 0 and col == 2 and GPIO.input(A_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(A_p) == 0:
                Key = "0"
                swState[0] = 1
        # 0押下戻し
        elif swState[0] == 1 and col == 2 and GPIO.input(A_p) == 1:
            Key = Non
            swState[0] = 0
        # #押下
        if swState[11] == 0 and col == 3 and GPIO.input(A_p) == 0:
            # チャタリング回避
            time.sleep(0.05)
            if GPIO.input(A_p) == 0:
                Key = "#"
                swState[11] = 1
        # #押下戻し
        elif swState[11] == 1 and col == 3 and GPIO.input(A_p) == 1:
            Key = Non
            swState[11] = 0

        col += 1
        if col > 3:
            col = 1
        
        time.sleep(0.005)

Start()でthreadProcess()をバックグラウンドで実行、Stop()でLoop=Falseになるまで実行します。

スイッチを押すと、その値がKeyに入るので、それをGetKey()で取り出します。

変数でワンクッション置いているのは、ボタン押しっぱなしで複数回キー入力を検出するのを防ぐためです。

def __main__():
    GPIO.setmode(GPIO.BCM)

    SW.PinsInit(21, 22, 23, 24, 25, 26, 27)
    SW.Start()

    try:
        while True:
            key = SW.GetKey()
            if key != "":
                print(key)

            time.sleep(0.1)
    except KeyboardInterrupt:
        SW.Stop()
        GPIO.cleanup()

__main__()

ここまで出来れば、他モジュールと組み合わせることも出来そうです。

【料理】【リュウジのバズレシピ】もやしの爆弾

想像以上にボリューミー。

こちらのレシピ動画を参考にしました。

使用するのはもやしとひき肉だけ。

それらを手でこねて焼くだけという、簡単に作れてしまいます。

しかも、半分はもやしなので、かなりのかさ増しハンバーグになりました。

ダイエットにも最適だと思います。

これだけ簡単で美味しいとなると、料理も楽しくなりますね。

【北海道大戦】対戦ルールを検討する

さて、前回までで、マップ関連は完成しました。

次回からバトル関連を作成していこうと思うのですが、バトルのルールを決めておく必要があります。

まずは、コンピューターだけでバトルさせて、どの市町村が勝利するかを見てみたいと思います。

ということで以下の様にしていました。

  • 各市町村、1ターンに1回行動できる
  • 行動順はランダムで並び替えされる
  • 1ターンにつき、隣接する市町村に攻撃を仕掛けることが出来る
  • 戦力値は人口×0.5~3.0(乱数)で決定される
  • 戦力値が大きい方が勝利する
  • 攻撃側が勝利した場合は防御側の市町村を吸収合併する。
  • 防御側が勝利しても何も無し。
  • 最終的に市町村が残り1つになるまで繰り返す。

こんな感じでどうだろうか?

まずは、作ってみて動かしてみましょうか。

【北海道大戦】離島問題を解決する

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/HokkaidoWar

さて、前回で隣接都市とのリンクを作成しましたが、

1つ問題がありまして、

それは離島とのリンクです。

今のままではマスの隣接関係でリンクを確認しているので、マスが離れている離島との隣接関係がありません。

具体的には、

  • 奥尻ー江差
  • 礼文ー稚内
  • 礼文ー利尻
  • 礼文ー利尻富士
  • 利尻富士ー稚内

この隣接関係を作成しなければ行けません。

※ちなみに、天売島、焼尻島は羽幌に属しています。

今回はUp(),Down(),Left(),Right()処理に例外を入れることで対応します。

マップそのものが変わってしまうと、ここの処理も修正しなければ鳴りませんが、他に有効な手段が思いつかないので、仕方がありません。

    class Map
    {
        public Map Up { 
            get {
                var field = Singleton.GetFieldMap();
                if(_x == 18 && _y == 0)
                {
                    return field.GetMap(23, 0);
                }
                else if(_x == 23 && _y == 0)
                {
                    return field.GetMap(18, 0);
                }
                else if (_x == 20 && _y == 1)
                {
                    return field.GetMap(18, 0);
                }
                else
                {
                    return field.GetMap(_x, _y - 1);
                }
            }
        }

        public Map Down
        {
            get
            {
                var field = Singleton.GetFieldMap();
                if(_x == 18 && _y == 0)
                {
                    return field.GetMap(19, 1);
                }
                else
                {
                    return field.GetMap(_x, _y + 1);
                }
            }
        }

        public Map Left
        {
            get
            {
                var field = Singleton.GetFieldMap();
                if (_x == 2 && _y == 29)
                {
                    return field.GetMap(0, 29);
                }
                else if(_x == 19 && _y == 1)
                {
                    return field.GetMap(18, 0);
                }
                else if (_x == 23 && _y == 0)
                {
                    return field.GetMap(20, 1);
                }
                else
                {
                    return field.GetMap(_x - 1, _y);
                }
            }
        }

        public Map Right
        {
            get
            {
                var field = Singleton.GetFieldMap();
                if (_x == 0 && _y == 29)
                {
                    return field.GetMap(2, 29);
                }
                else if(_x == 18 && _y == 0)
                {
                    return field.GetMap(20, 1);
                }
                else if (_x == 20 && _y == 1)
                {
                    return field.GetMap(23, 0);
                }
                else
                {
                    return field.GetMap(_x + 1, _y);
                }
            }
        }

こんな感じで離島とのリンク関係を強引に作りました。

給付金で買ったジンギスカンセットでジンギスカンを食べる

食べ過ぎちゃった(てへぺろ

こちらの記事で購入したジンギスカンセットでジンギスカンを食べました。

使用したお肉はこれ。

行者ニンニク入り味付けラムです。


うん、美味しそうである。

野菜は、もやし、玉ねぎ、ニラを用意しました。

そして忘れちゃいけないのはうどん。

準備完了。

焼くぞー。

味付けラムを焼くときは、火を強くしすぎないことです。

大体弱めの中火ぐらい。

強すぎると肉汁が蒸発してしまうので。

そうすると、肉汁が鍋の縁に貯まっていきます。

ここにうどんを投入。

肉汁でうどんを煮込みます。

このうどんが美味い。

いやー1kgペロッと食べちゃった。

美味かった。

そして後片付けである。

このジンギスカン鍋、キャプテンスタッグ製のものです。

これは鋳物なので、洗剤は使用しません。

たわしで表面の汚れを落とします。

しかし、ジンギスカンのタレが焦げて、たわしでも落とせない焦げ付きがあるんですよ。

その場合は、ガスコンロで空焚きします。

ガスボンベ一本使い切るぐらい。

空焚きしていると、次第に焦げつきが剥がれてくるんです。

あとは、この焦げをたわしで落として、

乾燥後にオリーブオイルを塗る。

これが出来るのは、品物が良いのと、お手入れがしっかりしているからですね。

さすがキャプテンスタッグ。

いやーしばらくジンギスカンはいいけど、また食べたいね。

良かった良かった。

自分、ぼっちですが何か?