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

【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で定期実行できるようにすれば問題ないでしょう。

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

これだけは知っておきたい。Web開発に必要な周辺技術って何ですか?

Twitterで昔こんな会話をしていたので、

Web開発に必要な技術を、自分の経験とともにまとめてみたいと思います。

Web開発って、コーディングができれば良いってもんじゃ無いんですよ。

Web自体がいろんな技術の組み合わせで成り立っているので、それを知らないと、万が一のトラブルの時に対応出来ないのですよ。

その当たりのサポートもできれば、一人前のWeb開発者です。

Linux

WebサーバのほとんどがLinux系OSで動作しています。

その理由は、コスト。

Linuxはオープンソースで開発されたOSなので、OSそのものにお金がかかりません。

その代わりメンテナンスも自分でやらないといけませんがね。

通信プロトコル(http等)

ブラウザのWebサーバの間はHTTPという通信プロトコルを使用しています。

Ajaxを使用した場合もその都度HTTPを使用することになりますので、その当たりの知識も勿論必要になります。

Webサーバ(Apache or Nginx)

サーバにソースファイルを置いただけでは機能しません。

HTTPを処理してくれるWebサーバがあって初めてWebページが機能します。

Apacheはリソースを多く使用しますが、プラグインで機能追加できるので、扱いやすいです。

Nginxは非常に軽量で動作できるWebサーバです。

玄人からすれば、Nginxの方が好まれるようです。

データベース

Webシステムでは大量のデータを扱いますので、データベースを理解することは非常に重要です。

自分も今は慣れましたが、情報処理の資格を取るのにSQLを覚えるのが大変でした。

データベースの種類は沢山ありますが、基本的なSQL文は共通しているので、基本的なところを押さえれば問題無いでしょう。

このほかにも、使用するフレームワークやライブラリなどが挙げられますが、挙げれば切りが無いので、必要なときにその都度勉強する必要があります。

もう勉強することが多くてたいへんよぉ

でも知識はあればあるだけその分自分に有利に働きますので、学ぶことは大事。

ITエンジニアは日々勉強です。

【Laravel】【ホテル予約管理】レスポンシブ対応を行う

前回までの状況はこちら

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

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

さて、残る作業はレスポンシブ対応ですが、

そもそも、レスポンシブ対応とは何かというと、

PCだけでなく、スマホやタブレットでも、そのデバイスに対応した表示に切り替えることができる対応、ということです。

PCでは正しく表示できても、スマホだと表示が崩れて使用できない、というのはレスポンシブ対応とは言えません。

その確認のために重宝するのが、Google Chromeのレスポンシブモード。

擬似的にスマホやタブレットでの表示に切り替えてくれる機能です。

使い方は、Google Chromeの画面でF12を押し、

このボタンをクリックして青色(絵の状態)にします。

表示エリア上部にこんな感じのバーが表示されますので、ここをクリックすることで、画面の表示解像度を切り替えることができます。

こうやってレスポンシブ対応できているかを確認するのですね。

実機を使うと、それだけ実物のデバイスを用意しなければなりませんので、これはかなり有効な確認方法です。

ためしに、作成中のいろんなページを表示させてみましょう。

こんな感じで文字が2行になるのはまだ読めるのでセーフです。

こんな感じで表示が枠からはみ出てしまったらアウトですね。

修正する必要があります。

こういうのは、たいていテンプレートやスタイルの問題です。

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

いい感じに仕上がったと思います。

実は、Laravelには、標準でBootstrapというJSライブラリが組み込まれていて、このライブラリでブラウザ差分を吸収したり、基本的なレスポンシブ対応を行えるようにしてくれています。

今作成している機能はBootstrapをバリバリ活用した作りになっていません。そもそもそんな表示をするところが無いためです。

もしかしたら、画像のサムネイルなどをたくさん表示させたり、表を二列に表示させる場合などに活用することになるかもしれませんね。

まぁ、これで最終チェックして提出しようと思います。

【C#】【数独】解析ロジック(ラインチェック)を追加する

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

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

https://github.com/takishita2nd/sudoku

さて、前回のアルゴリズムで、いくつか問題を解いてみたのですが、

こんな問題の時、解析が完了しませんでした。

この状態のまます、解析が進まなかったんですね。

この状態、手で解いた場合、

この2箇所に「3」が入ります。

この時の解析ロジックを組み込まなければなりません。

では、どうやって解析すればいいのか。

この場合、3という数字に注目すると、

この部分、および、すでに確定されているマスに「3」が入ることができません。

赤いところの9マスは一箇所しか空いていないため、そこの空いているマスには「3」が入ることが確定されます。

これをプログラミングで行います。

考え方は、9×9の二次元配列を用意し、各数字について、入れることができないマスを埋めていき、9エリアに一箇所だけ空きがあれば、その値が確定する、とします。

        private void searchNumber()
        {
            for(int number = 1; number <= 9; number++)
            {
                bool[,] tempTable = new bool[9, 9];
                // 初期化
                for (int i = 0; i < 9; i++)
                {
                    for (int j = 0; j < 9; j++)
                    {
                        tempTable[i, j] = false;
                    }
                }

                // 数字が入らないところをtrueにする
                for (int i = 0; i < 9; i++)
                {
                    for(int j = 0; j < 9; j++)
                    {
                        if(tempTable[i,j] == false)
                        {
                            tempTable[i, j] = _square[i, j].isConfirmed();
                            if(_square[i,j].GetValue() == number)
                            {
                                for(int row = 0; row < 9; row++)
                                {
                                    tempTable[row, j] = true;
                                }
                                for(int col = 0; col < 9; col++)
                                {
                                    tempTable[i, col] = true;
                                }

                                int rowStart;
                                int colStart;
                                getRowCol9Area(i, j, out rowStart, out colStart);
                                for (int r = rowStart; r < rowStart + 3; r++)
                                {
                                    for (int c = colStart; c < colStart + 3; c++)
                                    {
                                        tempTable[r, c] = true;
                                    }
                                }
                            }
                        }
                    }
                }

                // debug
                FileAccess.Output(tempTable);

                // 結果を確認する
                for(int i = 0; i < 9; i++)
                {
                    for(int j = 0; j < 9; j++)
                    {
                        if(tempTable[i,j] == false)
                        {
                            int rowStart;
                            int colStart;
                            getRowCol9Area(i, j, out rowStart, out colStart);

                            int count = 0;
                            for (int r = rowStart; r < rowStart + 3; r++)
                            {
                                for (int c = colStart; c < colStart + 3; c++)
                                {
                                    if(tempTable[r,c] == false)
                                    {
                                        count++;
                                    }
                                }
                            }
                            if(count == 1)
                            {
                                _square[i, j].SetValue(number);
                            }
                        }
                    }
                }
            }
        }

        private void getRowCol9Area(int row, int col, out int rowStart, out int colStart)
        {
            if (row >= 0 && row <= 2)
            {
                rowStart = 0;
            }
            else if (row >= 3 && row <= 5)
            {
                rowStart = 3;
            }
            else
            {
                rowStart = 6;
            }

            if (col >= 0 && col <= 2)
            {
                colStart = 0;
            }
            else if (col >= 3 && col <= 5)
            {
                colStart = 3;
            }
            else
            {
                colStart = 6;
            }
        }

一応、色塗りした処理結果もデバッグ用に出力させました。

3の時の色塗り結果を見てみると、9マスで一か所だけ空きがあることが分かります。

目論見通り、3が確定されました。

全部埋まりました。

ロジックがうまく働いたようです。