Pythonを使って車校の技能実習予約を自動化したBlog

# ほんとうにはじめに
偉そうに Qiita に記事を投稿させてもらっておりますが、そもそも僕は大学学部1回生で理系ではあるけど工学部生ですらないんですよね。だからプログラムにも「なんでそんなやりかたした?」「いやこうした方が読みやすくなるしスピードも上がるくね?」とツッコミが入る部分が絶対多々多々あると思います。暖かい目で見守って下さり、できれば指摘していただけると嬉しく思います。

# はじめに
いや今年の春晴れて第二志望の大学に受かって念願の教習所に通っているんですけどね。大都会では技能実習の予約がとれん!
ってことでキャンセル待ちって言うのをやってるんですけど...

私が通ってる教習所のキャンセル待ちのやり方は

> ①実習生が番号が書かれている札をとる
> ②番号が呼ばれた順に、キャンセルが出たら技能実習を受けられる

という制度なんですけどもね。

初めてキャンセル待ちしたとき "22"と書かれた札を取ったんですよ。そしたら呼ばれた順番が 18 → 25 → 21 → **22** → 7 → 16 とかで4番目に乗れて。「はは～ん、番号が後ろの方が先に呼ばれやすいんだな～?」とか思って
ウッキウキで2回目キャンセル待ちしたとき "18" と書かれた札が目に入ってきたんですよ。これ最初のキャンセル待ちのときに一番最初に呼ばれた札だったから、もう嬉々として "18" の札を取ったら、今度呼ばれた順番が 7 → 1 → 3 → 11 → .... とかもうとにかく最初の方の数字しか呼ばれなくて、結局 "18" が呼ばれたのは1番最後で。
変に考えて取ったらいけないと思って臨んだ3回目のキャンセル待ちで、もう何も考えずに引いたら "24" 番、

> 受付のおねぇさん「 21番の方～ 次に 25番の方～」
> わたくし「おっ？後の方の番号呼ばれてんな」
> おねぇさん 「 23番の方～ 19番の方～」
> わたくし「24番の前後呼ばれてる、これは絶対いける」
> おねぇさん 「 16番の方～ 9番の方～」
> わたくし「 ... 」
> ... (以下悶々とする私) ...
> おねぇさん 「 13番の方～ **最後に**24番の方～」

........

**.....いや結局一番最後かい!!、後ろの方の番号が先に呼ばれといて一番最後かい!!!!!、前後の数字が4番目までぐらいに呼ばれといて一番最後かい!!!!!!!!!!!!、昨日もキャンセル待ち一番最後やったのに今日も一番最後かい!!!!!!!!!!!やってられんわこんなん!!!!!....**

はい、というわけで。技能実習の予約を自動化してばんばん予約を入れて行ってキャンセル待ちで2回も一番最後に回させた教習所と教習所のおねぇさんへの恨みを全部ぶつけていこうと思いま～す。許さんからな

# 目標
技能実習の予約を自動化する!!!!! 

.....って言ってもふんわりしすぎですよね。
具体化すると、人間が全力でなんかの予約を取る時、F5キーかリロードのグルグルを押しまくって、予約の空きを見つけた瞬間全力でそこに予約を入れるという作業をするじゃないですか。その作業を自動化するのが目標ですね。

# 設計
まず、やっぱり "予約自動化" なんて抽象的なのを目標にするんじゃなくって、もっと具体化して問題を切り分けて簡単なのに落とし込んで行きましょうや。ものづくり・問題解決・京大数学・日常生活の基本。
>たとえば京大合格を目標にするとき、 "京大合格！" なんて抽象的なものを目標にするんじゃなくって "物理70点、化学50点、数学150点 .... を取る!" だとか、あるいはもっと低次な "物理標準問題集全問2回解く、分からなかった問題はさらに2回解く" とかの目標にしてから発進するでしょうよ。こんな偉そうなこと言っといて僕京大落ちたんですけど。2022京大物理の大問2なんてあれ反則でしょうよ。あんなん知ってるか知らないかやもん。あんなんで物理の能力が測れるとは思えないけどな。行きたかったな～京大... **閑話休題**

閑話休題。
具体化して問題を切り分けると
> ①教習所の技能実習の予約ページを開き、予約の空き状況・自分のとった予約を取得する
> ②自分が既に予約している技能実習の時間より**前に**技能実習の予約の空きがあり、かつスケジュール的にOKなら、すでに取った予約をキャンセルして、より前の技能実習の予約をとる

これを while ループで回してやれば良い...

これだけの話で無事予約自動化できそうですね。どうです? "予約自動化" の一言よりずっと簡単に見えるでしょう。さらに切り分けて、本質でない部分を省略し、ざ～っくり画像にまとめるとこんな感じです。イメージ大切。

![fig1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2715879/9a2b388e-81b6-9373-a411-cf274c4620ba.png)



さらに簡単に見えてきましたかね。
これをプログラムに起こすとこうなります。

# 実装

~~~python:autobooker.py
import pandas as pd
from time import sleep

def main():
    schedule = pd.read_csv("schedule.csv", index_col = "date")
    
    while True:
        status = statusGetter()
        reservedDay1,reservedDay2,reservationCount = reservingDayChecker(status)
        reservableDay,reservableTime = reservableDaySearcher(reservedDay2, status, schedule)
        
        if reservableDay != 0 and reservableTime != 0 :
            if reservationCount == 2:
                reservationCanceller(2)
            function_reservationMaker_status = reservationMaker(reservableDay, reservableTime)
            sleep(5)
            continue
        sleep(50)
    return 0


#関数の説明

# list stautsGetter(void) は 引数はなし / 戻り値は(日付 vs 時間)で2次元となったリスト型に "予約可能" "予約不可" "予約済" の要素が格納するような関数とする。
# int,int,int reservingDayChecker(list) は 引数は statusGetter()で取得した2次元のリスト型 / 戻り値が既に予約を取った日の日付2こ  + すでに取った予約の個数 となるような関数とする
# int,int reservableDaySearcher(int,list,list) は 引数は すでに予約がある日の日付のうち遅い方、stausGetter()で取得した2次元のリスト型、スケジュールを格納した2次元のリスト型 / 戻り値が、スケジュール的に入れることのできる、すでにある予約よりも早い、予約可能な日付・時間 となるような関数とする
# void reservationCanceler(int) は 引数がキャンセルしたいほうのキャンセルの番号 / 戻り値なしで キャンセルするような関数とする
# int reservationMaker(int,int) は 引数が予約したい技能実習の日付-時間 / 戻り値が予約に成功したら0, 予約に失敗したらそれ以外が返ってくるような関数とする
~~~

実に簡単ですね!

# おわりに

次からは細かい関数の中身を見ていきます!