「技術」カテゴリーアーカイブ

【C#】【数独】仮置き対象を抽出する

かなり時間が空いてしまいましたが。

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

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

https://github.com/takishita2nd/sudoku

さて、実際に仮置きロジックを実装していくのですが、

そのときに必要となる情報が、

仮置きロジックをどこに適用するか

ということです。

今回は、9マスのエリアの中で、一番空きマスの少ない箇所を選択するように実装してみようと思います。

        private List<Square> searchKariokiSquare(Square[,] squares)
        {
            List<Square> ret = null;
            for(int row = 0; row < 9; row += 3)
            {
                for(int col = 0; col < 9; col += 3)
                {
                    List<Square> temp = new List<Square>();
                    for(int i = 0; i < 3; i++)
                    {
                        for(int j = 0; j < 3; j++)
                        {
                            if(squares[row + i, col + j].isConfirmed() == false)
                            {
                                temp.Add(_square[row + i, col + j]);
                            }
                        }
                    }
                    if(ret != null)
                    {
                        if(ret.Count > temp.Count && temp.Count != 0)
                        {
                            ret = temp;
                        }
                    }
                    else
                    {
                        ret = temp;
                    }
                }
            }
            return ret;
        }

コードはこんな感じに書いてみました。

9マスエリアに対して、まだ数字が入っていないマスの数を確認します。

数字が入っていないマスのオブジェクトをリストに登録し、それが他の9マスエリアの数より少ないか、を確認します。

調査結果は数字が入っていないマスのオブジェクトのリストを返します。

では、このメソッドを使用する処理を作成します。

        private void doKarioki()
        {
            Square[,] copySquare = makeClone(_square);
            List<Square> kariokiList = searchKariokiSquare(copySquare);
            foreach(var s in kariokiList)
            {
                Console.WriteLine("[{0},{1}]", s.Row, s.Col);
            }
        }

仮置き処理を実行するので、処理前にマス配列のクローンを作成します。

そして、先ほどのメソッドを使用して仮置き対象のマスをリストで取得。

そして、それに対してforeachを使って仮置きロジックを適用していきます。

Windows TerminalPS E:\Source\Repos\takishita2nd\sudoku\sudoku\bin\Debug> .\sudoku.exe .\q026.txt
仮置きロジック
[0,6]
[2,6]

こんな感じで、仮置き対象のマスの抽出ができました。

うん、完成が見えてきたぞ。

【Laravel】【ホテル予約管理】解錠ナンバーをQRコードに変換する

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

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

https://github.com/takishita2nd/hotel-mng

さて、今回は、前回作成したコードで生成した解錠コードをQRコードに変換します。

使用するのは、simplesoftwareio/simple-qrcodeというライブラリ。

Laravelのプロジェクトディレクトリにて、以下のコマンドを実行。

$ composer require simplesoftwareio/simple-qrcode

いま使用しているLaravelのバージョンは5.5.*なのでこれだけでライブラリが使用可能になります。

では、解錠コード生成処理を修正します。

use QrCode;

    public function add($param, $room, $user)
    {
        Log::debug(print_r($param ,true));
        $model = new ReserveManagement;
        foreach($this->paramNames as $name)
        {
            $model->$name = $param[$name];
        }
        $model->lock_number = $this->generateLockNumber();

        $src = base64_encode(QrCode::format('png')->size(100)->generate($model->lock_number));
        Log::debug(print_r($src ,true));
        $model->save();
        $this->attachToRoom($model, $room);
        $this->attachToSchedule($model);
        $this->attachToUser($model, $user);
    }

QrCodeクラスを使って解錠コードをpngファイルで生成、それをbase64に変換しています。

これは、とりあえずログに出力させています。

[2020-02-07 10:06:26] local.DEBUG: iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB3UlEQVR4nO2b24rEIBAFd8L+/yeHfRMWQbrsNjozVa+Ty1CcQ4zG133fPxLj2v0H3gllAZQFUBZAWQBlAZQFUBZAWQBlAZQFUBZAWQBlAZQFUBZAWYDfudOuK2W5Tc/21+lnbtsxg7Pm7k4xWQBlASZr2ECRHpRurlnJu1NMFkBZgGwNG4OQD8oyeNJVVaxwYdRkAZQFKKthFck+LsVkAZQFOKWGkZfE7ZgsgLIAZTWca01V157prMkCKAuQrWFy3iPybjgYneZnXRAmC6AswOuQsZ+D0k9DWYCF64ZoBTCycjH3WCyc8zFZAGUBsk/D8vX3yOlVV6aYLICyAPU17El2BL0ALh3KmiyAsgD1M6XJkSe6V4TC9UeTBVAWYPJpGMl2VfvQlOnS0anJAigLMPk0jCS5Pwa990V4+EsbkwVQFmDzDou5acy5L1EdlD6KsgCbd1hUHbzuPfTfX6q60DegLMDmHRYRkh/PuG64B2UBNn/aPahGcgEx8hPFZAGUBTh3h0WjamdxHpMFUBZg8w6LwemtUMkJmcJimiyAsgCbd1j010FLIX7Mdi7KApyyw+ItMFkAZQGUBVAWQFkAZQGUBVAWQFkAZQGUBVAWQFkAZQGUBVAWQFkAZQH+AEkJCJS/ZGd/AAAAAElFTkSuQmCC  

これは後ほど、HTMLメールのimgタグのsrc要素に書き込んで使用することを考えています。

これをブラウザで表示させてみましょう。

以下をアドレスバーに入力するとQRコードが表示されます。

data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB3UlEQVR4nO2b24rEIBAFd8L+/yeHfRMWQbrsNjozVa+Ty1CcQ4zG133fPxLj2v0H3gllAZQFUBZAWQBlAZQFUBZAWQBlAZQFUBZAWQBlAZQFUBZAWYDfudOuK2W5Tc/21+lnbtsxg7Pm7k4xWQBlASZr2ECRHpRurlnJu1NMFkBZgGwNG4OQD8oyeNJVVaxwYdRkAZQFKKthFck+LsVkAZQFOKWGkZfE7ZgsgLIAZTWca01V157prMkCKAuQrWFy3iPybjgYneZnXRAmC6AswOuQsZ+D0k9DWYCF64ZoBTCycjH3WCyc8zFZAGUBsk/D8vX3yOlVV6aYLICyAPU17El2BL0ALh3KmiyAsgD1M6XJkSe6V4TC9UeTBVAWYPJpGMl2VfvQlOnS0anJAigLMPk0jCS5Pwa990V4+EsbkwVQFmDzDou5acy5L1EdlD6KsgCbd1hUHbzuPfTfX6q60DegLMDmHRYRkh/PuG64B2UBNn/aPahGcgEx8hPFZAGUBTh3h0WjamdxHpMFUBZg8w6LwemtUMkJmcJimiyAsgCbd1j010FLIX7Mdi7KApyyw+ItMFkAZQGUBVAWQFkAZQGUBVAWQFkAZQGUBVAWQFkAZQGUBVAWQFkAZQH+AEkJCJS/ZGd/AAAAAElFTkSuQmCC

スマホで読み取ると、

データベース上では、

うまくできているようです!

【C#】【数独】仮置きロジックを適用する条件を考える。

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

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

https://github.com/takishita2nd/sudoku

さて、いよいよ仮置きロジックの実装にとりかかります。

そのためには、仮置きロジックを行う条件を考えましょう。

現在まで実装しているロジックでのみで、ある程度はマスを埋めることができますので、そのロジックでも埋まらなかった場合、と考えるのが妥当でしょう。

その条件とは、周期処理の前と後で、確定しているマスの数が同じならば、と判断するのが一番簡単だと思います。

それでは実装します。

まずは、確定しているマスを数えるメソッドを作成します。

        private int countInputedNumber()
        {
            int ret = 0;
            for(int i = 0; i < 9; i++)
            {
                for(int j = 0; j < 9; j++)
                {
                    if(_square[i, j].isConfirmed())
                    {
                        ret++;
                    }
                }
            }
            return ret;
        }

特に難しいところはありませんね。

これを、周期処理に組み込みます。

        private int now_count = 0;
        private int prev_coount = 0;

        public void run()
        {
            bool roop = true;
            while (roop)
            {
                for(int row = 0; row < 9; row++)
                {
                    for(int col = 0; col < 9; col++)
                    {
                        if(_square[row,col].isConfirmed() == false)
                        {
                            Candidate candidate = new Candidate();
                            searchRowLine(row, candidate);
                            searchColLine(col, candidate);
                            search9Area(row, col, candidate);
                            _square[row, col].checkCandidate(candidate);
                        }
                    }
                }
                searchNumber();

                prev_coount = now_count;
                now_count = countInputedNumber();

                if(prev_coount == now_count)
                {
                    //debug
                    Console.WriteLine("ここで仮置きロジックを適用する {0} {1}", prev_coount, now_count);
                    return;
                }

                roop = !checkEnd();
                FileAccess.Output(_square);
            }
        }

こんな感じでどうでしょうか。

prev_coountが周期前の確定したマス数、now_countが周期後の確定したマス数です。

確定したマス数を数える前に前回のマス数を保存し、それと、現周期でのマス数を比較します。

これが同じならば、仮置きロジックを適用する(debug出力を行っているところ)という動きになります。

次回は、このdebugの箇所を考えていきます。

【C#】【数独】オブジェクトを複製する

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

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

https://github.com/takishita2nd/sudoku

仮置きロジックに必要な処理を実装していきます。

まずは、解析状況のデータの複製を作るところです。

仮置き解析して、矛盾があれば、そのデータを破棄するようにします。

オブジェクトの複製に=演算子を使用してはいけません。

これはオブジェクトの移動です。

C言語的に言えば、ポインタを移しているだけです。

なので、オブジェクトをnewで作成して、同じデータを持たせるように設定しなければなりません。

まずは、Squareクラス。

    class Square
    {
        // 確定した数字
        private int _value;
        // 確定したかどうか
        private bool _confirmed;

        public Square()
        {
            this._value = 0;
            this._confirmed = false;
        }

        public Square(int val)
        {
            this._value = val;
            if(val == 0)
            {
                this._confirmed = false;
            }
            else
            {
                this._confirmed = true;
            }
        }

中略

        public Square Clone()
        {
            return new Square(_value);
        }
    }

Clone()で同じデータを持つオブジェクトを作成して返しています。

次に、Sudokuクラス。

    class Sudoku
    {
        private Square[,] _square;

中略

        private Square[,] makeClone(Square[,] _square)
        {
            Square[,] ret = new Square[9, 9];
            for(int i = 0; i < 9; i++)
            {
                for(int j = 0; j < 9; j++)
                {
                    ret[i, j] = _square[i, j].Clone();
                }
            }

            return ret;
        }
    }

Square[]をnewで作成し、SquareのCloneを設定し、返しています。

これでこの関数の戻り値は、完全なSquare[,]の複製が作成されます。

次回は実際に仮置きをするロジックを考えます。

【自作PC】Ryzen5 3600Gでベンチマークを試す。

パーツ交換したら恒例、ベンチマークテスト祭。

ちなみに交換前のスコアはこちら。

ドラクエ10

PSO2

FF14

FF15

PCMARK10

やはり全体的にスコアがアップしました。

PCゲーム系も多少アップしたのも良いですね。

もう、今のPCに満足したので、PCパーツはもう買い事は無いでしょう。(たぶん)

【自作PC】CPUをアップデートしちゃいました。

でん。

ででん。

でででん。

第3世代Ryzen5です。

今までは、Ryzen5 3400でした。

今回はRyzen5 3600です。

これで何が違うかというと、

まずプロセッサーが第2世代から第3世代になりました。

型番は3000番台で、製造時期も第3世代に近いですが、中身は第2世代です。

そして、コア数が4コアから6コアになりました。

スレッド数も8スレッドから12スレッドに増えました。

コア数が増えれば、それだけ同時に処理できる仕事の数が増えるので、それだけでもパワーアップが期待されます。

そして、グラフィックスチップ内蔵だったのが、無くなりました。

まぁ、すでにグラボを使用しているので、問題ありません。

では、まずはCPUを撤去します。

埃だらけのCPUクーラーを取り外し。

CPU撤去。

新しいCPUを装着。

クーラーも取り付け。

ヒートシンクのサイズが小さくなったような気がします。

グラフィックスチップが内蔵されていないため、発熱量が抑えられているのかもしれません。

BIOSで正しく認識されているのを確認しました。

さて、古いCPUは下取りに出して、引っ越し資金の足しにしようと思います。

パーツ型番価格
CPURyzen 5 3600G24368
マザーボードPRIME A320M-A7544
メモリCT2K16G4DFD822614280
電源KRPW-L5-750W/80+6256
ケースCC-9011086-WW5099
SSDGH-SSDR2SA1202178
M.2SSDSCKKW480H6X15980
グラフィックボードSAPPHIRE PULSE RADEON RX 570 8G GDDR514800
DVDドライブIHAS324-17/A2020
OSWindows 10 Pro3259
電源ユニットネジ200
合計85986

【Laravel】【ホテル予約管理】クレジット情報を登録する(訂正)

前回までの状況はこちら

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

https://github.com/takishita2nd/hotel-mng

さて、まずはユーザー登録時にクレジット情報を登録するようにしましょうか。

本来ならば、SSL通信によって、暗号化した状態でデータを送信しなくちゃいけないのですが、今はローカル環境でテスト用に動かしているので、そこら辺は考慮しないことにします。

考慮する場合は、NginxなどのWebサーバの設定が必要になります。

こちら、自前のクラウドサーバをHTTPSに対応した記事が参考になると思います。

それではコーディングしていきます。

やっていることは、以前にも書いた、usersテーブルにカラムを追加していく、ということです。

まずはマイグレーションの記述。

class AddCreditInfoUsers extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('credit_number')->after('phone');
            $table->string('mm')->after('credit_number');
            $table->string('yy')->after('mm');
            $table->string('credit_name')->after('yy');
            $table->string('code')->after('credit_name');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('credit_number');
            $table->dropColumn('mm');
            $table->dropColumn('yy');
            $table->dropColumn('credit_name');
            $table->dropColumn('code');
        });
    }
}

ビューの記述。

                        <div class="form-group{{ $errors->has('credit') ? ' has-error' : '' }}">
                            <label for="credit" class="col-md-4 control-label">credit number</label>

                            <div class="col-md-6">
                                <input id="credit" type="credit" class="form-control" name="credit" required>

                                @if ($errors->has('credit'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('credit') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <label for="mmyy" class="col-md-4 control-label">MM / YY</label>

                            <div class="col-md-6">
                            <select name="mm">
                                <option value="1">01</option>
                                <option value="2">02</option>
                                <option value="3">03</option>
                                <option value="4">04</option>
                                <option value="5">05</option>
                                <option value="6">06</option>
                                <option value="7">07</option>
                                <option value="8">08</option>
                                <option value="9">09</option>
                                <option value="10">10</option>
                                <option value="11">11</option>
                                <option value="12">12</option>
                            </select>
                            /
                            {{Form::selectYear('yy', 2020, 2030)}}
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('credit_name') ? ' has-error' : '' }}">
                            <label for="credit_name" class="col-md-4 control-label">credit name</label>

                            <div class="col-md-6">
                                <input id="credit_name" type="credit_name" class="form-control" name="credit_name" required>

                                @if ($errors->has('credit_name'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('credit_name') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('code') ? ' has-error' : '' }}">
                            <label for="code" class="col-md-4 control-label">security code</label>

                            <div class="col-md-6">
                                <input id="code" type="code" class="form-control" name="code" required>

                                @if ($errors->has('code'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('code') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

入力項目に、クレジット番号、有効期限(MM/YY)、名義、セキュリティコードを追加しました。

バリデーション処理です。

    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|string|max:255',
            'fullname' => 'required|string|max:255',
            'address' => 'required|string|max:255',
            'phone' => 'required|digits:11',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:6|confirmed',
            'credit' => 'required|digits:16',
            'mm' => 'required|numeric',
            'yy' => 'required|numeric',
            'credit_name' => 'required|string|max:255',
            'code' => 'required|digits:3',
        ]);
    }

登録処理です。

    protected $fillable = [
        'name', 'fullname', 'address', 'phone', 'email', 'password', 'credit_number', 'mm', 'yy', 'credit_name', 'code'
    ];
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'fullname' => $data['fullname'],
            'address' => $data['address'],
            'phone' => $data['phone'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
            'credit_number' => encrypt($data['credit']),
            'mm' => $data['mm'],
            'yy' => $data['yy'],
            'credit_name' => encrypt($data['credit_name']),
            'code' => encrypt($data['code'])
        ]);
    }

クレジット番号、名義、セキュリティコードは機密性が高いため、encrypt()(※2020/2/5訂正)で暗号化してわからない形でデータベースに保存します。

※bcrypt()では、復号化できないようです。後ほどこの情報を使って自動決済する必要がありますので、復号化できないと困ります。

うまくできました。

【C#】【数独】解析ロジック(仮置き矛盾チェック)を考える

前回までの状況はこちら

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

https://github.com/takishita2nd/sudoku

さて、以下のような問題が出題されたとき、解析が止まってしまう現象が発生しました。

例えば、数字の2に注目した場合、

オレンジの2箇所と青の2箇所が数字の2が入る可能性があるのですが、今までのロジックでは値が確定しないため、解析が進まない状態となってしまいます。

この場合、仮置きというやり方をします。

例えば、

オレンジのマスに数字2を置いた場合、今までの解析ロジックから青のマスに2が入りますが、同じライン上に2がすでに存在しますので、この置き方は誤りと言うことになります。

逆に、このように置けば、矛盾が発生しませんので、このマスに入る数字は2で確定する事になります。

これをプログラムでロジック化します。

やり方をまとめます。

解析ループ処理に変化が無かった場合、仮置きロジックを適用します。

解析途中のデータを複製し、空いている箇所に、仮の値を置き、通常の解析ロジックを実施します。

その結果、矛盾が発生していれば、その複製データを破棄します。

矛盾が発生していなければ、その値で確定します。

値が確定すれば、その状態で解析を継続します。

ざっくり言えばこんな感じですね。

次回以降、もう少し細かいところを詰めて、実装していこうと思います。

iPhoneの買い換えを予定している人は、3月まで待った方が良いかもしれない。

根拠となる記事

https://www.itmedia.co.jp/news/articles/2001/24/news074.html

この記事によると、iPhoneの廉価版が2月に製造が開始され、3月に発表になるとのこと。

この機種は、iPhone SEの後継機になると思われます。

小型ディスプレイで、最新CPUを搭載したモデルになることが予想されます。

・・・おいらはAndroid派ですけどね。

【Laravel】【ホテル予約管理】次の課題は、自動決済を可能にする。

さて、お次の課題は、自動決済できるようにする、というものです。

具体的には、

  • クレジット情報を登録する
  • QRコードまたはナンバーを発行し、メールで送付する
  • QRコードもしくはナンバーで部屋のロックを解除し、このときに決済を行う。
  • ナンバーを3回間違えたら、ナンバーを再発行する。
  • 時間がすぎると、キャンセル料8割を決済する。

これらから、どのような実装を行うかを検討します。

クレジット情報は、ユーザーテーブルにカラムを追加するだけでいいのですが、通信はすべて暗号化する必要がありますね。

SSLが有効になるように、証明書の発行と、Webサーバの設定を変えなければいけません。

QRコードはナンバーをそのままQRコードに変換するだけで大丈夫でしょう。

幸い、LaravelにはQRコードを生成するライブラリもあるようです。

それをメールで送付しなければならないので、SMTPを使用しなければなりませんね。

QRコードの読み取りは外部のデバイスを使用する、と仮定して、実装はそのデバイスからナンバーを受け取るためのAPIを用意する必要があると思います。

あとは、コンソールコマンドを用意し、cronで定期実行できるようにすれば問題ないでしょう。

それでは次回から早速実装に入ろうと思います。