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

【C#】【数独】ログ出力を強化し不具合を探す

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

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

https://github.com/takishita2nd/sudoku

前回のソースでは、以下のような問題で解析が途中で失敗していました。

この原因を探るため、ログ出力を強化します。

まず、マスに値を入れるタイミングでログを出します。

次に、仮置きロジックを適用する時と、仮置き前に巻き戻しをする時に、それが分かるようにログを出します。

さらに、仮置きロジックを適用する場所をログに出力するようにします。

ここまでやって、 仮置きロジックを適用する場所を探す処理に不具合がある事が分かりました。

        /**
         * 仮置き対象のマスを抽出する
         *
         * squares マス
         */
        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;
        }

★の箇所で、ret=nullで、temp.Count = 0の時に、仮置きロジックを適用する箇所がない(ret.Count=0)となり、解析が終了していることが分かりました。

なので、★の箇所を修正します。

                    if (ret != null)
                    {
                        if (ret.Count > temp.Count && temp.Count != 0)
                        {
                            ret = temp;
                        }
                    }
                    else if(temp.Count != 0)
                    {
                        ret = temp;
                    }

解けました。

難易度★5の問題も解けるようになったので、大抵の問題は解けるようになりました。

もう少し動かしてみます。

【Laravel】【ホテル予約管理】解錠APIを追加する

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

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

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

さて、前回からだいぶ期間が空いてしまいましたが、

続きやります。(思い出すのに時間かかった)

今回は、前回メールに添付したQRコードに書かれた解錠コードを使って解錠する処理を実装するのですが、

実際に解錠を行うのは、外部のデバイスを使用する、という前提として考え、ここではデバイスに入力した解錠コードをサーバに送信し、照合結果を返すAPIを実装します。

このAPIのレスポンスをデバイスが受信して、デバイスが実際に解錠を行います。そういう想定で実装します。

まず、APIのルーティングを作成します。

routes配下のapi.phpに以下を追加します。

Route::group(['middleware' => ['api']], function(){
    Route::post('/unlock', 'Api2Controller@unlock');
});

なぜ、今までのようにweb.phpではないかというと、web.phpには

Auth::routes();

がかかれてあり、ログイン状態でアクセスしなければAPIは受け付けられません。

デバイス側にログイン状態というのは意識できないので、この制約が入らないルートに設定しなければなりません。

では、コントローラーを作成します。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Repository\RegisterManagementRepository;
use App\Repository\RoomRepository;
use App\Repository\UserRepository;

class Api2Controller extends Controller
{
    public function __construct()
    {
        $this->registerManagement = new RegisterManagementRepository();
        $this->room = new RoomRepository();
        $this->user = new UserRepository();
    }

    public function unlock(Request $request)
    {
        \Log::debug(print_r($request->input('number'), true));
        \Log::debug(print_r($request->input('room'), true));

        $registers = $this->registerManagement->getItemsByDate(date('Y-m-d'));
        if(is_null($registers) == false)
        {
            foreach ($registers as $register)
            {
                $room = $register->rooms()->first();
                if(is_null($room) == false)
                {
                    if($room->id == $request->input('room') &&
                        strcmp($register->lock_number, $request->input('number')) == 0)
                    {
                        return response()->json(['result' => true]);
                    }
                }
            }
        }
        return response()->json(['result' => false]);
    }
}

Api2Controller.phpを追加しました。

ApiController.phpでは、コンストラクタに

        $this->middleware('auth');

と記述しているため、これも上記と同じ理由で使用できません。

入力は部屋番号と解錠コードをjsonで入力します。

現在の日付から予約情報を取得し、部屋番号を解錠コードの比較を行い、一致したときにtrue、一致しない場合はfalseを返します。

思ったように動いているようです。

ただし、このままだと誰でもアクセスできてしまうので、セキュリティ的にガバガバ状態です。

デバイス情報を登録して、それも入力情報に含めるようにしましょうか。

次回やります。

北海道でも5Gサービスが始まるらしい。

元ネタはこちら

https://k-tai.watch.impress.co.jp/docs/news/1241563.html

ドコモの公式発表によると、全国の特定スポットにて5Gサービスが提供されます。

https://www.nttdocomo.co.jp/area/5g/?icid=CRP_menu_to_CRP_AREA_5g

その中には北海道も含まれています。

しかし、本当にとあるポイント周辺に限られているので、いつでも5Gが使えるわけではありません。

では、北海道ではどこで5Gが使えるのか。

PDFファイルにも書いてあるのですが、

  • 札幌ドーム( 観客席、ドーム前広場周辺 )
  • JR札幌駅( 南口広場周辺、北口(東)周辺 )
  • 札幌駅前通地下広場 ( 北大通交差点広場(西)周辺 )
  • 大通公園西12丁目広場
  • 大通公園西9丁目広場
  • 一部のドコモショップ店内

本当に特定ポイントやね。

5Gを利用するためには、対応端末が必要です。(知ってると思うけど)

全国で使用できるには、少なくとも1年は待つ必要はあります。

なので、今焦って買う必要は無いと思います。

5G試せる人は一部のガジェットマニアぐらいか・・・

【Laravel】まっさらな状態のLinuxから環境構築

この記事、定期的にアップデートしていこう。

MySQLのセットアップ

composerのインストール

$ sudo apt-get install composer

phpの足りないモジュールをインストール

$ sudo apt-get install php7.2-mbstring
$ sudo apt-get install php7.2-xml
$ sudo apt-get install php7.2-zip
$ sudo apt-get install php7.2-gd
$ sudo apt-get install php7.2-mysql

nginxのインストール

Laravelの設定

$ composer global require "laravel/installer"
$ cd /var/www
$ sudo chmod 777 html
$ cd html

リポジトリからLaravelのソースをclone

$ git clone リポジトリのURL
$ chmod 777 storage/
$ chmod 777 bootstrap/cache/

.envを作成して、設定を記入

$ composer install
$ php artisan key:generate

node.jsのセットアップ

$ sudo apt-get install npm
$ sudo apt-get install libpng-dev
$ npm install
$ npm run dev

データベースを設定

$ php artisan migrate
$ php artisan db:seed --class=実行するseederクラス

【Linux】mysqlをセットアップしたら躓いたので

忘れないようにメモしておく。

MySQLのインストール

$ sudo apt-get install mysql-server

rootパスワード設定

$ sudo mysql_secure_installation

問い合わせはすべてyを入力。

rootでログインを確認

$ sudo mysql -u root -p

MySQLにユーザーを追加

mysql> CREATE USER 'user'@'localhost' IDENTIFIED BY 'password'

ユーザーに権限を設定

mysql> GRANT all ON *.* TO 'user'@'localhost'

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のソースコードを参照して頂ければ。

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