量子的コネ取得
TRPGのお話でごんす。
システムは割と「どこでも」。
TRPGで、ある程度(以上)社会戦をやるキャラにおいて、或いはシステムにおいては「基本的に全員*1」とか。
「コネクション(知己、友人、つながり、縁故、その他)」の類いは割と必要で重要になります。
……が、一つ目には「そのシステムの世界観」と、それ以上に割とでかいのが「"マスターが認識している"そのシステムの世界観」によって、「どのコネを取るか?」ってのは、割と色々と虹色の回答が待ってます。
まぁある程度ベテランになったら「とりあえず安全かつ堅い所」とか「なんならGM相手にリアル社会戦(言いくるめ等)」なんて方法がないわけでもないのですが、そこまでいきつかない人に取っては色々とシビアで難儀な所になります。
で、おいちゃんがちょいちょいやっているのが「量子的コネ取得」。
この"量子的"は、量子将棋あたりを想起いただくとよろしいんじゃないか、と思われます。
方法。
例えば「コネが3つ取れる」ような背景やコストやポイントやCPや自由割振点なんかを支払ったとします。
キャラシには「コネ 3」とだけ書いておきます。
で、そのままセッション開始。
セッション中にコネが必要になった時に「貴方は今、コネを3つ取る事ができますが、その1つを使って**(例:警察)のコネを取得しますか?」と聞いて、もしYesなら「コネがある事にする」「そのPCのコネの1つは"警察"に固定される」という風に運用をします。
これ、全員にやってもいいし「初心者だけ」とか「上級者以外」とか、まぁその辺も割と柔軟に。
そうすると、「コネ」っていう特徴を比較的取りやすいのと、一方で「取ったのに使えなかった orz & 他のコネだったら大活躍したのに orz」っていう orz を減らす事ができます。
なんていう方法を、ちょいちょいやってまして。
ほら、いうじゃないですか「キャラメイクはフレンドリーに、セッションはデッドリーに」って*2。
多分わりと「システムあんまり選ばずに使える」小技なんで、明文化してみました。
Laravelのミューテタを調べてみた
ちょっと故がありまして、ミューテタについてちょっと気になる事があったので調べてみました。
Laravelのバージョンは8で検証してますが、多分まぁどのバージョンでもさほどの差異はなかろうかなぁ、と(新しく生えたメソッドを除く)。
ミューテタについては例えば https://readouble.com/laravel/8.x/ja/eloquent-mutators.html あたりをベースに。
機能は色々あるのですが、一端、get*Attribute() とset*Attribute() を見ています。
基本機能についての基本情報は公式サイトを参考にしていただきつつ。
多分一つ「この辺は想定しているんだろうなぁ」というのが、「既存のカラムを加工合成してデータを取得する」あたりなんじゃなかろうか、と。
マニュアルでも「ユーザーのフルネームの取得」という風に書かれていますが、この辺はまぁ割と「あったら便利」って思う人も多いんじゃなかろうかと思います。
マニュアルだとこんな感じですね。
/**
* ユーザーのフルネームの取得
*
* @return string
*/
public function getFullNameAttribute()
{
return "{$this->first_name} {$this->last_name}";
}これを書いておくと、マニュアルには書いてませんが、大体こんな感じで取得できます。
use App\Models\User; $user = User::find(1); $fullName = $user->full_name;
なんとなし便利だなぁ、というあたりなのですが。
ちょいと気になったのが「存在しないカラム」だけじゃなくて「存在するカラム」に対してもgetやsetを書く事ができます。
その辺で、いくつか実験してみたので、その辺を記録しておく、ってのがこの記事の目的です。
一端まず「姓と名、と後で使う文字列」用の、雑なテーブルを用意しました。
MariaDB [lara_test]> insert tests set first_name='aaa',last_name='bbb', val='val'; Query OK, 1 row affected (0.01 sec) MariaDB [lara_test]> select * from tests; +----+------------+-----------+-----+------------+------------+ | id | first_name | last_name | val | created_at | updated_at | +----+------------+-----------+-----+------------+------------+ | 1 | aaa | bbb | val | NULL | NULL | +----+------------+-----------+-----+------------+------------+ 1 row in set (0.00 sec)
とりあえずまず、上述の通り「存在しないカラム名を指定して合成した値の取得」を、ざっくりと書いてみます。
「どのコードがどこに書かれているか」などは適宜推測してください(コメントとかで突っ込みが多かったら綺麗に推敲しますw)。
//
Route::get('/test', [TestController::class, 'index']);resources/views/tests.blade.php
public function getNameAttribute()
{
echo "Trap getNameAttribute\n";
return "{$this->first_name} {$this->last_name}";
} public function index()
{
//
$data = TestModel::find(1);
var_dump($data->name);まぁこんな感じで、取得ができます。
さて、ここから。
public function getFirstNameAttribute()
{
echo "Trap getFirstNameAttribute\n";
return $this->first_name;
}これを書くとこんな風に言われます。
ErrorException: Undefined property: App\Models\Test::$first_name in file
これは、こんな風に書く必要があるようです。
public function getFirstNameAttribute()
{
echo "Trap getFirstNameAttribute\n";
return $this->attributes['first_name'];
//return $this->first_name;
}$attributesプロパティはマニュアルにも書いてあるので、基本的にミューテタ内では $attributes を使う、ってのがよろしい感じのようです。
public function getAll()
{
return $this->attributes ;
}なんてのをModelに生やすと外部から「生データを一通り」取れるので、今回のような実験の時には便利か、と。
さて。
いやまぁgetも多少気になる事がないわけではないのですが、setのほうでより、ちょっと気になる事があって。
まずはこんなものを用意します。
public function setValAttribute($v)
{
$this->attributes['val'] = strtoupper($v);
}これを書くと「valの値は全部大文字になる(事を期待している)」と思われるんですが、さてはて。
Modelにレコードを入れる時は、save()、create()、insert(単体)、insert(バルク)、Laravel8あたりからはupsert()なんてのがございます。
っつわけで、早速。
//
TestModel::create([
'first_name' => 'create',
'last_name' => 'create',
'val' => 'aBcDe',
]);
//
$o = new TestModel();
$o->fill([
'first_name' => 'save',
'last_name' => 'save',
'val' => 'aBcDe',
]);
$o->save();
//
TestModel::insert([
'first_name' => 'insert',
'last_name' => 'insert',
'val' => 'aBcDe',
]);
//
TestModel::insert([
[
'first_name' => 'bulk insert',
'last_name' => 'bulk insert',
'val' => 'aBcDe',
],
[
'first_name' => 'bulk insert2',
'last_name' => 'bulk insert2',
'val' => 'aBcDe',
],
]);
//
TestModel::upsert([
[
'first_name' => 'bulk upsert',
'last_name' => 'bulk upsert',
'val' => 'aBcDe',
],
[
'first_name' => 'bulk upsert2',
'last_name' => 'bulk upsert2',
'val' => 'aBcDe',
],
], ['id']);MariaDB [lara_test]> select * from tests; +----+--------------+--------------+-------+---------------------+---------------------+ | id | first_name | last_name | val | created_at | updated_at | +----+--------------+--------------+-------+---------------------+---------------------+ | 1 | aaa | bbb | val | NULL | NULL | | 2 | create | create | ABCDE | 2022-03-25 05:16:54 | 2022-03-25 05:16:54 | | 3 | save | save | ABCDE | 2022-03-25 05:16:54 | 2022-03-25 05:16:54 | | 4 | insert | insert | aBcDe | NULL | NULL | | 5 | bulk insert | bulk insert | aBcDe | NULL | NULL | | 6 | bulk insert2 | bulk insert2 | aBcDe | NULL | NULL | | 7 | bulk upsert | bulk upsert | aBcDe | 2022-03-25 05:16:54 | 2022-03-25 05:16:54 | | 8 | bulk upsert2 | bulk upsert2 | aBcDe | 2022-03-25 05:16:54 | 2022-03-25 05:16:54 | +----+--------------+--------------+-------+---------------------+---------------------+ 8 rows in set (0.00 sec)
うんまぁ予想通りっちゃぁ予想通り。
「createとsave」はsetを通るようなのですが、insertとupsertは「setを通らない」。
多分、createとsaveは基本的に「Eloquentに所属している」のに対して、insertとupsertはおそらく「クエリビルダに所属している」んだろうなぁ、と。
あと「んじゃ、selectしてきた値をインスタンスに入れる時にはsetは通るのか?」ってのを一応確認。
public function index()
{
//
$data = TestModel::find(8);
var_dump($data->name);
var_dump($data->getAll());
$data->sss('aBc');
var_dump($data->getAll());
}
public function sss($v)
{
//$this->val = $v;
$this->attributes['val'] = $v;
}Trap getNameAttribute
Trap getFirstNameAttribute
string(25) "bulk upsert2 bulk upsert2"
Trap getFirstNameAttribute
string(12) "bulk upsert2"
array(6) {
["id"]=>
int(8)
["first_name"]=>
string(12) "bulk upsert2"
["last_name"]=>
string(12) "bulk upsert2"
["val"]=>
string(5) "aBcDe"
["created_at"]=>
string(19) "2022-03-25 05:16:54"
["updated_at"]=>
string(19) "2022-03-25 05:16:54"
}
Trap getFirstNameAttribute
string(12) "bulk upsert2"
array(6) {
["id"]=>
int(8)
["first_name"]=>
string(12) "bulk upsert2"
["last_name"]=>
string(12) "bulk upsert2"
["val"]=>
string(3) "aBc"
["created_at"]=>
string(19) "2022-03-25 05:16:54"
["updated_at"]=>
string(19) "2022-03-25 05:16:54"
}うんまぁだろうなぁ。
あとついでに。
public function setValAttribute($v)
{
$this->val = 'hoge';
}これやると「エラーは出ないけど動かない」となります。
なんとなくなにが起きてるか? は想像できそうな感じではありますが。
さてここからおいちゃんの感想。
「存在しないカラム値のget」は、いやまぁ「それ、明示的にメソッド書いたほうがよくない?」とは思うんだけど、まぁ「ありっちゃぁアリと言えなくもない」かなぁ、と。
「存在するカラム値のget」は、そこそこ微妙。一方で「加工した値が欲しい」気持ちはわかるのですが、おいちゃんはEloquentを「ORM」と思っているので、だとすると「基本的には、生情報を返せ」って思うんですよねぇ。「加工した情報が欲しいなら、それ用のメソッドを生やせ」的な。ただまぁ「シームレスに取りたい」気持ちが全くわからないわけでもない、ので、微妙。
setについては、おいちゃんは基本「あんまりいい顔はしないなぁ」と。
一方で「便利」だったりするのはなんとなしわかるんだけど、もう一方で「隠蔽が多いと、その辺を"わかってない"人がやらかす」確率が増えて、ねぇ……………。
なのでまぁ「強弁をふるって止める」ってほどではないのですが、あんまり積極的に好印象ってわけでもないかなぁ、。
というわけで、あんまりポジティブな内容にはならんかったんですが、せっかく調べたんで、メモを兼ねて。
"The Zen of Python" と "TMTOWTDI"
いやまぁ「TMTOWTDI の字面をすっかり失念する事が多いから書いておく」とかいう超絶健忘録的な記事なのですがおいといて。
割と個人的に「対極っぽく見えるんじゃないかなぁ」と思っているのが、"The Zen of Python" と "TMTOWTDI"。
TMTOWTDI の"There's More Than One Way To Do It."をDeepLしてみるとこんな感じ。
やり方はひとつじゃない。
Google翻訳だとこんな感じ。
それを行うには1つ以上の方法があります。
まぁそのまんま。
おいちゃん的にはDeepLのほうが好みな訳語かな。
"The Zen of Python" は色々と書いてあるんだけど、TMTOWTDI と対比するのであればこの一文だろうなぁ、と。
"There should be one-- and preferably only one --obvious way to do it."
そのためには、1つ、できれば1つだけ、明白な方法があるはずです。
それを行うための明白な方法は1つ、できれば1つだけでなければなりません。
んで、以下、おいちゃんの私見。
趣味なら「お好きに」なんだろうけど、お仕事だと正直おいちゃんは "The Zen of Python" 推しかなぁ。
小説とかその辺ならともかく、技術系だと、プログラムだろうが日本語だろうが基本的に「表記は揺らさないで欲しい」と思ってる。なんでかっていうと「同じような意味の事を別の文で記載している場合、一定確率で"別の事"が書かれている」から*1。
もうちょっと思考を深掘りすると
・「同じ意味」と思われることが「別の記法」で書かれている
・本当に「完全に同じ」なら、「同じ記法」で書けばいいのではなかろうか?
・という事は、わざわざ「別の記法」で書いているからには「同じ記法ではなく、別の記法で書く理由」が存在する可能性が想起される
というあたりまで考えるので、結果的に「じゃぁその"別にすべき理由"はなんだろうか?」ってのを考えてしまう。
うんまぁその辺の「微妙な差異」が、手書き時の筆跡にも似た「プログラマの微妙な個性」だったりして、デバッグとかに役立つ事もあるんだけど*2。
基本的には「同じ事を書くんなら同じ書き方をしてくれる」ほうが、特に「後からjoinする人間」的には楽だったりするんだよねぇコード読む時。
そんな所で個性だされても困惑するだけだし。
それは個人のプロダクトでやってよ、と、しか。
なのでまぁ、おいちゃんの好みは "The Zen of Python"。
今回取り上げた以外でも
Explicit is better than implicit.
とか
Sparse is better than dense.
とか
In the face of ambiguity, refuse the temptation to guess.
とか
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
とか(それ以外もよいんだがその辺言い出すと全部書き出すことになるので省略)。
まぁこの辺は色々な思考があるんだろうけど、とはいえ「自分と同じような感覚」のものを見つけると、ちょっと嬉しいよねぇ*3。
HTMLの終了タグ(閉じタグ)のお話
ちょいと考察するタイミングがあったもんで、考察したり調べたり。
おいちゃんの基本方針は
・デザイナさんが書いてくるHTMLは「それが正義」
・おいちゃんが(主にmockupで)書く時は
→ liとかテーブル(tr th td)とかリスト(dl dt)とかは省略
くらいの感じでざっくりと書いてます。
んで、色々あってちょいと調べてたら面白いものにぶち当たったので、ちょいと書いておこうかなぁ、と。
Google HTML/CSS Style Guide
https://google.github.io/styleguide/htmlcssguide.html
ってのがあって(初めて知ったけど「まぁあるよねぇ」くらいで、驚きは無し)。
https://google.github.io/styleguide/htmlcssguide.html#Indentation
Indent by 2 spaces at a time.
へぇ「2スペなんだ」。
https://google.github.io/styleguide/htmlcssguide.html#Document_Type
Use HTML5.
うんわかる。
https://google.github.io/styleguide/htmlcssguide.html#HTML_Validity
Use valid HTML where possible.
そらそうだろうよ。
で読んでいくと……
https://google.github.io/styleguide/htmlcssguide.html#Optional_Tags
Omit optional tags (optional).
For file size optimization and scannability purposes, consider omitting optional tags. The HTML5 specification defines what tags can be omitted.
………を?
うん、例が載ってる。
<!-- Not recommended -->
<!DOCTYPE html>
<html>
<head>
<title>Spending money, spending bytes</title>
</head>
<body>
<p>Sic.</p>
</body>
</html><!-- Recommended --> <!DOCTYPE html> <title>Saving money, saving bytes</title> <p>Qed.
……まぢ???
いやまぁ「雑に書く」時とか、headとbodyとか省略しているし「省略できるのは知ってる」けど、これが「推奨」なの???
「For file size optimization and scannability purposes, consider omitting optional tags.」って言われると反論がしにくいのですが(笑
いやまぁわからんでもないのですが、「削れるものは削れ」というあたりは、うん、まぁ、ピーキーで嫌いじゃないよwww
なんか過去にごくうっすら「終了タグ省略するとレンダリング(っつかその手前のパース)で時間がかかる」とかって話を聞いたような記憶がうっすらあるんだけど、どこぞの検証だと「終了タグ、削ったほうがレンダリングが早い」なんて検証もあったので。
まぁとはいえ「言うほど通信量もレンダリング速度も影響あるんかね?」とか思うので割合に「どっちでもいいんぢゃね?」くらいの感じではあるのですが。
ググるさんの規約がなんか微妙にツボったので、メモ(笑
(VARBINARYの代わりとしての)COLLATE utf8mb4_bin
いやまぁそのまんまなのですが。
ちょいと故ありましてLaravel触ってるんですが、あの子、デフォでVARBINARY扱う手段ないんですよねぇ……。
DB::statement('ALTER TABLE (以下略とかで「可能」なのは理解しているんですが、それも「ど~なのよ?」的な。
で。
おいちゃんがVARBINARYを使いたい、一つは「utf8mb4で文字列の長さがINDEXとかPKとか*1」なんですが。
もう一つが「大文字と小文字を等しいとかマジですか? 馬鹿なの? ○○の?」ってあたり。
gallu.hatenadiary.jp
gallu.hatenadiary.jp
gallu.hatenadiary.jp
辺りをご参照の事。
で、「大文字小文字は違うもの」だけなら「COLLATE utf8mb4_bin」でいける、のと、これだとLaravelでも一応取り扱える、ので、軽く実験君。
用意その1。
CREATE TABLE `t1` ( `id` SERIAL, `email` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT 'email', UNIQUE KEY `unique_t1_email` (`email`), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='ユーザテーブル'; CREATE TABLE `t2` ( `id` SERIAL, `email` varchar(255) NOT NULL COMMENT 'email', UNIQUE KEY `unique_t2_email` (`email`), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='ユーザテーブル';
実験。
INSERT INTO t1(email) VALUES('gallu@example.com');
INSERT INTO t1(email) VALUES('Gallu@example.com');
INSERT INTO t2(email) VALUES('gallu@example.com');
INSERT INTO t2(email) VALUES('Gallu@example.com');
mysql> INSERT INTO t1(email) VALUES('gallu@example.com');
Query OK, 1 row affected (0.01 sec)mysql> INSERT INTO t1(email) VALUES('Gallu@example.com');
Query OK, 1 row affected (0.00 sec)
で
mysql> INSERT INTO t2(email) VALUES('gallu@example.com');
Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO t2(email) VALUES('Gallu@example.com');
ERROR 1062 (23000): Duplicate entry 'Gallu@example.com' for key 't2.unique_t2_email'
うん予想通り。
一応、再実験くん。
CREATE TABLE `t3` ( `id` SERIAL, `email` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT 'email', UNIQUE KEY `unique_t3_email` (`email`), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='ユーザテーブル';
mysql> INSERT INTO t3(email) VALUES('gallu@example.com');
Query OK, 1 row affected (0.01 sec)mysql> INSERT INTO t3(email) VALUES('Gallu@example.com');
Query OK, 1 row affected (0.00 sec)
うん。
んで、Laravelだと
$table->collation = 'utf8mb4_bin';
で、(カラムには無理だけどテーブルには)貼り付けられる。
という、多分「ってもおいちゃん自身は使うことねぇんだろうなぁ」的Tipsの検証をしたので、一応、めも。
今のところの「糖尿病」の対策:小まとめ
とりあえず、薬物療法はがっつりと「お医者様の領域」なので、食事療法と運動療法の側の、個人的雑感を、ざっくりと。
当然ですがおいちゃん「医師ではありません」し「個人の見解」程度なので、参考程度にごらんくださいませ。
まず先に「チューニングの基本は計測」なので、今回だと「血糖値の計測が出来るようになる」のが最優先。
一端は「1日に1~2回」くらいはかって、せめて200を切るくらいまで、は、思いっきりがんばりませう。端的には「がっつりと糖質を削る」「運動をする」あたり。
それ以降についてはまぁ緩やかに。確か「食後で140、2時間くらい経つと100くらい」が「普通の人の値」だったと思ったので、この辺まで頑張れるとベターなんじゃないか、と。
んで。
とりあえず「食事のコントロール」と「運動のコントロール」は、多分「両輪だろうなぁ」と。
運動のほうは、基本的には「有酸素でカロリーをある程度減らす」と「筋トレでそもそもの基礎代謝を上げるの両輪がよいぽい。
がっつりやっている人は知らんが、運動不足のおいちゃん的には「とりあえずまず歩く」からstart、かなぁ。
出来たらエアロバイクくらい漕ぐとよさげ。「2日に1回」くらいのペースの時は、色々と調子がよかった気もする。
結構色々ありそうなのが、食事。
おいちゃん的には
・緩やかに低糖質
・ある程度の低脂質
・難消化性デキストリンが結構有効打になった
って感じでした。
どうも、血液検査で「中性脂肪」が上がるとHbA1cも高値をマークする傾向があったので(まぁ糖新生とかあるしなぁ)。
血液検査の結果次第ではあるのですが、「中性脂肪が高い」人は、これも下げて上げるとよい、ので。
そこで「ある程度の低脂質」と、結構有効打だったのが「難消化性デキストリン」。
この辺で、ある程度のガードが出来そうな気がする。
難消化性デキストリンは
・デカい袋かって飲む
以外にも
・キリン メッツ コーラとかで、入ってるのがある(特保でいくつかあるみたいです)
・食物繊維( https://www.otsuka.co.jp/nmd/product/item_310/ )を、食前に飲む
とか、いくつか方法があるので、お好みで。
糖質は、勿論「ドカ食い」は駄目、ってのは前提として。
後はなんとなし「GIが低いほうが割とよさげ」な気がするので、その辺も少し注意しつつ。
主食を、出来たら「夜くらいは控える(減らすか、なくす)」といいんじゃないかなぁ、と。次は「昼と夜」をカット。
糖質の量については、一端「1日に120~130g程度」を目安にすると、「それなりに絞れて」「そんなに無理がない」ような気がするです。
「脂と糖を減らしてなに食うねん?」の答えは「蛋白質」。
後は、間食だと
・ナッツ
・チーズ
・82%とかのチョコレートを少量
・こんにゃくゼリー
とかが、割と便利かなぁ、と。
プロテインバーも低糖質のがあるので、探すと便利。高いのが多いですが、安いのもあるので(笑
料理の時の調味料として
・砂糖は使わない:ラカンントとエリスリトールを使ってます
→ 「みりん」は「酢」に置き換えると、案外と美味しいです(好みもあるんだろうけど)
・ケチャップも控える
・片栗粉は、サイリウムで置き換えるとよいですが使い方にコツがあるので注意
とか少し気を配ったり、食材的には
・カボチャとか芋類は控える
くらいからstartすると、割と緩やかにいけるのではないかなぁ、と。
あとは、個人的には「ローソンと仲良くなると低糖質がはかどりやすい」と思われます(笑
選べば、アイスとかも割と低糖質あるしねぇ。多分、商売の文脈は「ダイエット」なんだろうけど、まぁありがたい(笑
この辺が、出だしではないかしらん?