LoginSignup
6
4

More than 5 years have passed since last update.

テクテクテクテクの稼ぎ場所をオープンデータから求める(初級編)

Last updated at Posted at 2018-12-10

こんにちは、みなさん テクテクテクテク してますか?

このゲームはIngressやPokemon Goと同じ位置情報ゲームです。なので実際に出歩く必要があります。ただ前者と違って速度制限が特にないようなので新幹線に乗ったり、たどり着きにくいところに船で行くなどの「リアル課金」がものを言うゲームです。

私は デブ性 出不精なのですが、電車で移動したりしてランク119、レベル29まで来ました (2018/12/10現在)。

今のところ特に人と協力・競争する要素はないのでのんびりマイペースで進めてもいいのですが、ここは「楽して稼げる」方法を考えてから行動することにしてみました。

(この記事はアドベントカレンダー駆動で書かれています)

初級編:東京都内での大字の密集地帯を探そう

このテクテクテクテクは自分の周りの道路で囲まれた場所を「塗る」ことでTPP (経験値のようなもの) を稼いでいくのですが、「大字」をすべて塗ると100%ボーナスがもらえます。このボーナスは毎日もらえるため、たくさんの「大字」を塗りつぶすことで出歩かなくても多く稼ぐことができるわけです。

ちなみに「大字」って知ってますか?ざっというと市区町村の次に小さい単位だと思ってください。
例えば「東京都千代田区内幸町一丁目」とか「千代田区神田東紺屋町」とかそういう区分です。

今回は大字が一番密集している場所をプログラムで探すことで短時間で大量の大字100%ボーナスをもらっちゃおう!というのをやってみます。

大字の情報をダウンロード

日本国内の大字の情報は国土交通省のページからダウンロードすることができます。

この中には、

  • 都道府県名
  • 市区町村名
  • 大字名
  • 緯度
  • 経度

などが含まれているため、今回はこのデータを元に、大字の密集している地域を求めることにします。

ダウンロード時に利用規約を見ましたが、このような使い方は問題ないようでした。

今回は私が住んでいるのが東京なので、東京都のデータだけを取得してみました。

zipをダウンロードし、展開すると 13_2017.csv というファイルが得られます。
このファイルによると東京都には大字が5,359箇所あるようです。

求める方法

今回は初級編ということもあり、適当な矩形を動かしながら、その中に最も多くの大字の緯度経度が含まれる矩形の位置を探すことにしました。

緯度経度は0.01度で1.1km程度とのことなので、0.02度 x 0.02度の矩形内に含まれる大字の緯度経度が最大になる地点を0.001度ずつずらしながら探してみます。

実装はGoを使いました。
CSVを読み込み(ShiftJISになってるので注意)、ループするだけなので1時間程度で書けました。実行時間は自分のPCで5秒程度です。

結果

今回の結果は 緯度 35.695558999999555, 経度 139.7745240000037 の地点が、
0.1度以内に大字を83含む最大の地点になりました。

だいたい 都営新宿線の岩本町駅 あたりのようです。

含まれる大字は次のとおりです。

市区町村 大字 緯度 経度
千代田区 岩本町一丁目 35.692346 139.777635
千代田区 神田西福田町 35.691334 139.774244
千代田区 神田東紺屋町 35.692833 139.774711
千代田区 神田北乗物町 35.692455 139.773897
千代田区 神田富山町 35.693673 139.773588
千代田区 神田鍛冶町三丁目 35.693613 139.770976
千代田区 内神田二丁目 35.690601 139.768027
千代田区 神田紺屋町 35.692021 139.774233
千代田区 東神田二丁目 35.696189 139.780146
千代田区 神田多町二丁目 35.693856 139.769189
千代田区 内神田一丁目 35.69058 139.765604
千代田区 神田司町二丁目 35.693464 139.767523
千代田区 大手町二丁目 35.686301 139.768087
千代田区 神田美土代町 35.693283 139.765581
千代田区 神田佐久間町四丁目 35.697658 139.779837
千代田区 東神田三丁目 35.697364 139.781365
千代田区 岩本町二丁目 35.693526 139.776933
千代田区 東神田一丁目 35.694328 139.780497
千代田区 岩本町三丁目 35.695636 139.776931
千代田区 神田東松下町 35.694239 139.773572
千代田区 神田佐久間町三丁目 35.697983 139.777936
千代田区 神田平河町 35.698036 139.775653
千代田区 神田岩本町 35.695506 139.775004
千代田区 神田佐久間河岸 35.697048 139.777798
千代田区 神田花岡町 35.698802 139.773971
千代田区 鍛冶町二丁目 35.692583 139.772023
千代田区 内神田三丁目 35.691005 139.769658
千代田区 外神田五丁目 35.704021 139.772366
千代田区 神田佐久間町二丁目 35.698009 139.776368
千代田区 神田佐久間町一丁目 35.697979 139.774222
千代田区 神田和泉町 35.699704 139.777907
千代田区 神田練塀町 35.70071 139.774037
千代田区 鍛冶町一丁目 35.690198 139.77154
千代田区 外神田四丁目 35.70143 139.77237
千代田区 神田相生町 35.699524 139.773602
千代田区 神田松永町 35.70031 139.775293
千代田区 外神田三丁目 35.701275 139.770496
千代田区 神田淡路町一丁目 35.695759 139.767031
千代田区 神田淡路町二丁目 35.697519 139.767838
千代田区 神田小川町一丁目 35.694724 139.766412
千代田区 神田須田町一丁目 35.696223 139.769841
千代田区 神田須田町二丁目 35.695815 139.773059
千代田区 外神田一丁目 35.698406 139.770885
千代田区 外神田二丁目 35.700675 139.768552
千代田区 外神田六丁目 35.704066 139.770971
千代田区 神田駿河台三丁目 35.696732 139.764721
千代田区 神田美倉町 35.690853 139.774501
千代田区 神田駿河台四丁目 35.698594 139.765849
中央区 日本橋久松町 35.689545 139.784211
中央区 日本橋堀留町二丁目 35.688584 139.781188
中央区 日本橋人形町三丁目 35.686653 139.781547
中央区 日本橋小舟町 35.686858 139.778267
中央区 日本橋本町二丁目 35.687852 139.775799
中央区 日本橋本町一丁目 35.685747 139.776872
中央区 日本橋本石町二丁目 35.686261 139.771288
中央区 日本橋本石町三丁目 35.687534 139.770761
中央区 日本橋本町三丁目 35.688895 139.77566
中央区 日本橋室町三丁目 35.687974 139.772824
中央区 日本橋室町二丁目 35.686841 139.773767
中央区 日本橋本石町四丁目 35.688585 139.770806
中央区 日本橋富沢町 35.688951 139.782661
中央区 東日本橋三丁目 35.69155 139.783599
中央区 日本橋横山町 35.693024 139.783587
中央区 日本橋小伝馬町 35.691464 139.778699
中央区 日本橋室町四丁目 35.689122 139.77239
中央区 日本橋堀留町一丁目 35.687931 139.779894
中央区 日本橋大伝馬町 35.690253 139.779661
中央区 日本橋本町四丁目 35.690183 139.775106
中央区 日本橋馬喰町一丁目 35.693636 139.782375
中央区 日本橋馬喰町二丁目 35.695734 139.783754
文京区 湯島一丁目 35.701413 139.764617
文京区 湯島二丁目 35.705198 139.765922
台東区 台東二丁目 35.703252 139.778437
台東区 台東三丁目 35.704838 139.778737
台東区 台東一丁目 35.701458 139.778197
台東区 浅草橋五丁目 35.700562 139.782102
台東区 上野三丁目 35.705408 139.773096
台東区 秋葉原 35.701896 139.774417
台東区 鳥越一丁目 35.70292 139.78296
台東区 上野五丁目 35.705188 139.775309
台東区 小島一丁目 35.70429 139.782968
台東区 浅草橋四丁目 35.698503 139.781432
台東区 浅草橋一丁目 35.697415 139.784498

ソースコード

今回の調査に利用したソースコードは https://github.com/mtgto/teku4easy/ にpushしています。

teku4easy.go
package main

import (
    "encoding/csv"
    "flag"
    "fmt"
    "golang.org/x/text/encoding/japanese"
    "golang.org/x/text/transform"
    "math"
    "os"
    "strconv"
)

// 大字の定義
type oaza struct {
    name string
    city string
    pos position
}

type position struct {
    latitude float64
    longitude float64
}

func main() {
    flag.Parse()
    if flag.NArg() < 1 {
        fmt.Fprintf(os.Stderr, "引数に大字のCSVファイルを渡してください\n")
        os.Exit(1)
    }
    oazas := loadCsv(flag.Arg(0))
    //fmt.Printf("%v\n", oazas)
    minLat, minLong := 10000.0, 10000.0
    maxLat, maxLong := 0.0, 0.0
    for _, oaza := range oazas {
        minLat = math.Min(minLat, oaza.pos.latitude)
        maxLat = math.Max(maxLat, oaza.pos.latitude)
        minLong = math.Min(minLong, oaza.pos.longitude)
        maxLong = math.Max(maxLong, oaza.pos.longitude)
    }
    pos, result := findMostCongested(&oazas, 0.01, 0.01, position{latitude: minLat, longitude: minLong}, position{latitude: maxLat, longitude: maxLong})
    fmt.Printf("緯度 %v, 経度 %v 大字の数%v\n", pos.latitude, pos.longitude, len(result))
    for _, oaza := range result {
        fmt.Printf("%v, %v (%v, %v)\n", oaza.city, oaza.name, oaza.pos.latitude, oaza.pos.longitude)
    }
}

// min - maxの矩形内で、width, height (単位は緯度経度) 以内に一番多くの大字を含む地点とその数を返す
func findMostCongested(oazas *[]oaza, width, height float64, minPos, maxPos position) (position, []oaza) {
    var bestPos position
    var bestResult []oaza = make([]oaza, 0, 0)
    for lat := minPos.latitude; lat < maxPos.latitude; lat += width/10 {
        for long := minPos.longitude; long < maxPos.longitude; long += height/10 {
            result := make([]oaza, 0)
            for _, oaza := range *oazas {
                if lat - width <= oaza.pos.latitude && oaza.pos.latitude <= lat + width && long - height <= oaza.pos.longitude && oaza.pos.longitude <= long + height {
                    result = append(result, oaza)
                }
            }
            if len(bestResult) < len(result) {
                //fmt.Printf("%v, %v, %v\n", lat, long, result)
                bestResult = result
                bestPos = position{latitude: lat, longitude: long}
            }
        }
    }
    return bestPos, bestResult
}

// 大字CSVデータを読み込む。ShiftJISになっているのとヘッダ行があるので処理する
func loadCsv(in string) []oaza {
    // 今回は離島は計算しない
    count := 5283
    oazas := make([]oaza, 0, count)
    file, err := os.Open(in)
    if err != nil {
        panic(err)
    }
    defer file.Close()
    reader := csv.NewReader(transform.NewReader(file, japanese.ShiftJIS.NewDecoder()))
    records, err := reader.ReadAll()
    if err != nil {
        panic(err)
    }
    for i, record := range records {
        if i >= 1 && i < count {
            latitude, err := strconv.ParseFloat(record[6], 64)
            if err != nil {
                panic(err)
            }
            longitude, err := strconv.ParseFloat(record[7], 64)
            if err != nil {
                panic(err)
            }
            oazas = append(oazas, oaza{name: record[5], city: record[3], pos: position{latitude: latitude, longitude: longitude}})
        }
    }
    return oazas
}

終わりに

今回は「初級編」ということで、国土交通省の緯度経度を含む大字のオープンデータを使い、大字が密集している場所を探してみました。

実際にゲームをやってみるとわかるのですが、100%コンプしやすさにはこれだけではなく大字自体が小さいことだったり、電車だけでコンプできる大字の情報がほしいと感じます。それらは今後の課題(中級編・上級編)としましょう。

ではみなさん、レッツテクテクテクテク

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4