【LARAVEL】【ダイエット支援】グラフ表示用のデータを取得するその2

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

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

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

前回はAPI側を作成したので、今回はフロント側を作成します。

使用したライブラリは、chart.jsです。

なんか、Vue.js用に拡張されたvue-chart.jsというものもあるみたいなのですが、うまく動かなかったので、chart.jsにしました。

原因はわからん。

npm install chart.js --save

でインストール。

resouces/assets/app.jsに以下を書き込みます。

require('chart.js');

これでどこでもchart.jsが使えます。

<template>
    <div>
        <div class="dashboard">
            <div class="chart">
                <canvas id="weight"></canvas>
            </div>
            <div class="command">
                <ul>
                    <li><a @click="onClickInput">クイック入力</a></li>
                    <li><a href="/weight">詳細</a></li>
                </ul>
            </div>
        </div>
        <weight-input-dialog-component :show="showInputDialogContent" @update="invokeUpdateList"></weight-input-dialog-component>
    </div>
</template>

<script>
export default {
    data() {
        return {
            showInputDialogContent: false,
            datetimeList: [],
            weightList: [],
            fat_rateList: [],
            bmiList: [],
        };
    },
    created: function() {
    },
    mounted: function() {
        this.graphUpdate();
    },
    methods: {
        onClickInput: function() {
            this.showInputDialogContent = true;
        },
        invokeUpdateList: function() {
            this.graphUpdate();
        },
        graphUpdate: function() {
            this.datetimeList = [];
            this.weightList = [];
            this.fat_rateList = [];
            this.bmiList = [];
            var ctx = document.getElementById("weight");
            var self = this;
            axios.post('api/weight/graph').then(function(response){
                response.data.datas.forEach(element => {
                    self.datetimeList.push(element.datetime);
                    self.weightList.push(element.weight);
                    self.fat_rateList.push(element.fat_rate);
                    self.bmiList.push(element.bmi);
                });
                var myChart = new Chart(ctx, {
                    type: 'line',
                    data: {
                        labels: self.datetimeList,
                        datasets: [
                            {
                                yAxisID: 'weight',
                                label: '体重(kg)',
                                data: self.weightList,
                                borderColor: "rgba(255,0,0,1)",
                                backgroundColor: "rgba(0,0,0,0)"
                            },
                            {
                                yAxisID: 'fat_rate',
                                label: '体脂肪率(%)',
                                data: self.fat_rateList,
                                borderColor: "rgba(0,255,0,1)",
                                backgroundColor: "rgba(0,0,0,0)"
                            },
                            {
                                yAxisID: 'bmi',
                                label: 'BMI',
                                data: self.bmiList,
                                borderColor: "rgba(0,0,255,1)",
                                backgroundColor: "rgba(0,0,0,0)"
                            },
                        ]
                    },
                    options: {
                        title: {
                            display: true,
                            text: '最近の記録',
                        },
                        elements: {
                            line: {
                                tension: 0,
                            }
                        },
                        scales: {
                            yAxes: [
                                {
                                    id: 'weight',
                                    type: 'linear',
                                    position: 'left',
                                    ticks: {
                                        suggestedMax: 100,
                                        suggestedMin: 0,
                                        stepsize: 10,
                                        callback: function(value, index, values){
                                            return value + 'kg';
                                        }
                                    }
                                },
                                {
                                    id: 'fat_rate',
                                    type: 'linear',
                                    position: 'right',
                                    ticks: {
                                        suggestedMax: 100,
                                        suggestedMin: 0,
                                        stepsize: 10,
                                        callback: function(value, index, values){
                                            return value + '%';
                                        }
                                    }
                                },
                                {
                                    id: 'bmi',
                                    type: 'linear',
                                    position: 'left',
                                    ticks: {
                                        suggestedMax: 100,
                                        suggestedMin: 0,
                                        stepsize: 10,
                                        callback: function(value, index, values){
                                            return value;
                                        }
                                    }
                                },
                            ]
                        }
                    }
                });
            }).catch(function(error){
            });
        }
    }
}
</script>

var ctx = document.getElementById(“weight”);でcanvasの要素を取得し、var myChart = new Chart(ctx, {…})で{…}の部分にデータを入れることで、canvasにグラフが描画されます。

axiosのpostメソッドを使用して、前回作成したAPIを呼び出し、表示するデータを項目ごとにリスト化してchart.jsに渡します。

動作結果はこんな感じ。

思ったよりいい感じです。

【LARAVEL】【ダイエット支援】グラフ表示用のデータを取得する

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

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

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

これからダッシュボードに表示するグラフを作成するんですが、それに使用するデータの取得を行います。

今回グラフに表示するのは、最近10日間のデータのみ、という想定をしています。

    public function getGraphData($user)
    {
        $datetimes = [];
        for($i = 0; $i < 10 ; $i++) {
            $datetimes[] = date('Y-m-d', strtotime('today - '.$i.' day'));
        }

        return $user->WeightManagements()
                    ->whereIn(DB::raw('date_format(datetime, "%Y-%m-%d")'), $datetimes)
                    ->get();
    }

今回のポイントは特定ユーザに関連するデータのみを対象にする場合、

$user->WeightManagements()->whereIn()

という感じで、リレーションからのSQLビルダ作成、というやり方ができるらしい。

前回のホテル予約管理ではjoinやらwhereやら使いまくっててコードがごちゃごちゃしていたけど、その必要はなかった。

ただし、ここからgroupbyやら統計関連の関数を使用するとうまく行かない。

どうやら、laravelさんがget()の出力内容にuser_idなどの情報を含めているためにグループ化ができないため、SQL実行エラーとなるようです。

なので、一日の最新を取り出す、ということになると、このやり方ではSQLビルダは使用できなくって、PHP側で処理することになります。

今回はめんどくさいので、最新10日のデータ全部、としました。

きちんとtinkerで動作確認したよ。

    /**
     * グラフ用データを取得する
     */
    public function graph(Request $request)
    {
        return response()->json(['datas' => $this->weightManagement->getGraphData(Auth::user())]);
    }
Route::post('api/weight/graph', 'Weight\ApiController@graph');
>>> $rep->getGraphData($user)
=> Illuminate\Database\Eloquent\Collection {#3849
     all: [
       App\Model\WeightManagement {#3843
         id: 1,
         datetime: "2020-05-28 02:14:00",
         weight: "80.00",
         fat_rate: "17.00",
         bmi: "27.00",
         created_at: "2020-05-28 02:14:50",
         updated_at: "2020-05-28 02:14:50",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3840
           user_id: 1,
           weight_management_id: 1,
         },
       },
       App\Model\WeightManagement {#3844
         id: 2,
         datetime: "2020-05-28 02:15:00",
         weight: "80.00",
         fat_rate: "17.00",
         bmi: "27.00",
         created_at: "2020-05-28 02:15:10",
         updated_at: "2020-05-28 02:15:10",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3841
           user_id: 1,
           weight_management_id: 2,
         },
       },
       App\Model\WeightManagement {#3845
         id: 5,
         datetime: "2020-05-28 02:34:00",
         weight: "80.00",
         fat_rate: "17.00",
         bmi: "28.00",
         created_at: "2020-05-28 02:34:49",
         updated_at: "2020-06-01 01:20:56",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3779
           user_id: 1,
           weight_management_id: 5,
         },
       },
       App\Model\WeightManagement {#3846
         id: 9,
         datetime: "2020-05-31 02:44:00",
         weight: "87.00",
         fat_rate: "17.00",
         bmi: "17.00",
         created_at: "2020-05-31 02:44:36",
         updated_at: "2020-05-31 02:44:36",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3834
           user_id: 1,
           weight_management_id: 9,
         },
       },
       App\Model\WeightManagement {#3847
         id: 10,
         datetime: "2020-06-02 02:03:00",
         weight: "87.80",
         fat_rate: "15.90",
         bmi: "27.00",
         created_at: "2020-06-02 02:03:29",
         updated_at: "2020-06-02 02:03:29",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3848
           user_id: 1,
           weight_management_id: 10,
         },
       },
     ],
   }

【北海道大戦】マップデータを作成

そもそも、北海道大戦って何?

北海道の全市町村179ありますが、それらが全道統一を目指してバトルしたらどうだろう?って思い付きで考えたゲームです。

とりあえず、Excelで北海道マップを作成しました。

Excel方眼紙はこうやって使う。

でも、このままではデータとして使用できないので、番号に置き換えます。

ちゃんと179市町村ありました。

右に市町村の一覧があり、それらに番号が振られており、マップ上の市町村に番号を設置しました。

これをさらにExcelマクロで加工します。

イメージとしては、Json形式となるようにマップを検索し、X座標とY座標をまとめます。

Sub output()
    Dim TownArea As Object
    Dim Rows As Integer
    Set TownArea = Worksheets("Sheet1").Range("AU1", Range("AU1").End(xlDown).End(xlToRight))
    Rows = TownArea.Rows.Count
    
    Dim Area As Object
    Dim RightLength As Integer
    Dim DownLength As Integer
    Set Area = Worksheets("Sheet1").Range("B2:AS36")
    RightLength = Area.Columns.Count
    DownLength = Area.Rows.Count
    
    Dim WS2 As Object
    Set WS2 = Worksheets("Sheet2")
    Dim WriteLine As Integer
    WriteLine = 1
    WS2.Cells(WriteLine, 1).Value = "{""list"":["
    WriteLine = WriteLine + 1
    
    For R = 1 To Rows
        Dim number As Integer
        Dim name As String
        number = TownArea.Cells(R, 1).Value
        name = TownArea.Cells(R, 2).Value
        
        WS2.Cells(WriteLine, 2).Value = "{""name"" :"""
        WS2.Cells(WriteLine, 3).Value = name
        WS2.Cells(WriteLine, 4).Value = """, ""point"" :["
        
        For RL = 1 To RightLength
            For DL = 1 To DownLength
                If Area.Cells(RL, DL).Value = number Then
                    WS2.Cells(WriteLine, 5).Value = "{""x"" :"
                    WS2.Cells(WriteLine, 6).Value = RL - 1
                    WS2.Cells(WriteLine, 7).Value = ", ""y"" :"
                    WS2.Cells(WriteLine, 8).Value = DL - 1
                    WS2.Cells(WriteLine, 9).Value = "}"
                    WS2.Cells(WriteLine, 10).Value = ","
                    WriteLine = WriteLine + 1
                End If
            Next
        Next
        WS2.Cells(WriteLine - 1, 10).Value = "]},"
    Next
    WS2.Cells(WriteLine - 1, 10).Value = "]}"
    WS2.Cells(WriteLine, 1).Value = "]}"
End Sub

これをテキストにコピーして、セル間のタブを置換処理で削除すれば、Jsonとして完成します。

整形したらこんな感じになりました。

これでようやくマップデータとして使用できそうです。

昨日は一日中ストレッチをしていました。

ストレッチの力は偉大。

特に肩と首の周りの治療を行っているので、その辺りを積極的に動かしたり、筋肉を伸ばしたりしていました。

まぁ、夏日であったと言うのもあったけど、これだけで結構汗が出てきまして、

その甲斐もあってか、体重が86kgまでダウンしました。

そして、今日はお酒を飲むつもりは無い!

明日さらにダウンするかも。

最近はというと、パソコン作業がだいぶ伸びてきました。

メインでやっているのは、

  • ピクロス解析ツール(C#)
  • ダイエット支援ツール(PHP / Laravel)
  • ラズパイ

この3つ。

さらに、北海道大戦とかいうゲームを練っている最中です。

その影響でゲームをする時間が少なくなり、

プレイするゲームをいくつか削除しました。

今プレイしているのは、

  • マインクラフトダンジョンズ(PC)
  • アリスギアアイギス(PC)
  • 禍つヴァールハイト
  • きららファンタジア
  • プリンセスコネクト!Re:Dive
  • ドールズフロントライン
  • De:Lithe
  • この素晴らしい世界に祝福を!ファンタスティックデイズ
  • エクゾスヒーローズ
  • ドラクエ6
  • バンドリ!ガールズバンドパーティ!!(iPad)
  • HeyDay(iPad)
  • クラッシュロワイヤル(iPad)

それでも容量ギリギリです。

64GBじゃ足りません。

ってか、リストアップしてみたらまだまだ多すぎやん。

でも、バックグラウンドで動かしたり、自動で周回できる物が多いので、そんなに負担にはならない物が多いです。

あとは、ジョギングを始めました。

夕方に4キロぐらい走ってます。

しかし、ジャージのズボンに穴が空いているのに気がついて

ちょうとおしりのところ。

また買い足ししなくちゃいけないなぁと思っています。

給付金振り込みはよ。

もう郵送から1週間ぐらい経ったけどなぁ。

【ラズパイ】【GLCD】ASCII文字列を表示する

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

今回は複数の文字を表示させます。

これもサンプルコードをPython用に書き換えました。

def GLCDPuts(Xp, Yp, text):
    x = Xp
    for s in text:
        GLCDPutc(x, Yp, s)
        x += 6

やってることはそんなに難しくはありませんでした。

文字と文字の間隔は1ドット空けています。

def __main():
    PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCDInit()
    GLCDDisplayClear()
    GLCDPuts(40, 10, "ABCDE")

    try:
        while True:
            time.sleep(1.0)
    except KeyboardInterrupt:
        GPIO.cleanup()

【バンドリ】【ガルパ】6/3のハロハピ放送局で公開された情報まとめ

花火、きれいでしたねー

さて、いよいよRASの実装が近づいてきましたよ~

新カバー楽曲

ノスタルジックレインフォール

テレビアニメ「恋は雨上がりのように」のOPテーマです。

予想レベル24

新バンドRAISE A SUILEN

ほぼほぼバンドリ3rdシーズンの内容ですね。

EXPOSE ‘Burn Out!!!’がイベント開始と同時に実装されます。

予想レベル26

同時にカバー曲「ヒトリノ夜」が実装されます。

アニメ「GTO」のOPテーマでした。

カバーコレクションに収録されている曲ですね。

予想レベル25

イベント後編にはバンドリ3rdシーズンの13話で披露されたBeautiful Birthdayが実装されます。

まとめ。

イベントは6月10日開始です。

次のイベントですね。

星配布と無料ガチャは嬉しい。

イベントで勝ち抜くにはメンツが必要。

ガチ課金勢には敵わないけどな。

【ラズパイ】【GLCD】ASCII文字を表示する

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

PythonコードをgitHubにアップしました。

https://github.com/takishita2nd/GLCD

サンプルソースにフォントのビットパターンデータがありましたので、これを置換処理を使ってPython用に書き換えました。

https://github.com/takishita2nd/GLCD/blob/master/Font.py

これを使用して、ディスプレイにアスキー文字を表示させます。

    [ 0x7e, 0x11, 0x11, 0x11, 0x7e ], # A   0x41

1文字8×5のサイズになっているようです。

お試しで表示させてみました。

chara = [0x7e, 0x11, 0x11, 0x11, 0x7e]

def __main():
    PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCDInit()
    GLCDDisplayClear()
    addr = 0
    SelectIC(1)
    SetPage(0)
    for c in chara:
        SetAddress(addr)
        WriteData(c)
        addr += 1

    try:
        while True:
            time.sleep(1.0)
    except KeyboardInterrupt:
        GPIO.cleanup()

このデータを表示するサンプルコードをPython用に書き換えました。

def GLCDPutc(Xp, Yp, c):
    code = ord(c)
    #ページ内のラインを選択
    L = Yp % 8
    #8×5のキャラクター文字を描画する
    for i in range(5):
        SetLocation(Xp + i, Yp)
        f = Font.Array[code - 0x20][i] << L
        WriteData(f)
        if (L != 0) & (SetPg < 7):
            SetPage(SetPg + 1)
            SetAddress(SetCol)
            f = Font.Array[code - 0x20][i] >> (8 - L)
            WriteData(f)
def SetLocation(Xp, Yp):
    global SetPg
    global SetCol
    cs = 0
    #チップの選択とカラムのアドレスの処理を行う
    if Xp < 64:
        #左側(IC1)を選択
        cs = 1
        SetCol = Xp
    else:
        #右側(IC2)を選択
        cs = 2
        SetCol = Xp - 64
    #ページとラインの選択
    SetPg = Yp // 8
    #LCDに描画するアドレスの位置を設定
    SelectIC(cs)
    SetPage(SetPg)
    SetAddress(SetCol)

好きな場所に文字を書くことができます。

ページ跨ぎとか、チップ跨ぎにも対応しているようです。

def __main():
    PinsInit(20, 7, 8, 9, 18, 19, 10, 11, 12, 13, 14, 15, 16, 17)
    GLCDInit()
    GLCDDisplayClear()
    GLCDPutc(20, 5, "B")

    try:
        while True:
            time.sleep(1.0)
    except KeyboardInterrupt:
        GPIO.cleanup()

【LARAVEL】【ダイエット支援】データ一覧画面からデータ削除

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

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

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

データ削除処理を作成します。

とはいっても、もう追加、編集処理が出来上がっているので、そんなに難しくありませんでした。

ぱぱっとやってしまいます。

    public function delete($id, $user)
    {
        $model = $this->getItemById($id);
        $this->detachToUser($model, $user);
        $model->delete();
    }
    /**
     * データを1件削除する
     */
    public function delete(Request $request)
    {
        $this->weightManagement->delete($request->contents["id"], Auth::user());
        
        return response()->json();
    }
Route::post('api/weight/delete', 'Weight\ApiController@delete');
<template>
    <div>
        <div id="overlay" v-show="show">
            <div id="content">
                <p v-if="error_flg == true" class="error">
                    <ui>
                        <li v-for="error in errors">{{ error }}</li>
                    </ui>
                </p>
                <table class="edit">
                    <tbody>
                        <tr>
                            <td>日時</td>
                            <td>{{contents.date}}</td>
                        </tr>
                        <tr>
                            <td>体重</td>
                            <td>{{contents.weight}}</td>
                        </tr>
                        <tr>
                            <td>体脂肪</td>
                            <td>{{contents.fat_rate}}</td>
                        </tr>
                        <tr>
                            <td>BMI</td>
                            <td>{{contents.bmi}}</td>
                        </tr>
                    </tbody>
                </table>
                <p id="command">
                    <button @click="clickDelete">OK</button>
                    <button @click="closeModal">キャンセル</button>
                </p>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    props: ['show'],
    data() {
        return {
            errors: [],
            error_flg: [],
            param: {},
            contents: {
                date: "",
                weight: "",
                fat_rate: "",
                bmi: "",
            },
        };
    },
    created: function() {
    },
    methods: {
        dataSet: function(data) {
            this.contents = data;
        },
        clickDelete: function() {
            var self = this;
            this.param.contents = this.contents;
            axios.post('api/weight/delete', this.param).then(function(response){
                self.closeModal();
                self.$emit('update');
            }).catch(function(error){
                self.error_flg = true;
                self.errors = error.response.data.errors;
            });
        },
        closeModal: function() {
            this.$parent.showDeleteDialogContent = false;
        },
    }
}
</script>
            <weight-delete-dialog-component ref="deleteDialog" :show="showDeleteDialogContent" @update="invokeUpdateList"></weight-delete-dialog-component>
        onClickDelete: function(id) {
            var editData = {};
            this.datalists.forEach(element => {
                if(element.id == id){
                    editData.id = id;
                    editData.date = element.date;
                    editData.weight = element.weight;
                    editData.fat_rate = element.fat_rate;
                    editData.bmi = element.bmi;
                    return true;
                }
            });
            this.$refs.deleteDialog.dataSet(editData);
            this.showDeleteDialogContent = true;
        },

いいかんじです。

【C#】【ピクロス】【ALTSEED】データ入力UIの改善

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

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

https://github.com/takishita2nd/Picross

いままではデータ入力値がパレットの陰に隠れて見えづらい、という問題をうすうすと感じていましたが、これを修正したいと思います。

具体的には、パレットの上に入力値を表示し、ENTERボタンを押下することで入力データを反映させます。

なので、パレットを拡張。

そして、パレット周りの処理をがっつり書き換えました。

    class Palette
    {
        public void OnClick(asd.Vector2DF pos)
        {
            if (paletteZeroSquareObject.IsClick(pos))
            {
                if(_valueText.Text != "" && _valueText.Text != "0")
                {
                    if (_valueText.Text.Length < 2)
                    {
                        _valueText.Text += "0";
                    }
                }
            }
            else if (paletteBSSquareObject.IsClick(pos))
            {
                if(_valueText.Text.Length > 0)
                {
                    _valueText.Text = _valueText.Text.Remove(_valueText.Text.Length - 1);
                }
            }
            else if (paletteCRSquareObject.IsClick(pos))
            {
                _valueText.Text = "";
            }
            else if (paletteENSquareObject.IsClick(pos))
            {
                value = _valueText.Text;
                _isClickEnter = true;
            }
            else
            {
                for (int row = 0; row < 3; row++)
                {
                    for (int col = 0; col < 3; col++)
                    {
                        if (paletteSquareObjects[row, col].IsClick(pos) == true)
                        {
                            if(_valueText.Text.Length < 2)
                            {
                                if(_valueText.Text == "0")
                                {
                                    _valueText.Text = paletteSquareObjects[row, col].GetValue();
                                }
                                else
                                {
                                    _valueText.Text += paletteSquareObjects[row, col].GetValue();
                                }
                            }
                        }
                    }
                }
            }
        }

        public bool IsClickEnter()
        {
            return _isClickEnter;
        }

        public string GetValue()
        {
            return value;
        }

パレットを使用する側もがっつり書き換えます。

                            if (palette.IsClick(pos))
                            {
                                string value = string.Empty;
                                palette.OnClick(pos);
                                if(palette.IsClickEnter())
                                {
                                    palette.Hide();
                                    if (selectedNumberSquare != null)
                                    {
                                        selectedNumberSquare.SetValue(palette.GetValue());
                                        if (selectedNumberSquare.GetStringValue() != string.Empty)
                                        {
                                            if (selectedRowIndex >= 0)
                                            {
                                                if (Math.Abs(selectedColIndex - 1) > rowNumberSquare[selectedRowIndex].Count)
                                                {
                                                    var square = new NumberSquare(selectedRowIndex, selectedColIndex - 1);
                                                    asd.Engine.AddObject2D(square.getBackTexture());
                                                    asd.Engine.AddObject2D(square.getTextObject());
                                                    rowNumberSquare[selectedRowIndex].Add(square);
                                                }
                                            }
                                            else if (selectedColIndex >= 0)
                                            {
                                                if (Math.Abs(selectedRowIndex - 1) > colNumberSquare[selectedColIndex].Count)
                                                {
                                                    var square = new NumberSquare(selectedRowIndex - 1, selectedColIndex);
                                                    asd.Engine.AddObject2D(square.getBackTexture());
                                                    asd.Engine.AddObject2D(square.getTextObject());
                                                    colNumberSquare[selectedColIndex].Add(square);
                                                }
                                            }
                                        }
                                        else
                                        {
                                            if (selectedRowIndex >= 0)
                                            {
                                                if (Math.Abs(selectedColIndex - 1) <= rowNumberSquare[selectedRowIndex].Count)
                                                {
                                                    asd.Engine.RemoveObject2D(rowNumberSquare[selectedRowIndex][Math.Abs(selectedColIndex + 1)].getBackTexture());
                                                    asd.Engine.RemoveObject2D(rowNumberSquare[selectedRowIndex][Math.Abs(selectedColIndex + 1)].getTextObject());
                                                    rowNumberSquare[selectedRowIndex].RemoveAt(Math.Abs(selectedColIndex + 1));
                                                    for (int col = selectedColIndex + 1; Math.Abs(col) < rowNumberSquare[selectedRowIndex].Count; col--)
                                                    {
                                                        rowNumberSquare[selectedRowIndex][Math.Abs(col)].SetPosition(selectedRowIndex, col - 1);
                                                    }
                                                }
                                            }
                                            else if (selectedColIndex >= 0)
                                            {
                                                if (Math.Abs(selectedRowIndex - 1) <= colNumberSquare[selectedColIndex].Count)
                                                {
                                                    asd.Engine.RemoveObject2D(colNumberSquare[selectedColIndex][Math.Abs(selectedRowIndex + 1)].getBackTexture());
                                                    asd.Engine.RemoveObject2D(colNumberSquare[selectedColIndex][Math.Abs(selectedRowIndex + 1)].getTextObject());
                                                    colNumberSquare[selectedColIndex].RemoveAt(Math.Abs(selectedRowIndex + 1));
                                                    for (int row = selectedRowIndex + 1; Math.Abs(row) < colNumberSquare[selectedColIndex].Count; row--)
                                                    {
                                                        colNumberSquare[selectedColIndex][Math.Abs(row)].SetPosition(row - 1, selectedColIndex);
                                                    }
                                                }
                                            }
                                            selectedNumberSquare.SetValue("0");
                                        }
                                        selectedNumberSquare = null;
                                    }
                                }
                            }
                            else
                            {
                                palette.Hide();
                            }

とりあえず、UI周りはこれで十分かと思います。

じゃあ、ロジックに戻りましょうか。

自分、ぼっちですが何か?