ロゴ ロゴ

部内競プロランキングをつくってみた

はじめに

最近電算では競プロがはやっています。みんなで同じものに取り組むのは楽しいですね。
競プロとは?【ブログリレー】競技プログラミングしませんか?
部内で参加人数も増えるにしたがって部内ランキングが見たくなり、
部内競プロランキングを作ってみることにしました。

サーバ構成

サーバ構成はこんな感じです。

使用言語

  • Go
  • JavaScript

ソース

ページ

GET /rank

AtCoderのレートでの順位を表示しています。
やっぱりレートの色は今後つけていきたいです。

GET /list

AC数でのランキングを標示してます。
ここではhttps://github.com/kenkoooo/AtCoderProblems/
のAPIを使わせていただきました。

// GET "https://kenkoooo.com/atcoder/atcoder-api/v2/user_info?user=" + name"
type AtCoderInfo struct {
    UserId            string      `json:"user_id"`
    AcceptedCount     json.Number `json:"accepted_count"`
    AcceptedCountRank json.Number `json:"accepted_count_rank"`
    RatedPointSum     json.Number `json:"rated_point_sum"`
    RatedPointSumRank json.Number `json:"rated_point_sum_rank"`
}

func getAtCoderInfoStruct(name string) *AtCoderInfo {

    res, err := http.Get("https://kenkoooo.com/atcoder/atcoder-api/v2/user_info?user=" + name)
    if err != nil {
        fmt.Println(err)
    }
    defer res.Body.Close()

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }
    var info string = string(body)
    // Unmarshal結果の格納先である構造体のポインターを取得
    atCoderInfo := new(AtCoderInfo)

    // JSON文字列をバイト列にキャスト
    jsonBytes := []byte(info)

    // atCoderInfoにバイト列を格納する
    if err := json.Unmarshal(jsonBytes, atCoderInfo); err != nil {
        fmt.Println(err)
    }

    return atCoderInfo
}

GET /user?q=

ここでは指定したユーザのコンテスト結果を表示しています。
APIはAtCoderの隠し機能を使わせていただきました。

// GET "https://atcoder.jp/users/" + user + "/history/json"
type AtCoderHistory struct {
    IsRated                     bool        `json:"IsRated"`
    Place                       json.Number `json:"Place"`
    OldRating                   json.Number `json:"OldRating"`
    NewRating                   json.Number `json:"NewRating"`
    Performance                 json.Number `json:"Performance"`
    InnerPerformance            json.Number `json:"InnerPerformance"`
    ContestScreenName           string      `json:"ContestScreenName"`
    ContestName                 string      `json:"ContestName"`
    ContestNameEn               string      `json:"ContestNameEn"`
    EndTime/*time.Time*/ string             `json:"EndTime"`
}

func getAtCoderHistoryStruct(name string) []*AtCoderHistory {

    res, err := http.Get("https://atcoder.jp/users/" + name + "/history/json")
    if err != nil {
        fmt.Println(err)
    }
    defer res.Body.Close()

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }
    var info string = string(body)
    // Unmarshal結果の格納先である構造体のポインターを取得
    var atCoderHistories []*AtCoderHistory
    // atCoderHistoriesにバイト列を格納する
    if err := json.Unmarshal([]byte(info), &atCoderHistories); err != nil {
        fmt.Println(err)
    }

    return atCoderHistories
}

ソートの方法

ランキングを生成するにあたってサーバ側で処理をするつもりだったのですが、
HTMLで作ったテーブルにソート機能を追加する「Tablesorter」の使い方を見つけてしまったので、今回はこれを使いました。

EX:

<table class="tablesorter-ice" id="rank">
  <thead>
    <tr>
      <th>UserName</th>
      <th>Rate</th>
      <th>ContestParticipation</th>
    </tr>
  </thead>
  <tbody>
    {{range .}}
    <tr>
      <td><a href="/user?q={{.UserName}}">{{.UserName}}</a></td>
      <td>{{.Rate}}</td>
      <td>{{.ContestCount}}</td>
    </tr>
    {{end}}
  </tbody>
</table>

さいごに

今回は CI/CD で開発を進めたいと思い、GithubActions を試してみました。
ですが、設定がめんどくさくなってそのままデプロイしちゃったので、次回からはちゃんと設定しようと思います。

コメント入力

関連サイト