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

Hyper-Vで仮想マシンにLinuxを動かす

そういえば、今使っているPCのWindows10がProなので、デフォで仮想環境が使える、と言うことに気がついたので。

これを使えば、VMwareとか、Virtual Boxとか使わなくても仮想環境を構築することができる。

参考にしたサイトはこちら。(Microsoftのヘルプページ)

https://docs.microsoft.com/ja-jp/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v

Hyper-Vを有効にして、Hyper-Vマネージャーから仮想マシンを作成すると、すでにUbuntu18.04のテンプレートが用意されているので、これを選択すると、自動的にisoイメージのダウンロード、インストールまで完了します。

注意するところは、リモートデスクトップで接続しないこと。

そりゃそうだ。インストール直後のUbuntuはリモートデスクトップを許可していないので。接続できるはずがありません。

リモートデスクトップ接続をキャンセルすれば、仮想マシンのデスクトップを直で表示されます。

ただ、このままだと、画面解像度的に使いづらいので、解像度の設定を書き換えます。

参考にしたサイトはこちら。(Qiita)

https://qiita.com/mizutoki79/items/6122455bfa2755942488

$ sudo vi /etc/default/grub

で設定ファイルを開いて、以下のように書き換えます。

GRUB_CMDLINE_LINUX_DEFAULTの行にvideo=hyperv_fb:[変更したい解像度]を書き足します。

1920×930程度にしておけば、フルHDのデスクトップにちょうど収まります。

そして以下のコマンドで設定を反映。

$ sudo update-grub

間違えてFedoraのコマンドを使用すると起動不能になる。(やらかした)

使ってみた感じでは、非常に快適です。

これなら本当にVMwareとかいらないかも。

メモリも32GBと余るほどあるので、半分の16GBをHyper-Vに割り当てても余裕。

まずい、これは本当にLinux PCいらないぞ。

とりあえず、開発環境をセットアップして見ようか。

【数独】まだまだ完成には程遠いみたい。

ナンプレアプリの問題を、数独解析プログラムに与えて、とけるかどうかを確認しているのですが、

難易度★4ならば、数独解析プログラムで解ける様になりましたが、難易度★5の中には、解けない問題があるようです。

赤いところが誤りの箇所です。

一応、解析途中の内容もアウトプットとして出力しているのですが、いまのままではちょっと解けない理由がわからないんですよね。

ちょっと出力処理に手を加えないと、解析が難しいです。

具体的にどうするかはこれから考えます。

まぁ、★4クリアできたからある程度満足ではあるけれども。

プログラマーはエラー処理に頭を悩ませる。

プログラムというのは、目的通りに動いていればいい、という訳ではありません。

目的通りに動かすのは「当たり前」で、それ以上に頭を悩ませるのがエラー処理なんです。

具体的には、なんらかの要因で正しい処理が行えなくなった場合でも、正しい状態を保つ、ということをプログラミングしなければなりません。

前者が「正常系」と呼ぶのに対し、後者は「準正常系」と呼んでいました。

ちなみに、それ以外の深刻な問題が発生したときは「異常系」と呼んで、オペレーターに異常を知らせる処理を実行します。主にハードウェアの故障などがこれに該当します。

準正常系は、入力データの異常や割り込み処理などが該当します。

ソフトウェア設計者は、こういった準正常系の処理を全て網羅して、あらかじめエラーを検出し、本来の正常な動作を保つように設計しなければなりません。

設計者が頭を悩ませるのが、「準正常系に漏れが無いよね?」ということなんです。

我々がニュースなどで耳にする「ソフトウェアの異常」というのは、大抵、準正常系の考慮が漏れていたことに起因します。

そして、本番でこういうことが起きないように、出荷前に様々なテストデータを用意して、徹底的にいじめます。

特に組み込み系のファームウェアは、簡単にアップデートできないので、出荷から当分の間はヒヤヒヤします。

トラブルがあったら現場大炎上なので。

では、どうすれば良いかというと、これも難しい話で、経験を積み重ねるしか無いんですよ。

ベテラン技術者にレビューして貰うのも一つの手です。

まぁ、ソフトウェア製品の開発にはこんな事があるんですよ、ということで理解して貰えれば。

【C#】【数独】仮置きロジック簡略化の修正を元に戻した。

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

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

https://github.com/takishita2nd/sudoku

修正を戻したのは、重大な欠陥に気がついたためです。

仮置きロジックを再起実行させたときに矛盾を検出した場合、正しく処理されない、という動きが発生していました。

やはり、面倒でも、仮置きロジックを再起処理から全てリターンして、値を一つずつ確定していくのが一番良い方法だと思います。

このコードでもう少し問題を解いてみます。

そして、最高難度の問題でも解けるかを確認していきたいと思います。

【C#】【数独】仮置きロジックを簡略化する。

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

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

https://github.com/takishita2nd/sudoku

前回、仮置きロジックを完成させたのですが、

このコード、結構無駄な処理をやっていることに気がついたんですよ。

        private Square doKarioki(Square[,] squares)
        {
            Square ret = null;
            List<Square> kariokiList = searchKariokiSquare(squares);
            foreach (var s in kariokiList)
            {
                bool roop = true;
                int kariValue = GetUnconfirmedValue(s.GetCandidate());
                if (kariValue == 0)
                {
                    return null;
                }
                Square[,] copySquare = makeClone(squares);
                copySquare[s.Row, s.Col].SetValue(kariValue);
                int now_count = 0;
                int prev_coount = 0;
                while (roop)
                {
                    for (int row = 0; row < 9; row++)
                    {
                        for (int col = 0; col < 9; col++)
                        {
                            if (copySquare[row, col].isConfirmed() == false)
                            {
                                Candidate candidate = new Candidate();
                                searchRowLine(copySquare, row, candidate);
                                searchColLine(copySquare, col, candidate);
                                search9Area(copySquare, row, col, candidate);
                                copySquare[row, col].checkCandidate(candidate);
                            }
                        }
                    }
                    searchNumber(copySquare);

                    if (checkContradict(copySquare))
                    {
                        break;
                    }

                    prev_coount = now_count;
                    now_count = countInputedNumber(copySquare);

                    if (prev_coount == now_count)
                    {
                        Console.WriteLine("仮置きロジック");
                        Square s2 = doKarioki(copySquare);
                        if (s2 == null)
                        {
                            Console.WriteLine("失敗しました");
                            return null;
                        }
                        else
                        {
                            copySquare[s2.Row, s2.Col].SetValue(s2.GetValue());
                        }
                    }

                    if (checkEnd(copySquare) == true)
                    {
             ★
                        roop = false;
                        s.SetValue(kariValue);
                        Console.WriteLine("[{0},{1}] = {2}", s.Row, s.Col, s.GetValue());
                        ret = s;
                    }
                    FileAccess.Output(copySquare);
                }
                if(ret != null)
                {
                    break;
                }
            }
            return ret;
        }

今までは★に入ったタイミングで仮置きした値が確定して、という処理を行っていたんですが、

実はここに入った時点で解析結果が判明しているんですよね。

なので、この時点で解析結果を出力して終了、という処理にすれば、大幅に処理が短くなるはずです。

詳細はgitHubのソースコードを参照して頂ければ。

ついでに関数ヘッダにコメント入れました。

【C#】【数独】矛盾チェック処理と仮置きロジック再帰処理の実装

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

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

いやーロジック考えるのに時間かかりました。

まず、仮置きロジックを完成させるには、仮置きした結果、矛盾が発生した、ということを検出できる用にしなければならなくて。

これが、以外と難しい。

実際のコードは短くなっても、そこにたどり着くのが難しいのです。

オイラはこのように書きました。

        private bool checkContradict(Square[,] squares)
        {
            for (int row = 0; row < 9; row++)
            {
                for (int col = 0; col < 9; col++)
                {
                    if(squares[row,col].isConfirmed() == false)
                    {
                        Candidate candidate = new Candidate();
                        searchRowLine(_square, row, candidate);
                        searchColLine(_square, col, candidate);
                        search9Area(_square, row, col, candidate);
                        if(candidate.Count() == 9)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

値は確定していない、しかし、縦、横、9マスを調べた結果、置ける数字が無い場合、という風に考えました。

これを使って仮置きロジックを作成します。

        private Square doKarioki(Square[,] squares)
        {
            Square ret = null;
            List<Square> kariokiList = searchKariokiSquare(squares);
            foreach (var s in kariokiList)
            {
                bool roop = true;
                int kariValue = GetUnconfirmedValue(s.GetCandidate());
                if (kariValue == 0)
                {
                    return null;
                }
                Square[,] copySquare = makeClone(squares);
                copySquare[s.Row, s.Col].SetValue(kariValue);
                int now_count = 0;
                int prev_coount = 0;
                while (roop)
                {
                    for (int row = 0; row < 9; row++)
                    {
                        for (int col = 0; col < 9; col++)
                        {
                            if (copySquare[row, col].isConfirmed() == false)
                            {
                                Candidate candidate = new Candidate();
                                searchRowLine(copySquare, row, candidate);
                                searchColLine(copySquare, col, candidate);
                                search9Area(copySquare, row, col, candidate);
                                copySquare[row, col].checkCandidate(candidate);
                            }
                        }
                    }
                    searchNumber(copySquare);

                    if (checkContradict(copySquare))
                    {
                        break;
                    }

                    prev_coount = now_count;
                    now_count = countInputedNumber(copySquare);

                    if (prev_coount == now_count)
                    {
                        Console.WriteLine("仮置きロジック");
                        Square s2 = doKarioki(copySquare);
                        if (s2 == null)
                        {
                            Console.WriteLine("失敗しました");
                            return null;
                        }
                        else
                        {
                            copySquare[s2.Row, s2.Col].SetValue(s2.GetValue());
                        }
                    }

                    if (checkEnd(copySquare) == true)
                    {
                        roop = false;
                        s.SetValue(kariValue);
                        Console.WriteLine("[{0},{1}] = {2}", s.Row, s.Col, s.GetValue());
                        ret = s;
                    }
                    FileAccess.Output(copySquare);
                }
                if(ret != null)
                {
                    break;
                }
            }
            return ret;
        }

難しかったのが、仮置きロジックの計算中に再び仮置きロジックが必要になった場合。

そう、このロジックを再帰的に実行する処理が必要なのです。

これを実装するために、これ以外の所もかなりの広範囲で書き換えています。

しかし、これでようやく解を得ることができました。

138964275
624715398
957283614
285637941
796841523
341529786
512476839
479358162
863192457

このロジックでいろいろな問題を解いてみようと思います。

【LARAVEL】【ホテル予約管理】QRコードをメールに添付して送信する

前回までの状況はこちら

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

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

さて、前回作成したQRコードをメールに添付して送信する実装を行います。

メーラーはGMAILを使用します。

自前のsmtpサーバを使おうとしたけど、うまくいかなかった。

smtpサーバの設定を.envに記入します。

MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=xxxxx@gmail.com
MAIL_PASSWORD=xxxxx
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=xxxxx@gmail.com
MAIL_FROM_NAME=xxxxxx

内容を使用しているアカウント情報に合わせてください。

tinkerを使って、設定が正しいかを確認することができます。

$ php artisan tinker
>>> Mail::raw('test mail',function($message) {$message->to('xxxxx@gmail.com')->subject('test');});
=> null

正しく設定されていれば、メールが届くはずです。

※エラーが表示される場合は、GMAIL側の設定の問題だったりします。セキュリティ設定を変えてみてください。

では、メールを扱う処理を書いていきましょう。

以下のコマンドでメールクラスを作成します。

$ php artisan make:mail SendQRcodeMail

以下のように書き換えます。

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendQRcodeMail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($img)
    {
        $this->img = $img;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('emails.mail')
            ->from('manager@gmail.com','manager')
            ->subject('予約しました')
            ->attach($this->img);
    }
}

コンストラクタでQRコードの画像パスを受け取り、buildメソッドの中でattachで添付する、という処理になっています。

では、これを使用する処理を記入します。

use App\Mail\SendQRcodeMail;
use Mail;

    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();
        QrCode::format('png')->size(100)->generate($model->lock_number, public_path('/img/qr.png'));
        $model->save();
        $this->attachToRoom($model, $room);
        $this->attachToSchedule($model);
        $this->attachToUser($model, $user);

        $to = [
            [
                'email' => $user->email, 
                'name' => $user->fullname,
            ]
        ];
        Mail::to($to)->send(new SendQRcodeMail('/var/www/html/hotel-mng/public/img/qr.png'));

    }

base64を添付しようと思いましたが、うまく行かなかったので、generateで画像をファイルに出力します。

Mailクラスを使用して、$toに宛先(ユーザー登録時に入力したものを使用します。)を設定し、sendで先程のクラスを使用します。

コンストラクタの引数には、画像のフルパスを設定します。

最後に、メールの本文。

[添付ファイル]

画像を表示できればいいので、シンプルなテンプレートにしました。

これをresources/views/emails/mail.blade.phpとして、保存します。

これで、正しく動いていれば、予約登録時にメールでQRコードが届きます。

【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の箇所を考えていきます。