【C#】【数独】終了判定を実装する

前回までの状況はこちら

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

https://github.com/takishita2nd/sudoku

さて、最後に解析終了処理を実装していきます。

解析終了条件は、9×9=81マス全ての数字が確定した場合、になります。

逆に言えば、81マスの中で、一つでも確定していないマスがあれば、終了しない、と言うことになります。

と言うわけで、コードはこうなりました。

        private bool checkEnd()
        {
            for (int i = 0; i < 9; i++)
            {
                for(int j = 0; j < 9; j++)
                {
                    if(_square[i, j].isConfirmed() == false)
                    {
                        return false;
                    }
                }
            }
            return true;
        }

解析終了ならばtrueを、そうでないならばfalseを返します。

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

        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);
                        }
                    }
                }

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

ループ条件と判定結果が反転しているので、!演算子で反転させています。

実行結果はこちら。

ちゃんと全部埋まった時点で終了しました。

【Laravel】【ホテル予約管理】忘れていた機能を追加する

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

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

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

さて、ここである重大な欠陥を見つけてしまいました。

それは、Vue.jsで実装を行った際、管理者が予約をチェックする処理の実装を忘れていました。

いかんいかん、完全にミスったわ。

というわけで、ここを実装します。

修正するのは予約一覧から予約をクリックして表示される予約詳細画面です。

管理者がこの画面を表示させた場合、チェックボタンを追加し、チェック処理を行います。

Vue.jsのテンプレートと処理を追加します。

            <p>
                <button @click="closeModal">close</button>
                <button v-if="edit_flg == false" @click="onClickEdit">編集</button>
                <button v-else @click="onClickSave">保存</button>
                <button v-if="edit_flg == false" @click="onClickDelete">削除</button>
                <button v-if="role == true && edit_flg == false" @click="onClickCheck">チェック</button>
            </p>
        data() {
            return {
                role: false,
                error_message: "",
                error_flg:false,
                errors: {},
        created: function() {
            this.getRole();
            this.getRooms();
            this.getTimeList();
        },
        methods: {
            getRole: function() {
                var self = this;
                axios.post('/api/role').then(function(response){
                    self.role = response.data.role;
                }).catch(function(error){
                    console.log("失敗しました");
                });
            },

データにroleフラグを追加し、画面表示時にroleの取得を行います。

trueが返れば管理者であるということなので(ここは前回実装の動きに合わせる)、role=trueならば、チェックボタンを表示させます。

また、編集中はチェックボタンを表示させないようにします。

では、API部分の実装。

    public function check(Request $request)
    {
        $this->registerManagement->lodging($request->id);
        return response()->json(['registerLists' => $this->registerManagement->getListByMonth(
            $request->year,
            $request->month,
            $request->room,
            Auth::user()
        )]);
    }

チェックの実行を行った直後に、予約一覧を返すことで、チェック後の予約一覧を素早く表示させることができます。

最後Routeを追加。

Route::post('/api/check', 'ApiController@check');

これで機能するようになりました。

ふぅ。(汗

【C#】【数独】数独解析ロジックを実装する。

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

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

https://github.com/takishita2nd/sudoku

多分、今回が一番のキモ。

実際に数独を解析するロジックを作成していきます。

そもそも、数独のルールは、

オレンジのところに入る数字は、黄色の縦、横、9マスの部分に同じ数字が存在してはならない、ということです。

ということは、黄色の部分を検索して、そのなかに含まれない数字が、このマスに入る数字の候補となります。

そのとき、もし、候補が一つしか存在しない場合は、その値がそのマスに入る数字で確定します。

この調査を、確定していないマス全てに対して、全てのマスが確定するまで実施します。

では、まずは候補を調査した結果を格納するクラスの定義。

    class Candidate
    {
        public bool[] value;

        public Candidate()
        {
            this.value = new bool[9] { false, false, false, false, false, false, false, false, false };
        }

        public int Count()
        {
            int ret = 0;
            foreach(var val in this.value)
            {
                if(val == true)
                {
                    ret++;
                }
            }

            return ret;
        }
    }

boolean値の配列9個を持ち、コンストラクタでfalseに初期化します。

メソッドとしては、この中でいくつヒットしたか、配列のtrueの数を数えて結果を返すメソッドを持ちます。

これを使用して、実際に調査を行う処理はこちら。

    class Sudoku
    {
        private Square[,] _square;

        /**
         * コンストラクタ
         */
        public Sudoku(Square[,] square)
        {
            _square = square;
        }

        /**
         * 実行
         */
        public void run()
        {
            int roop = 0;
            while (true)
            {
                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);
                        }
                    }
                }

                //debug
                roop++;
                FileAccess.Output(_square);
                if(roop == 10)
                {
                    break;
                }
            }
        }

        private void searchRowLine(int row, Candidate candidate)
        {
            for(int i = 0; i < 9; i++)
            {
                int val = _square[row, i].GetValue();
                if(val != 0)
                {
                    candidate.value[val - 1] = true;
                }
            }
        }

        private void searchColLine(int col, Candidate candidate)
        {
            for (int i = 0; i < 9; i++)
            {
                int val = _square[i, col].GetValue();
                if (val != 0)
                {
                    candidate.value[val - 1] = true;
                }
            }
        }

        private void search9Area(int row, int col, Candidate candidate)
        {
            int rowStart;
            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;
            }

            for(int r = rowStart; r < rowStart+3; r++)
            {
                for (int c = colStart; c < colStart + 3; c++)
                {
                    int val = _square[r, c].GetValue();
                    if (val != 0)
                    {
                        candidate.value[val - 1] = true;
                    }
                }
            }
        }
    }

searchRowLine()では、横のラインを、

searchColLine()ででゃ、縦のラインを、

search9Area()では9マスの範囲を検索します。

ヒットした数字に対して、candidateの持つ配列にtrueを設定します。

なお、-1しているのは、数独に設定する数字が1~9なのに対し、プログラム上の配列の範囲は0~8なので、その補正です。

そして、調査結果を反映する処理はこちら。

    class Square
    {
:
中略
:
        public void checkCandidate(Candidate candidate)
        {
            if(candidate.Count() == 8)
            {
                for(int i = 0; i < 9; i++)
                {
                    if(candidate.value[i] == false)
                    {
                        SetValue(i + 1);
                    }
                }
            }
        }
    }

調査結果、見つかった数字の数が8個だった場合、見つかっていない数字を探し、その値でマスの値を確定します。

これをrun()メソッドで、確定していない全マスに対して行います。

本来は、全てのマスが埋まったことを確認して終了しなければならないのですが、そこはまだ作っていないので、とりあえず、10回繰り返す、と言うことにしています。

では、実際に動かしてみます。

インプットデータはこちら。

実行結果はこちら

1回ループする毎に、途中結果も全てファイルに吐き出すようにしています。

見事に全部埋まりました。

これを、ナンプレアプリに入力してみましょう。

目論見通りに動いてくれましたね。

多分、簡単な数独問題ならこれで解けるはず。

【Laravel】【ホテル予約管理】管理者画面の修正

前回までの状況はこちら

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

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

さて、前回はユーザーログインでのあれこれを修正したのですが、それに伴って、管理者ログインでのあれもれも直す必要があります。

まずは、予約一覧画面。

ユーザーログインでは、ログインしたユーザーのもののみを表示させましたが、管理者ログインでは、全ユーザーの情報を表示する必要があります。

なので、ロール「管理者(manager)」でなければwhere句でユーザーを指定するというふうに変えなければなりません。

    public function getListByMonth($year, $month, $room, $userId)
    {
        $select = ['reserve_managements.id as id', 'users.name as name', 'users.address as address', 'users.phone as phone', 'num', 'rooms.id as roomid', 'rooms.name as room', 'days', 'checkout', 'start_day'];
        $query = ReserveManagement::select($select)
                                ->leftJoin('reserve_management_room', 'reserve_managements.id', '=', 'reserve_management_room.reserve_management_id')
                                ->leftJoin('rooms', 'reserve_management_room.room_id', '=', 'rooms.id')
                                ->leftJoin('reserve_management_user', 'reserve_managements.id', '=', 'reserve_management_user.reserve_management_id')
                                ->leftJoin('users', 'reserve_management_user.user_id', '=', 'users.id')
                                ->where('start_day', '>=', date('Y-m-d', strtotime('first day of '.$year.'-'.$month)))
                                ->where('start_day', '<=', date('Y-m-d', strtotime('last day of '.$year.'-'.$month)))
                                ->where('reserve_management_room.room_id', $room)
                                ->where('lodging', false);
        if(Gate::denies('manager')){
            $query = $query->where('users.id', $userId);
        }
        $query = $query->orderBy('start_day');
        return $query->get();
    }

こんな感じで、where()を、Gate::denies()で「管理者以外」とすれば、このwhereはユーザーログインのみに適用されます。

次は、予約追加画面。

ユーザーログインの場合は、ログイン中の名前などの表示させましたが、管理者ログインの場合は、登録されているユーザーを選択して登録しなければなりません。

ここでVue.jsの出番です。(まじか・・・)

まずはテンプレート。

基本的には、編集時のVue.jsを参考にしています。

<template>
    <div>
        <p v-if="error_flg == true" class="error">{{error_message}}</p>
        <table class="edit">
            <tbody>
                <tr>
                    <th>名前</th>
                    <td v-if=role>{{ contents.name }}<button @click="openModal">検索</button></td>
                    <td v-else>{{ contents.name }}</td>
                </tr>
                <tr>
                    <th>住所</th>
                    <td>{{ contents.address }}</td>
                </tr>
                <tr>
                    <th>電話番号</th>
                    <td>{{ contents.phone }}</td>
                </tr>
                <tr>
                    <th>人数</th>
                    <td>
                        <select v-model=contents.num>
                            <option v-for="num in nums" v-bind:value="num.value">{{ num.text }}</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <th>宿泊部屋</th>
                    <td>
                        <select v-model="contents.roomid">
                            <option v-for="room in rooms" v-bind:value="room.id">{{ room.name }}</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <th>宿泊日数</th>
                    <td><input type="number" v-model=contents.days /></td>
                </tr>
                <tr>
                    <th>宿泊日</th>
                    <td><input type="date" v-model=contents.start_day /></td>
                </tr>
                <tr>
                    <th>チェックアウト</th>
                    <td>
                        <select v-model="contents.checkout">
                            <option v-for="time in timeList" v-bind:value="time.key">{{ time.value }}</option>
                        </select>
                    </td>
                </tr>
            </tbody>
        </table>
        <p><button @click="regist">登録</button></p>
        <div id="overlay" v-show="showContent">
            <div id="content">
                <table class="edit">
                    <p>名前<input type="text" v-model=param.search /></p>
                    <tbody>
                        <tr>
                            <th>名前</th>
                            <th>住所</th>
                            <th>電話番号</th>
                        </tr>
                        <tr v-for="user in users" @click="selectUser(user)">
                            <td class="name">{{ user.name }}</td>
                            <td class="address">{{ user.address }}</td>
                            <td class="phone">{{ user.phone }}</td>
                        </tr>
                    </tbody>
                </table>
            <p>
                <button @click="closeModal">close</button>
                <button @click="searchUsers">検索</button>
            </p>
            </div>
        </div>
    </div>
</template>

まず、テーブルの部分ですが、名前、住所、電話番号以外は、編集画面をそのまま使用しました。

問題の、名前、住所、電話番号の部分ですが、管理者ログインならば、検索ボタンを設置し、それをクリックするとモーダルダイアログを表示する、という仕組みにしたいと思います。

モーダルダイアログでユーザーを検索し、その名前をクリックすると、登録画面に反映される、という動きにします。

実際の処理。

<script>
    export default {
        data() {
            return {
                role: false,
                error_message: "",
                error_flg:false,
                errors: {},
                nums: [
                    {text:'1', value:1},
                    {text:'2', value:2}
                ],
                timeList:[],
                rooms: [],
                users: [],
                showContent: false,
                param: {
                    search: "",
                },
                contents: {
                    id: 0,
                    name: "",
                    address: "",
                    phone: "",
                    num: 0,
                    roomid: 0,
                    room: "",
                    days: 0,
                    start_day: "",
                    checkout: "",
                },
            }
        },
        created: function() {
            this.getRole();
            this.getRooms();
            this.getTimeList();
        },
        methods: {
            getRole: function() {
                var self = this;
                axios.post('/api/role').then(function(response){
                    self.role = response.data.role;
                    if(self.role == false){
                        self.contents.id = response.data.user.id;
                        self.contents.name = response.data.user.name;
                        self.contents.address = response.data.user.address;
                        self.contents.phone = response.data.user.phone;
                    }
                }).catch(function(error){
                    console.log("失敗しました");
                });
            },
            searchUsers: function() {
                this.users = [];
                var self = this;
                axios.post('/api/users', this.param).then(function(response){
                    response.data.users.forEach(element => {
                        self.users.push({id:element.id, name:element.name, address:element.address, phone:element.phone});
                    });
                }).catch(function(error){
                    console.log("失敗しました");
                });
            },
            selectUser: function(user) {
                this.contents.id = user.id;
                this.contents.name = user.name;
                this.contents.address = user.address;
                this.contents.phone = user.phone;
                this.closeModal();
            },
            regist: function() {
                var self = this;
                this.param.contents = this.contents;
                axios.post('/api/add', this.param).then(function(response){
                    document.location = "/management";
                }).catch(function(error){
                    self.error_flg = true;
                    self.error_message = error.response.data.errors;
                    console.log("失敗しました");
                });
            },
            getRooms: function() {
                var self = this;
                axios.post('/api/rooms').then(function(response){
                    response.data.roomLists.forEach(element => {
                        self.rooms.push({id:element.id, name:element.name});
                    });
                }).catch(function(error){
                    console.log("失敗しました");
                });
            },
            getTimeList: function(){
                var self = this;
                axios.post('/api/timelist').then(function(response){
                    for (let [key, value] of Object.entries(response.data.timelist)){
                        self.timeList.push({key: key, value: value});
                    }
                }).catch(function(error){
                    console.log("失敗しました");
                });
            },
            openModal: function(){
                this.users = [];
                this.showContent = true;
            },
            closeModal: function(){
                this.showContent = false;
                this.edit_flg = false;
            },
        }
    }
</script>

ポイントは、ユーザーログインも管理者ログインも使用するということ。

なので、現在ログインしているアカウントのロールをgetRole()で最初に取得している、ということです。

このgetRole()の結果で表示内容を切り替えたりしてます。

そして、必要事項を入力したら、登録処理を行います。

このとき必要になるのは、ユーザーID。これも送信するパラメータに含めます。

では、API側の処理。

    public function __construct()
    {
        $this->middleware('auth');
        $this->registerManagement = new RegisterManagementRepository();
        $this->room = new RoomRepository();
        $this->user = new UserRepository();
    }
    public function role(Request $request)
    {
        return response()->json(['role' => Gate::Allows('manager'),
                                 'user' => Auth::user()]);
    }

    public function users(Request $request)
    {
        return response()->json(['users' => $this->user->search($request->search)]);
    }

    public function add(Request $request)
    {
        \Log::debug(print_r($request->contents, true));
        if($this->registerManagement->checkSchedule($request->contents["start_day"], 
                                                    $request->contents["days"], 
                                                    $request->contents["roomid"]) == false)
        {
            return response()->json([
                'errors' => "スケジュールが重複しています"
            ], 400);
        }
        $param = $this->registerManagement->getParam();
        $this->registerManagement->add([
            $param[0] => $request->contents["num"],
            $param[1] => $request->contents["days"],
            $param[2] => $request->contents["start_day"],
            $param[3] => false,
            $param[4] => date('Y-m-d H:i', strtotime($request->contents["start_day"].' + '.$request->contents["days"].' day') + $request->contents["checkout"])
        ], $request->contents["roomid"], $this->user->getUserById($request->contents["id"]));
        return response()->json();
    }
class UserRepository
{
    public function __construct()
    {

    }

    public function getUserById($id)
    {
        return User::where("id", $id)->first();
    }

    public function search($word)
    {
        $select = ['id', 'name', 'address', 'phone'];
        return User::select($select)
                    ->where('name', 'like', "%{$word}%")
                    ->get();
    }
}

ユーザー検索で使用する「あいまい検索」はこんな感じで「like」を使用します。

管理者ログイン時の動作

ユーザーログイン時の動作

これでうまく行ったみたいです。(疲れた。。。)

【ぼっち】富士山

富士山と書いて、「ふじやま」と読みます。

https://taishu-izakaya-fujiyama.owst.jp

大通りの近くに、お昼から飲める居酒屋がオープンしているんですね。

飲み物は1280円で2時間、ビール付きは+300円です。

お酒の値段は高いですが、何よりもお食事の値段が安い。

このメニューの他にも黒板メニューがあります。

オニオンサラダ。鰹節の下に玉ねぎ+ドレッシングがあります。

サバ文化干し。

サバの味噌煮。

この日はとにかく魚が食べたかった。

これだけ飲み食いしてて、お会計は3000円程度でした。

かなりお手頃な価格設定ですよ。

ガーデンズキャビンからも近いので、ガーデンズキャビンのお風呂に行った後、ここでお風呂上がりの一杯、という使い方もできます。

なってったって、お昼から開いてますからね!

【ぼっち】ガーデンズキャビン

居酒屋ではないのですが、札幌市内のど真ん中に手ぶらでは入れるお風呂があったら良いと思いません?

あるのですよ。

ガーデンズキャビンというホテルの地下にお風呂があります。

できたばかりのホテルで、1階にはセブンイレブンもオープンする予定です。

建物に入ってエレベータに乗ると、自動的に二階のフロントに動くようになっています。

フロントで受付を済ませると、入浴場(地下一階)に行くためのカードとタオルを貸してくれます。1回1000円です。

それを持って、エレベーターに乗って、カードを読取り部にかざすと、地下一階へ行けるようになります。

お風呂は小さめですが、脱衣所も綺麗で、サウナもあります。

確かにお風呂に行くだけ1000円なら高いかもしれません。

でもタオルも貸し出ししてくれるとなったらどうでしょう?

しかも、大通の4プラの隣ですから、札幌市内のど真ん中にあるのです。

アクセスも便利で手ぶらでお風呂には入れて、その後はすすきのにも行ける。

いいじゃないですか。

じゃらんから予約するとPontaポイントがもらえますよ!

アルコール対策ドリンクを試す。

最近、年のせいか、

アルコールに弱くなった気がする。

具体的には、

昼から飲み始めると、なかなか酔いが醒めず、夜になると気持ち悪くなる。

夜遅くなるまで飲んでいると、次の日の朝が辛い。

調べてみると、やはり加齢によって肝臓の働きが弱くなるみたいで。

ならば、肝臓の働きをアシストする物を摂取すればいいのでは、と思いました。

カンゾー!

飲み会を科学するドリンクを試して、昼飲みをやってみました。

特に変化なし!

午前10時に飲み始めて午後2時まで飲んでたけど、夜6時になっても酔いが醒めない。

出来ることなら、飲んで、酔っ払って、気分がいいまま眠りにつきたい。

もう、アレだ。

昼飲み止めて、夜に飲もう。

因みに、

こっちの方を試してます。

【鬱病】また体調が悪くなってしまいました。

鬱になると体調管理が難しい。

お正月の三が日、年末に買ったビール1箱飲みきってから禁酒生活していましたが、先週水曜日から体調が悪化。

体のだるさは戻ったものの、耳鳴りが止まず辛い生活をしています。

思ったより体重落ちないし。

運動してなかったというのも影響しているかもしれないけど。

とりあえず、禁酒生活7日後にお酒解禁して、落ち込み気味の気分をアルコールの力で相殺していました。

あまりやっちゃいけないことなのかもしれないけど。

仕事復帰のお声もかけてもらってもいるのですが、

今の状態じゃ仕事復帰は難しいかも。

ゴメンナサイしようかな。

明日の朝、耳鳴りが治ってなかったら、ゴメンナサイします。

こんな感じで急に体調悪化するから鬱病は怖い。

体調維持出来るルーティンを見つけなければ。

加齢も加わっているからほんと、体調管理って難しいのよ。

まあ、今日はサウナからの居酒屋ビールで気分をリフレッシュします。

【C#】【数独】マス目のデータをどう持つか、を考える。

前回の状況はこちら。

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

https://github.com/takishita2nd/sudoku

前回はファイルからデータを取り出して、int型の二次元配列に取り込む、ということをしましたが、このままでは数独の解析は難しいでしょう。

なので、マス目一つ一つをオブジェクトとして、様々なデータを持つようにしたいと思います。

とりあえず、今考えているのは、

  • 確定した値
  • 確定したかどうか
  • 候補となる数字
  • etc…

とりあえず、これを実装してみたいと思います。

    class Square
    {
        class Candidate
        {
            public bool value1;
            public bool value2;
            public bool value3;
            public bool value4;
            public bool value5;
            public bool value6;
            public bool value7;
            public bool value8;
            public bool value9;

            public Candidate()
            {
                this.value1 = false;
                this.value2 = false;
                this.value3 = false;
                this.value4 = false;
                this.value5 = false;
                this.value6 = false;
                this.value7 = false;
                this.value8 = false;
                this.value9 = false;
            }
        }

        // 確定した数字
        private int _value;
        // 確定したかどうか
        private bool _confirmed;
        // 候補の数字
        private Candidate _candidate;

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

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

        public int GetValue()
        {
            return this._value;
        }

        public void SetValue(int val)
        {
            this._value = val;
            this._confirmed = true;
        }

        public bool isConfirmed()
        {
            return this._confirmed;
        }
    }

まずは、こんな感じでマス目のクラスSquareを定義しました。

これで完全とは思っていません。

今後も必要に応じて追加していきます。

これに、ファイルから取得したデータを設定します。

    static class FileAccess
    {
        /**
         * ファイルからデータを取得する
         */
        public static Square[,] OpenFile(string filePath)
        {
            int[,] matrix = new int[9, 9];

            // ファイルを開く
            bool error = false;
            using (var stream = new StreamReader(filePath))
            {
                int row = 0;
                while (stream.EndOfStream == false)
                {
                    string lineText = stream.ReadLine();
                    var val = lineText.Split(',');
                    int col = 0;
                    foreach (var v in val)
                    {
                        int i;
                        if (int.TryParse(v, out i))
                        {
                            matrix[row, col] = i;
                        }
                        else
                        {
                            error = true;
                        }
                        col++;
                    }
                    row++;
                    if (row > 9)
                    {
                        error = true;
                    }
                }
            }
            if (error)
            {
                Console.WriteLine("Illegal format.");
                return null;
            }

            Square[,] ret = new Square[9, 9]; 
            for (int row = 0; row < 9; row++ )
            {
                for(int col = 0; col < 9; col++ )
                {
                    Square sq = new Square(matrix[row, col]);
                    ret[row, col] = sq;
                }
            }

            return ret;
        }

        // debug
        public static void Output(Square[,] sq)
        {
            using (var stream = new StreamWriter(System.Environment.CurrentDirectory + "\\output"))
            {
                for (int row = 0; row < 9; row++)
                {
                    for (int col = 0; col < 9; col++)
                    {
                        stream.Write(sq[row, col].GetValue());
                    }
                    stream.Write("\r\n");
                }
            }
        }
    }

前回のファイルリード、ライト処理をクラス化しました。やっていることに大きな変更はありません。

これで、Main関数もスッキリするはずです。

    class Program
    {
        static void Main(string[] args)
        {
            // パラメータチェック
            if (args.Length != 1)
            {
                Console.WriteLine("usage : sudoku.exe [input file]");
                return;
            }

            // ファイルの存在を確認
            string filePath = Environment.CurrentDirectory + "\\" + args[0];
            if (File.Exists(filePath) == false)
            {
                Console.WriteLine("File not found.");
                return;
            }

            var sq = FileAccess.OpenFile(filePath);
            if(sq == null)
            {
                return;
            }

            // debug
            FileAccess.Output(sq);
        }
    }

前回と同じ結果を取得することができました。

取り込みが美味く機能していることが言えます。

とりあえず、今日はここまで。

実際にロジックを考えてみます。

【Laravel】【ホテル予約管理】予約情報を変更、削除する

前回までの状況はこちら

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

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

今回は、予約の編集処理と削除処理を修正します。

まず、UIですが、氏名、住所、電話番号はユーザー登録情報を使用するため、編集画面では、編集不可にします。

                    <tbody>
                        <tr>
                            <th>名前</th>
                            <td>{{ contents.name }}</td>
                        </tr>
                        <tr>
                            <th>住所</th>
                            <td>{{ contents.address }}</td>
                        </tr>
                        <tr>
                            <th>電話番号</th>
                            <td>{{ contents.phone }}</td>
                        </tr>

編集処理では、氏名、住所、電話番号のカラムはテーブルから削除しましたので、パラメータに含めないように修正します。

ログイン中のユーザー情報はAuth::user()を使用します。

予約情報の変更のみなので、ユーザーと予約情報の紐付けは変える必要ありません。

    public function update(Request $request)
    {
        \Log::debug(print_r($request->contents, true));
        if($this->registerManagement->checkScheduleForUpdate($request->contents["start_day"], 
                                                            $request->contents["days"], 
                                                            $request->contents["id"], 
                                                            $request->contents["roomid"]) == false)
        {
            \Log::debug("スケジュールが重複しています");
            return response()->json([
                'errors' => "スケジュールが重複しています"
            ], 400);
        }
        $param = $this->registerManagement->getParam();
        $this->registerManagement->updateById($request->contents["id"],
        [
            $param[0] => $request->contents["num"],
            $param[1] => $request->contents["days"],
            $param[2] => $request->contents["start_day"],
            $param[3] => false,
            $param[4] => date('Y-m-d H:i', strtotime($request->contents["start_day"].' + '.$request->contents["days"].' day') + $request->contents["checkout"])
        ], $request->contents["roomid"]);
        return response()->json(['registerLists' => $this->registerManagement->getListByMonth(
            $request->year,
            $request->month,
            $request->room,
            Auth::id()
        )]);
    }

削除処理は、予約情報の削除と同時に予約情報との紐付けを解除する必要があります。

    public function delete(Request $request)
    {
        $this->registerManagement->deleteById($request->id, Auth::user());
        return response()->json(['registerLists' => $this->registerManagement->getListByMonth(
            $request->year,
            $request->month,
            $request->room,
            Auth::user()
        )]);
    }
    public function deleteById($id, $user)
    {
        $model = $this->getItemById($id);
        $this->detachToUser($model, $user);
        $this->detachToRoom($model, $model->rooms()->first()->id);
        $this->detachToSchedule($model);
        $model->delete();
    }

これでユーザーログインでの修正は完了しました。

次は、管理者ログインでの処理を修正します。