whoami

学んだことや考えたことのアウトプットをします。AtCoder@japanesekeigo Twitter@keigopiano

LINE messaging API + Heroku + Python で発言をそのまま返してくるだけのボットを作成(備忘)

背景

LINE Developers - # Herokuでサンプルボットを作成するに従っても、一部できなかったので備忘も兼ねて記載。(javaだとできた)

始める前に

LINE Developersのサイトを参考に

・ボット用のチャネルを作成する。

・Herokuアカウントを作成する。

HerokuでCreate New App

名前はなんでも良い

LINE Developers Console

Webhook URLを下記にする。

https://{Herokuで作ったアプリ名}.herokuapp.com/callback

Channel access token (long-lived)

Channel secret

を記録

Heroku

settings

Config VarsをReveal Config Vars

LINE_CHANNEL_ACCESS_TOKEN

LINE_CHANNEL_SECRET

を追記

deploy

Deployment methodをgithubにして、リポジトリと連携させる。

GitHub

サンプルボットのコピー

リポジトリに下記フォルダ以下のファイルをコピーする。ただし、app_with_handler.pyは不要

line-bot-sdk-python/examples/flask-echo at master · line/line-bot-sdk-python · GitHub

main関数をLINE Bot + Python + Heroku で「Error R10 (Boot timeout) 」エラーが出たときの解消方法に従って変更

ファイル追加

Procfileを作成し、

web: python app.py

と記載

Heroku

Manual DeployからDeploy Branchをクリック

これでできるはず。

他勉強したこと

Herokuはどうやってアプリの形式を判断する?

Heroku での Python および Django アプリのデプロイ | Heroku Dev Center

Procfileって?

Procfileはなんでweb属性なん?

Procfile | Heroku Dev Center

沢渡 あまね「ここはウォーターフォール市、アジャイル町」 感想

www.amazon.co.jp

いい本でした。特に典型的JTCに勤める私にとっては。

組織としてシステム開発ウォーターフォールの形式であっても、いかにしてアジャイルな開発手法を取り込んでいくかということが、合間に解説を挟みつつ小説で描かれます。

もしスプリント開発等のアジャイル開発をすでに実践しているとしたらこの本は不要でしょう。

著者がどのようなモチベーションでこの本を書いているかは本から引用しますと

そして、私のようなコテコテのウォーターフォールの世界の住人にもアジャイルを知ってほしい、試してほしいと強く願うようになります。

さりとて、なかなかハードルが高い。当時、書店の技術書コーナーを見渡しても、「美しすぎる」アジャイル書籍ばかり。アジャイルの方法論を事細かに解説し、完璧なる定着に導く書物は多数あるものの、エッセンスを「つまみ食い」「いいところどり」できるようなライトなものは見当たらない。それが、私のようなウォーターフォールの住人にとって、アジャイルをますます「どこか遠い星のおとぎ話」にしてしまう。

このようなことが書いています。

あなたがそれなりに歴史ある日系企業システム開発の現場で、ウォーターフォールの限界を感じながらも働いているとしたらこの本は有益でしょう。閉塞感をなくし、無力感を消し去るために、現場からできるアジャイルなエッセンスの取り込み方がこの本には書いてあります。アジャイルウォーターフォールとは決して二項対立ではないということがこの本を読んでわかります。本の言葉を引用するのなら、アジャイルとは「あり方」なのです。

といっても小説の中で主人公たちが取り組む内容は、チームへの「チケット管理」と「チャットツールの導入」です。 ツールとしてはこの二つですが、このツールをどのように導入し、広めていくか。そして振り返り、チームそして組織として成長していくかがこの話のキーだと思います。 まぁ、解説も半分くらいあるので小説はちょっとうまく行きすぎな感はありますがそれでも「チケット管理」や「チャットツールの導入」をすでに行っている私のチームでもできることはいっぱいありました。

来週から自分もアジャイルな考え方で何か変化を提供できたらいいなと思います。

ABC077 C - Snuke Festival

1年以上振りの投稿

問題

長さNの自然数の配列A, B, Cが与えられる。
a∈A, b∈B, c∈Cとする。
a<b<cとなる組み合わせの個数を求めよ。

AtCoderの解説

配列AとCをソートして、配列Bの各値bについて、bより真に小さい配列Aの要素数とbより真に大きい配列Cの要素数を二分探索を用いて求める。ただし、配列AとCには同じ数字が複数ある可能性があるため、探し方には注意する。

Python3だとbisect.bisect_leftbisect.bisect_rightを用いるとよい。

時間計算量O(N*logN)

二つのやり方で解いた。

配列A, B, Cをソートする。配列Bの最も大きい要素より大きいCを後ろから順番に探す。その次に大きいBの要素をCから探すが、前に探したとこより前(後ろ)にあるため、それを利用する。この手法によりBの値を固定した時のCの値の個数がわかる。

配列Aを小さい方から見ていく。 配列Aの一番小さい要素より初めに真に大きくなるBの要素を順番に探して見つける。Aの要素を固定したとき、 BとCの要素の組み合わせは先ほど求めた配列の累積和となっているためあらかじめ求めておく。

配列Aの次に小さい要素は先ほど見つけたBの要素よりは後ろにあるはずなので、探す。

これらの手法は全てO(N)で計算可能であるため、通る。

Submission #11220971 - AtCoder Beginner Contest 077

Submission #11220645 - AtCoder Beginner Contest 077

結構好きかもしれない。

(25分)

自分とプログラミングの関わりを整理するだけ。学生〜社会人(AtCoder水色)

初めて真面目にブログを書く気がします。
私は、某通信企業の新卒1年目の社員です。2018年3月に大学院を卒業し4月から働き始めています。大学院ではグラフ理論に関する研究をしていました。

つい先日AtCoderでやっとこさ水色になりここまで何をしてきたかまとめてみることにしました。ついでに学生時代のこともまとめてみました。

ここから学生時代をまとめます。長いです。

↓ここから学生時代の私とプログラミングの話

始めてプログラミングをしたのは高校生の頃の授業でした。確かBASIC使った授業でした。何を作ったのかはもう忘れましたが周りより少し出来がよかったのと(周りよりできたからか)楽しかったのを覚えています。

なんとなくプログラミングかっこいいな。と思いつつも特に何をするでもなく高校を卒業、無事に浪人し、大学生となりました。私の大学は2年生に上がる時に詳細な学科を選び、1年生の時は広く学びます。東大ぱてぃーん。
1年生の後期にプログラミング入門の授業があり、C言語をやりました。不真面目な私は授業に遅刻しまくり、課題もわからずなんとなく面白くなく感じ、ギリギリの成績でパスして、プログラミングはいいやと思い情報系学科ではなく量子力学などのミクロな物性を学ぶ学科に進みました。

しかし、量子力学統計力学もあまり面白くなく2年生、3年生と部活に没頭する日々を過ごしました。部活は楽しかったし、今に繋がる学びも一生の友人もできたのでそれはそれでよいです。
楽しくなかった2年生、3年生の授業の中にも印象に残っているのが3つあります。
・NAND回路を組み合わせてOR回路やXOR回路などの論理回路を作る実験
・いくつかのプログラミングの課題(内容は忘れました)をやり、発表する。(友達が途中で諦める中で私だけが時間を忘れてできるまで取り組んだのが非常に印象に残っています。)
非線形微分方程式の数値解析解を数値シミュレーションで求める授業。(最終的にはそのような目標なのですが、プログラミングができない人もくるので初歩の初歩から教えてくれる授業でした。)マンデルブロ集合を描画したりして結構感動しました。
ja.wikipedia.org

とまぁ、なんだかんだプログラミング好きだなぁと思うことがあり、学部再編の影響でプログラミングができる研究室への道があり、成績が芳しくなく人気がある研究室の道は厳しそうでもあり、さっき書いた授業をしてくれた(人気のない研究室の)教授につくことにしました。


私の研究内容は非線形力学とは離れますが、グラフ理論に関わる研究でした。内容はいいとしてC言語でせっせこシミュレーションをして歴代でも稀に見る短さの学士論文を書き卒業、修士課程へと進みました。学部時代の研究でC言語に嫌気がさした私はPython3系に手をだしました。合計130万程度のデータを扱うこともあり、MySQLにも手を出し始め、あまり形にならないまま就職活動の時期を迎えました。なんとなく研究職楽しそうと思い研究職関連を受けるも全敗、就職活動に嫌気がさし始めたところで今の会社から内定をもらい、まぁでかい会社だし福利厚生もしっかりしてるし、いっかなーと深く考えず就職活動を終了。この頃から将来のことを少しずつ真剣に考え始めたりしました。

クラシック音楽が好きということもあり、海外で働けばいつでも世界の1流オーケストラの演奏きけるじゃんと思い、海外志向が芽生え夏休みには1ヶ月のなんちゃって語学留学@アイルランド。たのしかったぁ・・・

帰ってきたら、研究を進めPython3もMySQLもちょっとずつわかるようになってきて研究も楽しくなってくる。しかし、修士論文にシフトする時期でプログラミングとはちょっと疎遠に。

そのまま修士論文を書ききり、なんとか卒業。

就職となる。

↑ここまで。ここから社会人編

そして新入社員として働き始める。
そうすると、コレジャナイ感・・・
まぁ、就職活動を適当に終わらしたつけですよねぇ・・・
会社の人や制度、雰囲気、その他毎日みるニュースで漠然と焦燥感を感じ、勉強する必要性を感じる。そんなこんなで競技プログラミングをプログラミングの勉強的な視点から始めて見ることにしました。すると、対人なんだけど一人で取り組む、ある種のゲーム性、プログラミングという技術そのものが見事に自分の性格に一致し、楽しい楽しい。
競プロ沼へとはまっていくのです・・・

ここで6月にスタートして1月までの8ヶ月間のレートの推移を貼り付けます。
f:id:japanesekeigo:20190115230814p:plain
のんびり上がっていきますね。やはり会社員は平日八時間の拘束はあるので仕方ない。精進グラフ(AtCoder Scoresより)を見ても
f:id:japanesekeigo:20190115231503p:plain
問題を解くタイミングが、土日などの休み、またはお盆休みや正月休みに固まっているのがわかります。長期休暇の間にいっぱい問題といて次のコンテストでレートがあがるというのがパターン化していますね。この前水色に上がれたのは正月休みで問題いっぱいといた影響ですね。

どうやってレート上げてきたかを振り返るとやっぱりめんどくさいことはあまり続かなくて楽しんでやってきたことが続いて成果を残してると思います。
ここでいう私にとってめんどくさいことは、例えば自分の実力以上の問題を何日も使ってACする。とかですかね。どうしてもACが出ない時もありますし・・・
逆に楽しいのはACかな?WAかな?TLEかな?みたいな位置の問題を解いてACを出すことですね。ぱっと見わからんけど、ちょっと考えたらわかるレベルの問題を解く。それを繰り返してる気がします。でも同じレベルやとそのうち飽きてきます。
そうしたら、まずもっと難しい問題にチャレンジしたくなりました。
もう一つには、分かってるから、もっと早く書きたい、もっとめんどくさくない方法がいいって思いはじめました。そうすると他人の回答を見たりするようになったり、綺麗に書く方法を探ってみたりして、結果的にライブラリの知識やできることが増えていきました。

そうやって300点の問題なら面白くないときの方が多いかも・・・?まできて水色になったのが今の自分な感じです。

今後は400点問題を中心に解いていこうかなと・・・
あ、あとPython3で水色まできましたがDPとかをした時に間に合わないときがあるのでC++は少しずつ勉強始めてます。
競プロはプログラミングの学習的な意味ももちろんありますが、娯楽的な要素が完全に勝っています。娯楽は楽しくないと続かない。青色になった時またブログ書きたい。

青色って500点問題が面白くなくなるくらいですかね・・・?

isStable

AOJの問題
Aizu Online Judge

もっと簡単に実装したかった。

from copy import deepcopy


def printer(A):
    ret = str(A[0][1]) + str(A[0][0])
    for i in range(1, len(A)):
        ret += " " + str(A[i][1]) + str(A[i][0])
    print(ret)
    return True


def devide(card):
    ret = []
    for c in card:
        num = int(c[1])
        pic = c[0]
        ret.append((num, pic))
    return ret


def bubblesort(A):
    ret = 0
    flag = True
    num = len(A)
    while flag is True:
        flag = False
        for i in reversed(range(1, num)):
            if A[i - 1][0] > A[i][0]:
                tmp = A[i - 1]
                A[i - 1] = A[i]
                A[i] = tmp
                flag = True
                ret += 1
                # print(A)
        # num -= 1
    return ret


def selection_sort(A):
    ans = 0
    for i in range(len(A)):
        minj = i
        for j in range(i, len(A)):
            if A[minj][0] > A[j][0]:
                minj = j
        if i != minj:
            ans += 1
            tmp = A[i]
            A[i] = A[minj]
            A[minj] = tmp
    return ans


def isStable(card, sorted_card):
    if len(card) != len(sorted_card):
        return False
    for i in range(len(card)):
        c = card[i]
        s = sorted_card[i]
        if c[0] != s[0] or c[1] != s[1]:
            return False
    return True


n = int(input())
card = list(map(str, input().split()))

card = devide(card)
card_bubble = deepcopy(card)
card_selection = deepcopy(card)

bubblesort(card_bubble)
selection_sort(card_selection)

# print(card_bubble)
printer(card_bubble)
print("Stable")

printer(card_selection)
if isStable(card_bubble, card_selection) is True:
    print("Stable")
else:
    print("Not stable")

Selection Sort

AOJの問題
Aizu Online Judge

選択ソート
めっちゃ遅そう。
O(nlogn)か
Python3系だよ

def printer(A):
    ret = str(A[0])
    for i in range(1, len(A)):
        ret += " " + str(A[i])
    print(ret)
    return True


n = int(input())
A = list(map(int, input().split()))

ans = 0
for i in range(n):
    minj = i
    for j in range(i, n):
        if A[minj] > A[j]:
            minj = j
    if i != minj:
        ans += 1
        tmp = A[i]
        A[i] = A[minj]
        A[minj] = tmp
printer(A)
print(ans)

Shuffle

AOJの問題
Aizu Online Judge


カードのシャッフルをする。解説読めばできる。

#include<iostream>
#include<string>
using namespace std;

int main(){
    string card;
    int h;
    int n;
    
    while(cin >> card){
        if(card == "-")break;

        cin >> n;

        for(int i=0;i<n;i++){
            cin >> h;
            string tmp = card.substr(0, h);
            card.erase(0, h);
            card += tmp;
        }
        cout << card << endl;
    }
    return 0;
}