soukouki’s diary

誰かの役に立つ記事をかけたらいいなあ

DiscordBotのグリボト!とBlockKingの紹介

自分が作ったDiscordBotの紹介です。

招待したい場合は、

  • 自身がサーバーの管理者権限を持っている場合
    • 招待urlにアクセスすると導入する画面が出てきます。権限についてはできる限り絞ってあります。
  • 持っていない場合
    • サーバーの管理者権限を持っている人に招待urlを渡してください。

グリボト!

f:id:soukouki:20190805010853p:plain
グリボト!の例

挨拶をすると返事をしてくれるbotです。省略形(こん)とか、挨拶からちょっと離れたものまで色々対応してます。

最近は誤反応も殆ど起こらなくなっています。つよいでしょ。

現在108サーバーに導入されていてます。

↓招待リンク。 discordapp.com

BlockKing

f:id:soukouki:20190805011359p:plain
BlockKingの例

Discord内でプレイできる半放置形ゲームです。

ブロックを支配し、アイテムを集め、クラフトし、どんどん強くなっていくゲームです。

放置時間が終わったらメンションで通知してくれるので、新しいことに目が行っちゃう人にもおすすめ!

目指せ王座!

現在101サーバーに導入されています。

↓公式サーバー(わからないことがあればこちらへ。プレイもできます。プレイヤー同士での会話とかもあります。) discord.gg

↓招待リンク discordapp.com

鉄道とバスで大内宿に行くときのメモ(2019-夏)

(ブログ書くのいつぶりだろう)

役立つかもしれないし役に立たないかもしれない情報集です。少なくとも自分は欲しかったです。 基本的に関東方面から向かうことを前提に書いています。

東武線特急リバティは下今市より北は特急券がいらない

railway.tobu.co.jp

貧乏旅で一瞬だけ豪華な時間を味わえます。

会津湯野上温泉から大内宿へはバスで行ける

ouchi-juku.com

猿遊号(さるゆうごう)が使えます。予約もできますが、必要ではありません。 運行期間は4月1日から11月30日までなので、冬には使えません。

地味に本数少ないので注意です。

猿遊号と会津鉄道の共通割引きっぷがある

会津鉄道&レトロバス猿游号で行く大内宿共通割引きっぷ │ 会津鉄道-会津鉄道で行く、会津の列車たびwww.aizutetsudo.jp

リバティで会津田島まで行き、そこで買うこともできますし、AIZUマウントエクスプレス車内でも買えると思います。(検札あったから車掌さんのはず!)

日光方面から会津若松へ抜けていく場合、

会津田島-湯野上温泉730円+猿遊号往復1000円+湯野上温泉-西若松840円=2570円が1900円になるのだから断然お得です!ちくしょう!

途中下車もできるので、塔のへつりにも寄れます。

会津田島-湯野上温泉の往復のきっぷもあります。案内見るとその区間内はどこにも行けるように見えるけど、使ったことがないのでわからないです・・・

あと、有効期限は2日間なので、途中の温泉で一泊する旅行でも使えます。

日光-喜多方(会津田島まで、芦ノ牧温泉までのきっぷもあり)

今回の自分の旅とはあまり合わなかったので、詳しいことはわからないです・・・

tabi.tobu.co.jp

4日も使えるので、色々使えそうです。

ファイルのダウンロード時に、ものすごい重くなる問題への解決策

ファイルをダウンロードするとき、すごく重い・・・数秒間フリーズしませんか・・?

※アップデートを忘れたため少し前のバージョンになるので、最新バージョンだとなにか変わっているかもしれません。


ダウンロードタブの右側のスクロールバーを上にスライドさせると、ものすごい昔のダウンロード履歴まで見られます。

なんとなく重そうなので、ダウンロードパネルの右上、箒のマークの「一覧からダウンロード済みのものをすべて削除」を押し、ついでに残ったものも削除してみるとあら不思議!

すごく軽く動くようになりました。今どれだけダウンロードが進んでいるかもわかるほど!

悩んでる方はぜひ。

以上、数カ月ぶりの更新のすごく短い文章でした。


操作をしたバージョン

Vivaldi 2.2.1388.37 (Stable channel) (32-bit)

現在の最新版

Vivaldi 2.3.1440.48 (Stable channel) (32-bit)

電卓をワンライナーで書きたい!

さて、4ヶ月ぶりの更新です。

まぁ、やることはタイトルのとおりです。

改行、セミコロンと、セミコロンに近いもの((a=2)&&([a,a]) #=>[2, 2])は縛っていきます。

まずは逆ポーランド式電卓から

f = ->(s){->(t){(t==s)? s : f[t]}[s.gsub(/(-?\d+) (-?\d+) ([-+\/*%])/){$1.to_i.send($3, $2.to_i)}]}

f["1 2 3 + *"] #=> "5"

アンダースタンディング コンピュテーションって本を読んでるとだんだんRubyラムダ式に慣れてくる・・

基本的に変数を使いたくなったらラムダ式に変換します。再帰でなければ・・・

仕組みは正規表現マッチとObject#sendを使って、正規表現にマッチしなくなるまで変換し続けていく形です。

このときは楽だった・・

そして、普通の電卓へ

f = ->(r){->(a){r[->(b){r[->(d){r[->(g){g.gsub(/(-?\d+)([*\/])(-?\d+)/){$1.to_i.send($2,$3.to_i)}},d].gsub(/(-?\d+)([-+])(-?\d+)(?![*\/])/){$1.to_i.send($2,$3.to_i)}},b].gsub(/\((-?\d+)\)/){$1}},a]}}[->(f,v){->(f){->(x){->(m){f[x[x]][m]}}[->(x){->(m){f[x[x]][m]}}]}[->(x){->(s){->(a){a==s ? a : x[a]}[f[s]]}}][v]}]

f["1*2/3"] #=> "0"
f["-1+2"] #=> "1"
f["1*2+3*4+5+6+7"] #=> "32"
f["-1*(2+3)"] #=> "-5"
f["1+2*(3+4)*5"] #=> "71"

お化けです。

このままじゃ読めないので、分解していきます。

r = ->(f,v){->(f){->(x){->(m){f[x[x]][m]}}[->(x){->(m){f[x[x]][m]}}]}[->(x){->(s){->(a){a==s ? a : x[a]}[f[s]]}}][v]}
f = ->(a){r[->(b){r[->(d){r[->(g){g.gsub(/(-?\d+)([*\/])(-?\d+)/){$1.to_i.send($2,$3.to_i)}},d].gsub(/(-?\d+)([-+])(-?\d+)(?![*\/])/){$1.to_i.send($2,$3.to_i)}},b].gsub(/\((-?\d+)\)/){$1}},a]}

まずは、rとfに分解します。

rの詳細とZコンビネータ

さらにrを分解します。

z = ->(f){->(x){->(m){f[x[x]][m]}}[->(x){->(m){f[x[x]][m]}}]}
r = ->(f,v){z[->(x){->(s){->(a){a==s ? a : x[a]}[f[s]]}}][v]}

(一つラムダ式とその呼出が増えていますが、動きは一緒です。)

元の形ではrの内部でrを呼び出して再帰をしていたのですが、この縛りだとrの名前がなくなるので、簡単に再帰はできません。

なので、Zコンビネータを使います。 obelisk.hatenablog.com(詳細は丸投げ!) (ぶっちゃけZコンビネータの中身は理解できてないし、これの使い方に試行錯誤する時間が多分一番長かった気がする)

fの詳細

ついでにfもわかりやすくしてみます。

# 参考用r(Zコンビネータ使用前)
r = ->(f,v){
    a=f[v]
    a==v ? a : r[f,a]
}
f = ->(a){
    r[
        ->(b){
            r[
                ->(d){
                    r[
                        ->(g){
                            g.gsub(/(-?\d+)([*\/])(-?\d+)/){$1.to_i.send($2,$3.to_i)}
                        },
                        d
                    ]
                        .gsub(/(-?\d+)([-+])(-?\d+)(?![*\/])/){$1.to_i.send($2,$3.to_i)}
                },
                b
            ]
                .gsub(/\((-?\d+)\)/){$1}
        },
        a
    ]
}

実はものすごいネストしています。

r(f,v)は値が変わらなくなるまでfを呼び続けます。逆ポーランド式電卓の方にもそんな感じの部分があります。

そしてそれをネストしながら呼び続けることによって、優先順位のある計算を行います。

括弧の処理は中の+-*/を計算し尽くしてできた(x)xに置き換えることによって行っています。

計算の様子

r内にp [f,v,a]を置いてみると、計算の様子がよくわかります。(Procの部分を置き換えています。)

(なんか括弧の優先順位が違うような気がするけど、とりあえず正常に動くので気にしない・・バグがあったらコメント等で教えてくれるとありがたいです。)

# f["1*2/3"]
[#<*/の処理>, "1*2/3", "2/3"]
[#<*/の処理>, "2/3", "0"]
[#<*/の処理>, "0", "0"]
[#<+-の処理>, "1*2/3", "0"]
[#<*/の処理>, "0", "0"]
[#<+-の処理>, "0", "0"]
[#<括弧の処理>, "1*2/3", "0"]
[#<*/の処理>, "0", "0"]
[#<+-の処理>, "0", "0"]
[#<括弧の処理>, "0", "0"]

# f["-1+2"]
[#<*/の処理>, "-1+2", "-1+2"]
[#<+-の処理>, "-1+2", "1"]
[#<*/の処理>, "1", "1"]
[#<+-の処理>, "1", "1"]
[#<括弧の処理>, "-1+2", "1"]
[#<*/の処理>, "1", "1"]
[#<+-の処理>, "1", "1"]
[#<括弧の処理>, "1", "1"]

# f["1*2+3*4+5+6+7"]
[#<*/の処理>, "1*2+3*4+5+6+7", "2+12+5+6+7"]
[#<*/の処理>, "2+12+5+6+7", "2+12+5+6+7"]
[#<+-の処理>, "1*2+3*4+5+6+7", "14+11+7"]
[#<*/の処理>, "14+11+7", "14+11+7"]
[#<+-の処理>, "14+11+7", "25+7"]
[#<*/の処理>, "25+7", "25+7"]
[#<+-の処理>, "25+7", "32"]
[#<*/の処理>, "32", "32"]
[#<+-の処理>, "32", "32"]
[#<括弧の処理>, "1*2+3*4+5+6+7", "32"]
[#<*/の処理>, "32", "32"]
[#<+-の処理>, "32", "32"]
[#<括弧の処理>, "32", "32"]

# f["-1*(2+3)"]
[#<*/の処理>, "-1*(2+3)", "-1*(2+3)"]
[#<+-の処理>, "-1*(2+3)", "-1*(5)"]
[#<*/の処理>, "-1*(5)", "-1*(5)"]
[#<+-の処理>, "-1*(5)", "-1*(5)"]
[#<括弧の処理>, "-1*(2+3)", "-1*5"]
[#<*/の処理>, "-1*5", "-5"]
[#<*/の処理>, "-5", "-5"]
[#<+-の処理>, "-1*5", "-5"]
[#<*/の処理>, "-5", "-5"]
[#<+-の処理>, "-5", "-5"]
[#<括弧の処理>, "-1*5", "-5"]
[#<*/の処理>, "-5", "-5"]
[#<+-の処理>, "-5", "-5"]
[#<括弧の処理>, "-5", "-5"]

# f["1+2*(3+4)*5"]
[#<*/の処理>, "1+2*(3+4)*5", "1+2*(3+4)*5"]
[#<+-の処理>, "1+2*(3+4)*5", "1+2*(7)*5"]
[#<*/の処理>, "1+2*(7)*5", "1+2*(7)*5"]
[#<+-の処理>, "1+2*(7)*5", "1+2*(7)*5"]
[#<括弧の処理>, "1+2*(3+4)*5", "1+2*7*5"]
[#<*/の処理>, "1+2*7*5", "1+14*5"]
[#<*/の処理>, "1+14*5", "1+70"]
[#<*/の処理>, "1+70", "1+70"]
[#<+-の処理>, "1+2*7*5", "71"]
[#<*/の処理>, "71", "71"]
[#<+-の処理>, "71", "71"]
[#<括弧の処理>, "1+2*7*5", "71"]
[#<*/の処理>, "71", "71"]
[#<+-の処理>, "71", "71"]
[#<括弧の処理>, "71", "71"]

おまけ

製作途中

r = ->(f,v){a=f[v];a==v ? a : r[f,a]}
f1 = ->(s){r[->(t){t.gsub(/(-?\d+)([*\/])(-?\d+)/){$1.to_i.send($2,$3.to_i)}},s]}
f2 = ->(s){r[->(t){f1[t].gsub(/(-?\d+)([-+])(-?\d+)(?![*\/])/){$1.to_i.send($2,$3.to_i)}},s]}
f = ->(s){r[->(t){f2[t].gsub(/\((-?\d+)\)/){$1}},s]}

ハマったところ

  • rの再帰の呼び出しr[f,a]f[a]にしていて、なんかおかしいなと思いつつも大体の式はうまく動いちゃうので微妙なバグでした。
  • f1は楽だけど、f2のf1を呼ぶ部分で迷った・・3重ループになるはずだから、多分ここで合ってるはず・・実際式を入れたら動くのだし()
  • Zコンビネータの使い方・・あれって2つの引数を持つ再帰はできないのかな・・?最初fも再帰の引数に入れてて詰まってました。

以上

秋の夜長にプログラミング!そして次の日の朝起きられなくなる・・・

Rubyで大きな値(数億桁)を扱うときのメモ

ある日。フィボナッチ数列の10億万番目とその前2つの値を計算して、割って黄金比を求めているときのメモ。

nilを代入しないとGCは片付けてくれない

まぁ、メモリがそこまで逼迫することはあまりないと思うけど。

割り算ができない(浮動小数点数にできない)

浮動小数点数に直すとInfinity行っちゃいます。

最初NaNを見た時は「えっ」ってなります。

小数を使いたい時は割られる側に大きな数を掛けておきましょう。

Integer#** の右側に大きな値を置けない

よく引っかかるやつ。

10**10_0000_0000 # なら
([10**(10_0000_0000/100)]*100).inject(:*) # 100の部分は適当に割り切れる数字で

計算に結構な時間がかかるのであれ(

右側の値は100万くらいなら大丈夫っぽい。

Integer(Bignum)#to_s でエラーが出る

to_s お前もか

`to_s': bignum too big to convert into `string' (RangeError) はえぇ・・

OKU = ([10**(100_0000)]*100).inject(:*) # ここだけで100秒かかります
def very_big_num_to_string n
    if n < OKU
        n.to_s
    else
        bottom = n % OKU
        top = n / OKU
        n = nil
        very_big_num_to_string(top) << bottom.to_s
    end
end

みたいなメソッドを作っておけばいいです。遅いけど...