PokeAPIを使って簡単なアプリをつくる

この記事は[Ateam Brides Inc. Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ateam-brides)の20日目の記事です。

## はじめに
Qiitaに投稿すること自体初めてで、どんなことを書こうか迷っていたところ「PokeAPI」という、面白そうかつ、初心者の自分にも扱いやすそうなものを見つけたのでこのAPIとRailsを使って簡単なポケモンアプリを作ってみようと思います。

## PokeAPI
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583468/0c8b508d-0e52-8df3-c7f1-ef7861ca1331.png"  width="400" height="400">
[PokeAPI](https://pokeapi.co/)はポケモンに関する大量のデータを取得することのできるAPIです。
図鑑ナンバーや名前だけでなく、ゲーム上のイラストだったり、タイプや重さ、生態の説明など、ポケモンに関するあらゆる情報を持っており、それぞれが紐づいている画期的なAPIです。

## つくるもの
DockerでRailsの環境構築をし、PokeAPIを使って、ポケモンを捕まえるゲームと捕まえたポケモンを確認できる簡単なアプリを作成します。

## Dockerで環境構築
今回はDockerを使って環境構築をしました。
Dockerfileとdocker-compose.ymlは以下の仕様です。
まだ勉強中なので至らぬ点がありますが、多めにみてください。

```Dockerfile:Dockerfile
FROM ruby:2.6.3
ENV LANG C.UTF-8

RUN apt-get update -qq && \
    apt-get install -y build-essential \
            libpq-dev \

RUN mkdir /app
RUN mkdir /app/src

ENV APP_ROOT /app/src
WORKDIR $APP_ROOT

ADD ./src/Gemfile $APP_ROOT/Gemfile
ADD ./src/Gemfile.lock $APP_ROOT/Gemfile.lock

RUN bundle install

ADD . $APP_ROOT
```
```yml:docker-compose.yml
version: '3'
services:

  postgres:
    image: postgres
    ports:
      - "3306:3306"
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: 'admin'
      POSTGRES_PASSWORD: 'admin-pass'
    restart: always

  app:
    build: .
    image: rails
    container_name: 'app'
    command:
      - sh
      - -c
      - bundle install && bundle exec rails s -p 5000 -b '0.0.0.0'
    ports:
      - "5000:5000"
    environment:
      VIRTUAL_PORT: 5000
    volumes:
      - ./src:/app/src
    depends_on:
      - postgres
    restart: always
```

## アプリ開発
テンプレートの紹介は各アクションから取得したインスタンス変数を使うだけで実装できるので今回は省略します。
自分が持っているポケモン周りと野生のポケモン周りで2つのコントローラを使って作成していきます。
まずは、自分が持っているポケモン周りのアクションです。

```ruby:my_pokemons_controller.rb
class MyPokemonsController < ApplicationController
  def index #手持ちのポケモン一覧
    @my_pokemons = Pokemon.order('id')
  end

  def show #ポケモンの詳細
    @my_pokemon = Pokemon.find(params[:id])
    raw_response = Faraday.get "https://pokeapi.co/api/v2/pokemon-species/#{@my_pokemon['number']}/"
    @my_pokemon_data = JSON.parse(raw_response.body)
  end

  def partner #ポケモンをパートナーにする
    session[:partner_pokemon_number] = params[:partner_pokemon_number]
    redirect_to action: "index"
  end

  def set_free #ポケモンを逃す
    @pokemon = Pokemon.find_by(number: params[:set_free_pokemon_number])
    @pokemon.destroy
    redirect_to action: "index"
  end
end
```
基本的な処理を書くだけで簡単に実装できます。
パートナーポケモンを実装するためにsessionを用いました。

次に、野生のポケモン周りのアクションです。

```ruby:adventures_controller.rb
class AdventuresController < ApplicationController
  def top #冒険に行くときのトップページ、パートナーポケモンの情報を取得
    raw_response = Faraday.get "https://pokeapi.co/api/v2/pokemon/#{session[:partner_pokemon_number]}"
    @partner_pokemon_data = JSON.parse(raw_response.body) # パートナーポケモンの画像データ
  end

  def wild_area #野生のポケモンに出会う
    raw_response = Faraday.get "https://pokeapi.co/api/v2/pal-park-area/#{params[:area_code]}/"
    list = JSON.parse(raw_response.body) # そのエリアに出現するポケモンリスト取得

    pokemon_url_list = []
    appearance_rate_list = []
    list['pokemon_encounters'].each do |data| # 各ポケモンの詳細データのURLと出現率をそれぞれリストにいれていく
      pokemon_url_list.push(data["pokemon_species"]["url"])
      appearance_rate_list.push(data["rate"])
    end

    pokemon_number = get_random_index(appearance_rate_list) # 出現率のリストを元に出現する野生のポケモンのナンバーを取得
    wild_pokemon_url = pokemon_url_list[pokemon_number]

    raw_response = Faraday.get wild_pokemon_url
    @wild_pokemon = JSON.parse(raw_response.body) # 野生のポケモンのナンバーや名前のデータ

    raw_response = Faraday.get "https://pokeapi.co/api/v2/pokemon/#{@wild_pokemon['id']}"
    @wild_pokemon_data = JSON.parse(raw_response.body) # 野生のポケモンの画像データ

    raw_response = Faraday.get "https://pokeapi.co/api/v2/pokemon/#{session[:partner_pokemon_number]}"
    @partner_pokemon_data = JSON.parse(raw_response.body) # パートナーポケモンの画像データ
  end

  def catch #ポケモンを捕まえる
    status_number_list = [1,1,1,2,2] #ポケモンを捕まえられるかの割合リスト
    status_number = status_number_list.sample

    if status_number == 1
      @get_pokemon_name = params[:get_pokemon_name]
      @get_pokemon_image = params[:get_pokemon_image]
      Pokemon.create(number: params[:get_pokemon_id], name: params[:get_pokemon_name], image: params[:get_pokemon_image]) # 捕まえたポケモンのデータを保存
    else
      render action: :failure # 失敗したら失敗ページへ
    end
  end

  def failure #捕獲失敗
  end

  def get_random_index(weight_table) # 引数の配列から1つの値をランダム抽出
    total_weight = weight_table.sum
    value = rand(1..total_weight)
    ret_index = -1
    for i in 0..weight_table.length - 1 do
      if weight_table[i] >= value
        ret_index = i
        break
      end
      value -= weight_table[i]
    end
    return ret_index
  end
end
```
ここで工夫したことは、PokeAPIから取得した各ポケモンの出現レートをappearance_rate_listに入れ、その出現レートの配列を元に、出現するポケモンを重み付きでランダムに抽出する機能を実装したことです。
例えば、ポッポ、ピカチュウ、ミュウのレートがそれぞれ50、20、1であるとすると、それぞれが選ばれる確率は50/71、20/71、1/71のようになります。
ここでランダムに選ばれた配列のインデックスを、pokemon_url_listに紐付け、野生のポケモン情報を取得します。
また、ポケモンを捕まえられるか、逃げられるかの確率はcatchアクションのstatus_number_listの中身をいじれば変更することができます。

## アプリ画面
つくったアプリの画面紹介です。
cssの実装をしていないので簡素な見た目ですが、ご了承ください。

冒険へ行くトップ画面です。
- - -
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583468/32406315-6c3d-6e37-8233-673502d696cd.png" width=600" height="600">
- - -
この画面から、5つのエリアへ行きポケモンを探しにいくことができ、手持ちのポケモンとパートナーポケモンを確認することができます。
自分で何回か動かしているときにエンテイを捕まえたのでちょっと自慢します。

手持ちのポケモン一覧です。
ポケモンナンバーと名前とイラストを表示しています。
名前をクリックすることで詳細ページへ飛びます。
- - -
![スクリーンショット 2020-12-19 15.47.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583468/30f24d5b-8055-da2f-f6b6-7445a8fa6f01.png)
- - -
APIデータのずれによりポッチャマのように日本語でない名前がとれてきてしまうこともありますが愛嬌です。笑
カビゴンの詳細ページはこんな感じです。
- - -
![スクリーンショット 2020-12-19 15.50.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583468/5282d837-bc03-8b4c-2831-230d79645bf1.png)
- - -
なんちゃらポケモンと説明が表示されます。ここでパートナーにしたり、逃したりできます。
カビゴンをパートナーにしてみましょう。
- - -
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583468/062ae5d9-4b46-67fa-8421-8d7219e5853b.png" width=600" height="600">
- - -
変わりましたね！

冒険に出てみましょう。
「やま」ボタンをクリック。
- - -
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583468/ad62dacd-1a12-1e00-7343-8f251fe9087b.png" width=600" height="600">
- - -
チャーレムが現れました。
ここで「モンスターボールを投げる」と設定した確率でポケモンを捕まえられます。「逃げる」を押すとトップに戻ります。
ボールを投げてみましょう。
- - -
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583468/81efa966-293d-65c5-a27a-9474c869fdba.png"  width="400" height="400">
- - -
捕まえました👏
- - -
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/583468/5ac6cbf2-2070-6ed2-f1f5-5775368dacb9.png"  width="300" height="300">

- - -
逃げられてしまった場合はこちらの画面がでます。
以上、アプリの紹介でした！

## 最後に
幼い頃ポケモンで遊んでいたのでこの実装をしていて楽しかったです。
ポケモンの攻略サイトもこのAPIが使われてたりするのでしょうか。
興味があれば情報量が多くて使いやすい「PokeAPI」を是非触ってみてください!
明日は、新卒同期の@ma-niが担当します！

## 参考にさせていただいた記事
[重み付きランダム](https://qiita.com/divideby_zero/items/a8e749e307013ab24a0b)